]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #93613 - crlf0710:rename_to_async_iter, r=yaahc
authorMatthias Krüger <matthias.krueger@famsik.de>
Fri, 18 Feb 2022 15:23:32 +0000 (16:23 +0100)
committerGitHub <noreply@github.com>
Fri, 18 Feb 2022 15:23:32 +0000 (16:23 +0100)
Move `{core,std}::stream::Stream` to `{core,std}::async_iter::AsyncIterator`

Following amendments in https://github.com/rust-lang/rfcs/pull/3208/.

cc #79024
cc ``@yoshuawuyts`` ``@joshtriplett``

1275 files changed:
.github/workflows/ci.yml
.gitignore
.gitmodules
.mailmap
Cargo.lock
RELEASES.md
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/util/comments.rs
compiler/rustc_ast/src/util/comments/tests.rs
compiler/rustc_ast_lowering/src/asm.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_ast_pretty/src/pp.rs
compiler/rustc_ast_pretty/src/pp/convenience.rs [new file with mode: 0644]
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_ast_pretty/src/pprust/state/delimited.rs [new file with mode: 0644]
compiler/rustc_ast_pretty/src/pprust/state/expr.rs
compiler/rustc_ast_pretty/src/pprust/state/item.rs
compiler/rustc_attr/src/builtin.rs
compiler/rustc_borrowck/src/borrowck_errors.rs
compiler/rustc_borrowck/src/constraint_generation.rs
compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/diagnostics/move_errors.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/lib.rs
compiler/rustc_borrowck/src/nll.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/region_infer/opaque_types.rs
compiler/rustc_borrowck/src/renumber.rs
compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
compiler/rustc_borrowck/src/type_check/free_region_relations.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_borrowck/src/type_check/relate_tys.rs
compiler/rustc_borrowck/src/universal_regions.rs
compiler/rustc_builtin_macros/src/asm.rs
compiler/rustc_builtin_macros/src/assert.rs
compiler/rustc_builtin_macros/src/concat_bytes.rs
compiler/rustc_builtin_macros/src/deriving/default.rs
compiler/rustc_builtin_macros/src/deriving/mod.rs
compiler/rustc_builtin_macros/src/edition_panic.rs [new file with mode: 0644]
compiler/rustc_builtin_macros/src/format.rs
compiler/rustc_builtin_macros/src/global_allocator.rs
compiler/rustc_builtin_macros/src/lib.rs
compiler/rustc_builtin_macros/src/panic.rs [deleted file]
compiler/rustc_builtin_macros/src/proc_macro_harness.rs
compiler/rustc_builtin_macros/src/standard_library_imports.rs
compiler/rustc_builtin_macros/src/test.rs
compiler/rustc_codegen_cranelift/src/abi/mod.rs
compiler/rustc_codegen_cranelift/src/archive.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/common.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
compiler/rustc_codegen_cranelift/src/unsize.rs
compiler/rustc_codegen_cranelift/src/value_and_place.rs
compiler/rustc_codegen_gcc/src/archive.rs
compiler/rustc_codegen_gcc/src/consts.rs
compiler/rustc_codegen_llvm/src/abi.rs
compiler/rustc_codegen_llvm/src/allocator.rs
compiler/rustc_codegen_llvm/src/attributes.rs
compiler/rustc_codegen_llvm/src/back/archive.rs
compiler/rustc_codegen_llvm/src/consts.rs
compiler/rustc_codegen_llvm/src/context.rs
compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_llvm/src/llvm/ffi.rs
compiler/rustc_codegen_llvm/src/llvm/mod.rs
compiler/rustc_codegen_llvm/src/llvm_util.rs
compiler/rustc_codegen_llvm/src/type_of.rs
compiler/rustc_codegen_ssa/src/back/archive.rs
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/metadata.rs
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_codegen_ssa/src/base.rs
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
compiler/rustc_codegen_ssa/src/mir/constant.rs
compiler/rustc_codegen_ssa/src/target_features.rs
compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs
compiler/rustc_const_eval/src/const_eval/error.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/const_eval/mod.rs
compiler/rustc_const_eval/src/interpret/cast.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/intrinsics/type_name.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/place.rs
compiler/rustc_const_eval/src/interpret/util.rs
compiler/rustc_const_eval/src/interpret/validity.rs
compiler/rustc_const_eval/src/lib.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/check_consts/ops.rs
compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
compiler/rustc_const_eval/src/transform/promote_consts.rs
compiler/rustc_const_eval/src/util/call_kind.rs [new file with mode: 0644]
compiler/rustc_const_eval/src/util/mod.rs
compiler/rustc_data_structures/src/intern.rs [new file with mode: 0644]
compiler/rustc_data_structures/src/intern/tests.rs [new file with mode: 0644]
compiler/rustc_data_structures/src/lib.rs
compiler/rustc_data_structures/src/ptr_key.rs [deleted file]
compiler/rustc_data_structures/src/sip128.rs
compiler/rustc_data_structures/src/snapshot_map/mod.rs
compiler/rustc_data_structures/src/stable_hasher.rs
compiler/rustc_data_structures/src/stable_hasher/tests.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_codes/src/error_codes.rs
compiler/rustc_error_codes/src/error_codes/E0192.md
compiler/rustc_error_codes/src/error_codes/E0604.md
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_feature/src/removed.rs
compiler/rustc_hir/src/def.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir/src/itemlikevisit.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir/src/stable_hash_impls.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_index/src/bit_set.rs
compiler/rustc_infer/src/infer/at.rs
compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
compiler/rustc_infer/src/infer/canonical/mod.rs
compiler/rustc_infer/src/infer/canonical/query_response.rs
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/equate.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.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/nice_region_error/util.rs
compiler/rustc_infer/src/infer/error_reporting/note.rs
compiler/rustc_infer/src/infer/free_regions.rs
compiler/rustc_infer/src/infer/freshen.rs
compiler/rustc_infer/src/infer/fudge.rs
compiler/rustc_infer/src/infer/glb.rs
compiler/rustc_infer/src/infer/higher_ranked/mod.rs
compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
compiler/rustc_infer/src/infer/lub.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/nll_relate/mod.rs
compiler/rustc_infer/src/infer/outlives/env.rs
compiler/rustc_infer/src/infer/outlives/obligations.rs
compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
compiler/rustc_infer/src/infer/region_constraints/mod.rs
compiler/rustc_infer/src/infer/resolve.rs
compiler/rustc_infer/src/infer/sub.rs
compiler/rustc_infer/src/infer/type_variable.rs
compiler/rustc_infer/src/infer/undo_log.rs
compiler/rustc_infer/src/traits/mod.rs
compiler/rustc_infer/src/traits/project.rs
compiler/rustc_interface/src/callbacks.rs
compiler/rustc_interface/src/interface.rs
compiler/rustc_interface/src/lib.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/queries.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_interface/src/util.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/internal.rs
compiler/rustc_lint/src/non_fmt_panic.rs
compiler/rustc_lint/src/pass_by_value.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_metadata/src/locator.rs
compiler/rustc_metadata/src/native_libs.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_middle/src/arena.rs
compiler/rustc_middle/src/dep_graph/mod.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/infer/canonical.rs
compiler/rustc_middle/src/infer/unify_key.rs
compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
compiler/rustc_middle/src/middle/stability.rs
compiler/rustc_middle/src/mir/interpret/queries.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/pretty.rs
compiler/rustc_middle/src/mir/query.rs
compiler/rustc_middle/src/mir/tcx.rs
compiler/rustc_middle/src/mir/terminator.rs
compiler/rustc_middle/src/mir/traversal.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/thir/abstract_const.rs
compiler/rustc_middle/src/thir/visit.rs
compiler/rustc_middle/src/traits/mod.rs
compiler/rustc_middle/src/traits/query.rs
compiler/rustc_middle/src/ty/_match.rs
compiler/rustc_middle/src/ty/adt.rs
compiler/rustc_middle/src/ty/assoc.rs
compiler/rustc_middle/src/ty/closure.rs
compiler/rustc_middle/src/ty/codec.rs
compiler/rustc_middle/src/ty/consts.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/diagnostics.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/fast_reject.rs
compiler/rustc_middle/src/ty/flags.rs
compiler/rustc_middle/src/ty/fold.rs
compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
compiler/rustc_middle/src/ty/inhabitedness/mod.rs
compiler/rustc_middle/src/ty/instance.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
compiler/rustc_middle/src/ty/print/mod.rs
compiler/rustc_middle/src/ty/print/pretty.rs
compiler/rustc_middle/src/ty/query.rs
compiler/rustc_middle/src/ty/relate.rs
compiler/rustc_middle/src/ty/structural_impls.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_middle/src/ty/subst.rs
compiler/rustc_middle/src/ty/trait_def.rs
compiler/rustc_middle/src/ty/util.rs
compiler/rustc_middle/src/ty/walk.rs
compiler/rustc_mir_build/src/build/expr/as_constant.rs
compiler/rustc_mir_build/src/build/expr/into.rs
compiler/rustc_mir_build/src/build/matches/mod.rs
compiler/rustc_mir_build/src/build/matches/simplify.rs
compiler/rustc_mir_build/src/build/matches/test.rs
compiler/rustc_mir_build/src/build/misc.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/thir/constant.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_mir_build/src/thir/cx/mod.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
compiler/rustc_mir_build/src/thir/pattern/mod.rs
compiler/rustc_mir_dataflow/src/elaborate_drops.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/coverage/debug.rs
compiler/rustc_mir_transform/src/coverage/tests.rs
compiler/rustc_mir_transform/src/dest_prop.rs
compiler/rustc_mir_transform/src/early_otherwise_branch.rs
compiler/rustc_mir_transform/src/generator.rs
compiler/rustc_mir_transform/src/inline.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/normalize_array_len.rs
compiler/rustc_mir_transform/src/required_consts.rs
compiler/rustc_mir_transform/src/reveal_all.rs
compiler/rustc_mir_transform/src/shim.rs
compiler/rustc_mir_transform/src/simplify.rs
compiler/rustc_monomorphize/src/collector.rs
compiler/rustc_monomorphize/src/polymorphize.rs
compiler/rustc_monomorphize/src/util.rs
compiler/rustc_parse/src/lexer/mod.rs
compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
compiler/rustc_parse/src/lib.rs
compiler/rustc_parse/src/parser/expr.rs
compiler/rustc_parse_format/src/lib.rs
compiler/rustc_parse_format/src/tests.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_impl/src/keys.rs
compiler/rustc_query_impl/src/lib.rs
compiler/rustc_query_impl/src/plumbing.rs
compiler/rustc_query_impl/src/stats.rs [deleted file]
compiler/rustc_query_impl/src/values.rs
compiler/rustc_query_system/src/dep_graph/serialized.rs
compiler/rustc_query_system/src/query/config.rs
compiler/rustc_query_system/src/query/job.rs
compiler/rustc_query_system/src/query/mod.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/imports.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_resolve/src/macros.rs
compiler/rustc_save_analysis/src/dump_visitor.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_save_analysis/src/sig.rs
compiler/rustc_serialize/src/json.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/filesearch.rs
compiler/rustc_session/src/options.rs
compiler/rustc_session/src/search_paths.rs
compiler/rustc_span/Cargo.toml
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/source_map.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/src/legacy.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/abi/call/mod.rs
compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs
compiler/rustc_target/src/spec/aarch64_unknown_none_hermitkernel.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/abi.rs
compiler/rustc_target/src/spec/android_base.rs
compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabi.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs
compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs
compiler/rustc_target/src/spec/mips64_openwrt_linux_musl.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs
compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs
compiler/rustc_target/src/spec/wasm32_wasi.rs
compiler/rustc_trait_selection/src/opaque_types.rs
compiler/rustc_trait_selection/src/traits/auto_trait.rs
compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
compiler/rustc_trait_selection/src/traits/codegen.rs
compiler/rustc_trait_selection/src/traits/coherence.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/fulfill.rs
compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_trait_selection/src/traits/specialize/mod.rs
compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_traits/src/chalk/db.rs
compiler/rustc_traits/src/chalk/lowering.rs
compiler/rustc_traits/src/chalk/mod.rs
compiler/rustc_traits/src/dropck_outlives.rs
compiler/rustc_traits/src/normalize_erasing_regions.rs
compiler/rustc_ty_utils/src/instance.rs
compiler/rustc_ty_utils/src/representability.rs
compiler/rustc_ty_utils/src/ty.rs
compiler/rustc_type_ir/src/lib.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/_match.rs
compiler/rustc_typeck/src/check/callee.rs
compiler/rustc_typeck/src/check/cast.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/closure.rs
compiler/rustc_typeck/src/check/coercion.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/demand.rs
compiler/rustc_typeck/src/check/dropck.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/fallback.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
compiler/rustc_typeck/src/check/gather_locals.rs
compiler/rustc_typeck/src/check/generator_interior.rs
compiler/rustc_typeck/src/check/generator_interior/drop_ranges.rs
compiler/rustc_typeck/src/check/generator_interior/drop_ranges/cfg_build.rs
compiler/rustc_typeck/src/check/generator_interior/drop_ranges/record_consumed_borrow.rs
compiler/rustc_typeck/src/check/method/confirm.rs
compiler/rustc_typeck/src/check/method/mod.rs
compiler/rustc_typeck/src/check/method/probe.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/op.rs
compiler/rustc_typeck/src/check/pat.rs
compiler/rustc_typeck/src/check/place_op.rs
compiler/rustc_typeck/src/check/regionck.rs
compiler/rustc_typeck/src/check/upvar.rs
compiler/rustc_typeck/src/check/wfcheck.rs
compiler/rustc_typeck/src/check/writeback.rs
compiler/rustc_typeck/src/coherence/builtin.rs
compiler/rustc_typeck/src/coherence/orphan.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/collect/type_of.rs
compiler/rustc_typeck/src/constrained_generic_params.rs
compiler/rustc_typeck/src/hir_wf_check.rs
compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
compiler/rustc_typeck/src/lib.rs
compiler/rustc_typeck/src/mem_categorization.rs
compiler/rustc_typeck/src/outlives/mod.rs
compiler/rustc_typeck/src/outlives/utils.rs
compiler/rustc_typeck/src/variance/constraints.rs
config.toml.example
library/alloc/src/alloc.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/set.rs
library/alloc/src/collections/linked_list.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/fmt.rs
library/alloc/src/lib.rs
library/alloc/src/rc.rs
library/alloc/src/slice.rs
library/alloc/src/sync.rs
library/alloc/src/vec/mod.rs
library/alloc/tests/lib.rs
library/alloc/tests/str.rs
library/core/Cargo.toml
library/core/benches/str.rs
library/core/benches/str/char_count.rs [new file with mode: 0644]
library/core/benches/str/corpora.rs [new file with mode: 0644]
library/core/src/array/mod.rs
library/core/src/cell.rs
library/core/src/convert/mod.rs
library/core/src/iter/adapters/mod.rs
library/core/src/iter/mod.rs
library/core/src/iter/traits/accum.rs
library/core/src/iter/traits/collect.rs
library/core/src/iter/traits/iterator.rs
library/core/src/lazy.rs
library/core/src/lib.rs
library/core/src/macros/mod.rs
library/core/src/num/int_macros.rs
library/core/src/num/mod.rs
library/core/src/num/nonzero.rs
library/core/src/num/uint_macros.rs
library/core/src/num/wrapping.rs
library/core/src/ops/try_trait.rs
library/core/src/option.rs
library/core/src/panic.rs
library/core/src/panic/panic_info.rs
library/core/src/panicking.rs
library/core/src/pin.rs
library/core/src/ptr/non_null.rs
library/core/src/ptr/unique.rs
library/core/src/result.rs
library/core/src/slice/ascii.rs
library/core/src/slice/cmp.rs
library/core/src/slice/mod.rs
library/core/src/str/count.rs [new file with mode: 0644]
library/core/src/str/iter.rs
library/core/src/str/mod.rs
library/core/src/str/validations.rs
library/core/src/sync/atomic.rs
library/core/src/task/poll.rs
library/core/tests/future.rs
library/core/tests/hash/mod.rs
library/core/tests/iter/traits/iterator.rs
library/core/tests/lib.rs
library/core/tests/pin_macro.rs [new file with mode: 0644]
library/panic_unwind/src/gcc.rs
library/std/Cargo.toml
library/std/src/env.rs
library/std/src/ffi/c_str.rs
library/std/src/ffi/os_str.rs
library/std/src/fs.rs
library/std/src/io/buffered/bufreader.rs
library/std/src/io/buffered/bufwriter.rs
library/std/src/io/cursor.rs
library/std/src/io/error.rs
library/std/src/io/error/repr_bitpacked.rs [new file with mode: 0644]
library/std/src/io/error/repr_unpacked.rs [new file with mode: 0644]
library/std/src/io/error/tests.rs
library/std/src/io/impls.rs
library/std/src/io/mod.rs
library/std/src/io/tests.rs
library/std/src/lib.rs
library/std/src/net/mod.rs
library/std/src/net/udp.rs
library/std/src/os/fd/owned.rs
library/std/src/os/unix/fs.rs
library/std/src/os/unix/net/addr.rs
library/std/src/os/wasi/fs.rs
library/std/src/os/windows/io/handle.rs
library/std/src/os/windows/io/socket.rs
library/std/src/path.rs
library/std/src/path/tests.rs
library/std/src/process.rs
library/std/src/sys/hermit/fs.rs
library/std/src/sys/hermit/mod.rs
library/std/src/sys/hermit/net.rs
library/std/src/sys/hermit/stdio.rs
library/std/src/sys/hermit/thread.rs
library/std/src/sys/hermit/time.rs
library/std/src/sys/itron/condvar.rs
library/std/src/sys/itron/time.rs
library/std/src/sys/sgx/mod.rs
library/std/src/sys/sgx/net.rs
library/std/src/sys/sgx/path.rs
library/std/src/sys/sgx/time.rs
library/std/src/sys/solid/fs.rs
library/std/src/sys/solid/mod.rs
library/std/src/sys/solid/net.rs
library/std/src/sys/solid/os.rs
library/std/src/sys/solid/path.rs
library/std/src/sys/solid/time.rs
library/std/src/sys/unix/fs.rs
library/std/src/sys/unix/l4re.rs
library/std/src/sys/unix/mod.rs
library/std/src/sys/unix/net.rs
library/std/src/sys/unix/os.rs
library/std/src/sys/unix/path.rs
library/std/src/sys/unix/process/process_common.rs
library/std/src/sys/unix/process/process_fuchsia.rs
library/std/src/sys/unix/process/process_unix.rs
library/std/src/sys/unix/process/process_vxworks.rs
library/std/src/sys/unix/thread.rs
library/std/src/sys/unix/time.rs
library/std/src/sys/unsupported/common.rs
library/std/src/sys/unsupported/os.rs
library/std/src/sys/unsupported/process.rs
library/std/src/sys/unsupported/time.rs
library/std/src/sys/wasi/fs.rs
library/std/src/sys/wasi/time.rs
library/std/src/sys/windows/c.rs
library/std/src/sys/windows/fs.rs
library/std/src/sys/windows/mod.rs
library/std/src/sys/windows/net.rs
library/std/src/sys/windows/path.rs
library/std/src/sys/windows/process.rs
library/std/src/sys/windows/process/tests.rs
library/std/src/sys/windows/stdio.rs
library/std/src/sys/windows/thread.rs
library/std/src/sys/windows/time.rs
library/std/src/sys_common/fs.rs
library/std/src/sys_common/net.rs
library/std/src/time.rs
library/std/src/time/monotonic.rs [deleted file]
library/std/src/time/tests.rs
library/std/tests/run-time-detect.rs
library/stdarch
library/test/src/cli.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/test_result.rs
library/test/src/tests.rs
library/test/src/time.rs
library/test/src/types.rs
library/unwind/src/libunwind.rs
src/bootstrap/Cargo.toml
src/bootstrap/bin/main.rs
src/bootstrap/bootstrap.py
src/bootstrap/build.rs
src/bootstrap/config.rs
src/bootstrap/dist.rs
src/bootstrap/lib.rs
src/bootstrap/native.rs
src/bootstrap/setup.rs
src/ci/cpu-usage-over-time.py
src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile
src/ci/docker/host-x86_64/dist-armhf-linux/Dockerfile
src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile
src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile
src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile
src/ci/github-actions/ci.yml
src/ci/pgo.sh
src/doc/book
src/doc/man/rustc.1
src/doc/man/rustdoc.1
src/doc/nomicon
src/doc/reference
src/doc/rustc-dev-guide
src/doc/rustc/src/SUMMARY.md
src/doc/rustc/src/codegen-options/index.md
src/doc/rustc/src/instrument-coverage.md [new file with mode: 0644]
src/doc/rustc/src/platform-support.md
src/doc/rustc/src/platform-support/aarch64-unknown-none-hermitkernel.md [new file with mode: 0644]
src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md [new file with mode: 0644]
src/doc/rustc/src/platform-support/mips64-openwrt-linux-musl.md [new file with mode: 0644]
src/doc/rustc/src/tests/index.md
src/doc/rustdoc/src/command-line-arguments.md
src/doc/unstable-book/src/compiler-flags/cf-protection.md [new file with mode: 0644]
src/doc/unstable-book/src/compiler-flags/instrument-coverage.md [deleted file]
src/doc/unstable-book/src/compiler-flags/report-time.md
src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md [deleted file]
src/doc/unstable-book/src/language-features/asm-const.md
src/doc/unstable-book/src/language-features/asm-experimental-arch.md
src/doc/unstable-book/src/language-features/asm-sym.md
src/doc/unstable-book/src/language-features/asm-unwind.md
src/doc/unstable-book/src/language-features/c-unwind.md
src/etc/natvis/libstd.natvis
src/etc/pre-commit.sh [deleted file]
src/etc/pre-push.sh [new file with mode: 0755]
src/librustdoc/Cargo.toml
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/simplify.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/config.rs
src/librustdoc/core.rs
src/librustdoc/doctest.rs
src/librustdoc/html/format.rs
src/librustdoc/html/highlight.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/markdown/tests.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/search_index.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/static/js/search.js
src/librustdoc/html/static/js/settings.js
src/librustdoc/html/static/js/source-script.js
src/librustdoc/html/static/js/storage.js
src/librustdoc/lib.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/librustdoc/passes/html_tags.rs
src/librustdoc/scrape_examples.rs
src/librustdoc/visit_ast.rs
src/llvm-project
src/test/codegen/cf-protection.rs [new file with mode: 0644]
src/test/codegen/debug-vtable.rs
src/test/codegen/debuginfo-generic-closure-env-names.rs
src/test/codegen/fastcall-inreg.rs
src/test/codegen/function-arguments.rs
src/test/codegen/packed.rs
src/test/codegen/riscv-abi/riscv64-lp64-lp64f-lp64d-abi.rs
src/test/codegen/scalar-pair-bool.rs
src/test/codegen/transmute-scalar.rs
src/test/codegen/union-abi.rs
src/test/codegen/unwind-abis/aapcs-unwind-abi.rs [new file with mode: 0644]
src/test/codegen/unwind-abis/cdecl-unwind-abi.rs [new file with mode: 0644]
src/test/codegen/unwind-abis/fastcall-unwind-abi.rs [new file with mode: 0644]
src/test/codegen/unwind-abis/sysv64-unwind-abi.rs [new file with mode: 0644]
src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs [new file with mode: 0644]
src/test/codegen/unwind-abis/win64-unwind-abi.rs [new file with mode: 0644]
src/test/codegen/used_with_arg.rs [new file with mode: 0644]
src/test/incremental/hashes/trait_impls.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_allocation2.main.ConstProp.after.32bit.mir
src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir
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_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff [new file with mode: 0644]
src/test/mir-opt/const_prop/invalid_constant.rs [new file with mode: 0644]
src/test/mir-opt/const_prop/mutable_variable_no_prop.main.ConstProp.diff
src/test/mir-opt/const_prop/read_immutable_static.main.ConstProp.diff
src/test/mir-opt/coverage_graphviz.rs
src/test/mir-opt/instrument_coverage.rs
src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff
src/test/pretty/ast-stmt-expr-attr.rs
src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs
src/test/pretty/stmt_expr_attributes.rs
src/test/pretty/use-tree.rs [new file with mode: 0644]
src/test/run-make-fulldeps/atomic-lock-free/atomic_lock_free.rs
src/test/run-make-fulldeps/core-no-fp-fmt-parse/Makefile
src/test/run-make-fulldeps/coverage-llvmir/Makefile
src/test/run-make-fulldeps/coverage-llvmir/filecheck.testprog.txt
src/test/run-make-fulldeps/coverage-reports/Makefile
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-85461.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.no_cov_crate.txt
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
src/test/run-make-fulldeps/coverage/lib/inline_always_with_dead_code.rs
src/test/run-make-fulldeps/coverage/lib/used_crate.rs
src/test/run-make-fulldeps/coverage/no_cov_crate.rs
src/test/run-make-fulldeps/issue-19371/foo.rs
src/test/run-make-fulldeps/libs-and-bins/Makefile [deleted file]
src/test/run-make-fulldeps/libs-and-bins/foo.rs [deleted file]
src/test/run-make-fulldeps/libtest-json/output-default.json
src/test/run-make-fulldeps/libtest-json/output-stdout-success.json
src/test/run-make-fulldeps/output-with-hyphens/Makefile
src/test/run-make-fulldeps/output-with-hyphens/foo-bar.rs
src/test/run-make/rustdoc-scrape-examples-whitespace/Makefile [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-whitespace/examples/ex.rs [new file with mode: 0644]
src/test/run-make/rustdoc-scrape-examples-whitespace/src/lib.rs [new file with mode: 0644]
src/test/rustdoc-gui/anchors.goml
src/test/rustdoc-gui/docblock-big-code-mobile.goml
src/test/rustdoc-gui/hash-item-expansion.goml
src/test/rustdoc-gui/headers-color.goml
src/test/rustdoc-gui/headings.goml
src/test/rustdoc-gui/implementors.goml
src/test/rustdoc-gui/item-info-width.goml
src/test/rustdoc-gui/mobile.goml
src/test/rustdoc-gui/search-filter.goml
src/test/rustdoc-gui/sidebar-mobile.goml
src/test/rustdoc-gui/sidebar-source-code.goml
src/test/rustdoc-gui/sidebar.goml
src/test/rustdoc-gui/src-font-size.goml
src/test/rustdoc-gui/src/test_docs/Cargo.toml
src/test/rustdoc-gui/src/test_docs/lib.rs
src/test/rustdoc-gui/trait-sidebar-item-order.goml
src/test/rustdoc-gui/type-declation-overflow.goml
src/test/rustdoc-js-std/multi-query.js [deleted file]
src/test/rustdoc-js-std/typed-query.js
src/test/rustdoc-json/type/dyn.rs [new file with mode: 0644]
src/test/rustdoc-json/type/fn_lifetime.rs [new file with mode: 0644]
src/test/rustdoc-json/type/generic_default.rs [new file with mode: 0644]
src/test/rustdoc-ui/block-doc-comment.rs [new file with mode: 0644]
src/test/rustdoc-ui/block-doc-comment.stdout [new file with mode: 0644]
src/test/rustdoc-ui/check-attr-test.rs
src/test/rustdoc-ui/check-attr-test.stderr
src/test/rustdoc-ui/check-attr.rs
src/test/rustdoc-ui/check-attr.stderr
src/test/rustdoc-ui/intra-doc/macro-rules.rs [new file with mode: 0644]
src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs [new file with mode: 0644]
src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr [new file with mode: 0644]
src/test/rustdoc-ui/suggestions/html-as-generics.fixed [new file with mode: 0644]
src/test/rustdoc-ui/suggestions/html-as-generics.rs [new file with mode: 0644]
src/test/rustdoc-ui/suggestions/html-as-generics.stderr [new file with mode: 0644]
src/test/rustdoc/associated-consts.rs
src/test/rustdoc/async-fn.rs
src/test/rustdoc/auto_aliases.rs
src/test/rustdoc/blanket-reexport-item.rs
src/test/rustdoc/const-display.rs
src/test/rustdoc/const-generics/add-impl.rs
src/test/rustdoc/const-generics/const-generic-slice.rs
src/test/rustdoc/const-generics/const-generics-docs.rs
src/test/rustdoc/const-generics/const-impl.rs
src/test/rustdoc/deref-mut-methods.rs
src/test/rustdoc/deref-recursive-pathbuf.rs
src/test/rustdoc/deref-recursive.rs
src/test/rustdoc/deref-typedef.rs
src/test/rustdoc/double-quote-escape.rs
src/test/rustdoc/empty-impls.rs
src/test/rustdoc/ensure-src-link.rs
src/test/rustdoc/extern-default-method.rs
src/test/rustdoc/generic-impl.rs
src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/auxiliary/extern-lang-item-impl-dep.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/extern-inherent-impl.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/extern-lang-item-impl.rs [new file with mode: 0644]
src/test/rustdoc/issue-29503.rs
src/test/rustdoc/issue-33302.rs
src/test/rustdoc/issue-53812.rs
src/test/rustdoc/issue-86620.rs
src/test/rustdoc/method-list.rs
src/test/rustdoc/negative-impl-sidebar.rs
src/test/rustdoc/primitive/primitive-generic-impl.rs
src/test/rustdoc/recursive-deref-sidebar.rs
src/test/rustdoc/sidebar-items.rs
src/test/rustdoc/sidebar-link-generation.rs
src/test/rustdoc/sidebar-links-to-foreign-impl.rs
src/test/rustdoc/sized_trait.rs
src/test/rustdoc/source-version-separator.rs
src/test/rustdoc/spotlight-from-dependency.rs
src/test/rustdoc/src-links-auto-impls.rs
src/test/rustdoc/strip-block-doc-comments-stars.rs
src/test/rustdoc/trait-impl-items-links-and-anchors.rs
src/test/rustdoc/trait_alias.rs
src/test/rustdoc/version-separator-without-source.rs
src/test/rustdoc/where-clause-order.rs
src/test/ui/aligned_enum_cast.rs [new file with mode: 0644]
src/test/ui/allocator/not-an-allocator.stderr
src/test/ui/asm/aarch64/parse-error.stderr
src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr
src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr
src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr
src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr
src/test/ui/asm/reg-conflict.rs [new file with mode: 0644]
src/test/ui/asm/reg-conflict.stderr [new file with mode: 0644]
src/test/ui/asm/x86_64/parse-error.stderr
src/test/ui/associated-consts/issue-93835.rs [new file with mode: 0644]
src/test/ui/associated-consts/issue-93835.stderr [new file with mode: 0644]
src/test/ui/associated-consts/shadowed-const.rs [new file with mode: 0644]
src/test/ui/associated-consts/shadowed-const.stderr [new file with mode: 0644]
src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs
src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr
src/test/ui/associated-type-bounds/trait-params.rs
src/test/ui/associated-type-bounds/union-bounds.rs
src/test/ui/associated-types/associated-types-path-2.stderr
src/test/ui/associated-types/associated-types-stream.rs
src/test/ui/associated-types/hr-associated-type-bound-1.stderr
src/test/ui/associated-types/hr-associated-type-bound-object.stderr
src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr
src/test/ui/associated-types/hr-associated-type-bound-param-2.rs
src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr
src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr
src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr
src/test/ui/associated-types/hr-associated-type-bound-param-5.rs
src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr
src/test/ui/associated-types/issue-50301.rs
src/test/ui/associated-types/issue-91069.rs [new file with mode: 0644]
src/test/ui/associated-types/substs-ppaux.rs
src/test/ui/associated-types/substs-ppaux.verbose.stderr
src/test/ui/async-await/issue-93197.rs
src/test/ui/async-await/issue-93648.rs [new file with mode: 0644]
src/test/ui/attributes/main-removed-1.rs [new file with mode: 0644]
src/test/ui/attributes/main-removed-1.stderr [new file with mode: 0644]
src/test/ui/attributes/main-removed-2/auxiliary/tokyo.rs [new file with mode: 0644]
src/test/ui/attributes/main-removed-2/main.rs [new file with mode: 0644]
src/test/ui/attributes/used_with_arg.rs [new file with mode: 0644]
src/test/ui/attributes/used_with_arg.stderr [new file with mode: 0644]
src/test/ui/attributes/used_with_multi_args.rs [new file with mode: 0644]
src/test/ui/attributes/used_with_multi_args.stderr [new file with mode: 0644]
src/test/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
src/test/ui/binop/issue-28837.stderr
src/test/ui/borrowck/issue-64453.rs
src/test/ui/borrowck/issue-64453.stderr
src/test/ui/box/issue-78459-ice.rs [new file with mode: 0644]
src/test/ui/chalkify/assert.rs [new file with mode: 0644]
src/test/ui/chalkify/chalk_initial_program.stderr
src/test/ui/chalkify/impl_wf.stderr
src/test/ui/chalkify/impl_wf_2.stderr
src/test/ui/chalkify/println.rs
src/test/ui/chalkify/trait-objects.rs
src/test/ui/chalkify/type_wf.stderr
src/test/ui/check-static-values-constraints.rs
src/test/ui/check-static-values-constraints.stderr
src/test/ui/codemap_tests/unicode.stderr
src/test/ui/coherence/auxiliary/error_lib.rs
src/test/ui/coherence/coherence-negative-outlives-lifetimes.rs [new file with mode: 0644]
src/test/ui/coherence/coherence-negative-outlives-lifetimes.stderr [new file with mode: 0644]
src/test/ui/coherence/coherence-overlap-negate-use-feature-gate.rs
src/test/ui/coherence/coherence-overlap-negative-trait.rs
src/test/ui/coherence/coherence-overlap-with-regions.rs [new file with mode: 0644]
src/test/ui/const-generics/const-generic-default-wont-borrowck.rs [new file with mode: 0644]
src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr [new file with mode: 0644]
src/test/ui/const-generics/defaults/rp_impl_trait_fail.stderr
src/test/ui/const-generics/issue-93647.rs [new file with mode: 0644]
src/test/ui/const-generics/issue-93647.stderr [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-90318.rs
src/test/ui/const-generics/issues/issue-90318.stderr
src/test/ui/const-generics/min_const_generics/forbid-self-no-normalize.rs [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/forbid-self-no-normalize.stderr [new file with mode: 0644]
src/test/ui/const-generics/nested-type.full.stderr
src/test/ui/const-generics/nested-type.min.stderr
src/test/ui/const-generics/nested-type.rs
src/test/ui/const-generics/outer-lifetime-in-const-generic-default.rs [new file with mode: 0644]
src/test/ui/const-generics/outer-lifetime-in-const-generic-default.stderr [new file with mode: 0644]
src/test/ui/consts/const-call.rs
src/test/ui/consts/const-call.stderr
src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr
src/test/ui/consts/const-eval/const_panic.stderr
src/test/ui/consts/const-eval/const_panic_2021.stderr
src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr
src/test/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr [new file with mode: 0644]
src/test/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr [new file with mode: 0644]
src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs
src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr
src/test/ui/consts/const-fn-error.rs
src/test/ui/consts/const-fn-error.stderr
src/test/ui/consts/const-fn-not-safe-for-const.stderr
src/test/ui/consts/const-for.rs
src/test/ui/consts/const-for.stderr
src/test/ui/consts/const-mut-refs/issue-76510.32bit.stderr
src/test/ui/consts/const-mut-refs/issue-76510.64bit.stderr
src/test/ui/consts/const-mut-refs/issue-76510.rs
src/test/ui/consts/const-tup-index-span.stderr
src/test/ui/consts/const_fn_trait_bound.stock.stderr
src/test/ui/consts/control-flow/issue-46843.rs
src/test/ui/consts/control-flow/issue-46843.stderr
src/test/ui/consts/intrinsic_without_const_stab.rs
src/test/ui/consts/intrinsic_without_const_stab.stderr
src/test/ui/consts/intrinsic_without_const_stab_fail.rs
src/test/ui/consts/intrinsic_without_const_stab_fail.stderr
src/test/ui/consts/issue-28113.rs
src/test/ui/consts/issue-28113.stderr
src/test/ui/consts/issue-32829-2.rs
src/test/ui/consts/issue-32829-2.stderr
src/test/ui/consts/issue-43105.rs
src/test/ui/consts/issue-43105.stderr
src/test/ui/consts/issue-56164.rs
src/test/ui/consts/issue-56164.stderr
src/test/ui/consts/issue-68542-closure-in-array-len.rs
src/test/ui/consts/issue-68542-closure-in-array-len.stderr
src/test/ui/consts/issue-78655.rs
src/test/ui/consts/issue-78655.stderr
src/test/ui/consts/issue-90870.fixed
src/test/ui/consts/issue-90870.rs
src/test/ui/consts/issue-90870.stderr
src/test/ui/consts/issue-91560.fixed [new file with mode: 0644]
src/test/ui/consts/issue-91560.rs [new file with mode: 0644]
src/test/ui/consts/issue-91560.stderr [new file with mode: 0644]
src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs
src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr
src/test/ui/consts/min_const_fn/min_const_fn.stderr
src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr
src/test/ui/consts/mir_check_nonconst.rs
src/test/ui/consts/mir_check_nonconst.stderr
src/test/ui/consts/recursive.rs [new file with mode: 0644]
src/test/ui/consts/recursive.stderr [new file with mode: 0644]
src/test/ui/consts/unstable-const-fn-in-libcore.stderr
src/test/ui/derives/issue-91550.rs [new file with mode: 0644]
src/test/ui/derives/issue-91550.stderr [new file with mode: 0644]
src/test/ui/deriving/deriving-associated-types.rs
src/test/ui/did_you_mean/issue-39802-show-5-trait-impls.stderr
src/test/ui/error-codes/E0604.stderr
src/test/ui/error-festival.stderr
src/test/ui/feature-gates/feature-gate-allow_fail.rs [deleted file]
src/test/ui/feature-gates/feature-gate-allow_fail.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-asm_const.stderr
src/test/ui/feature-gates/feature-gate-asm_experimental_arch.stderr
src/test/ui/feature-gates/feature-gate-asm_sym.stderr
src/test/ui/feature-gates/feature-gate-asm_unwind.stderr
src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic-equal-alignment.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic-equal-alignment.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs
src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr
src/test/ui/feature-gates/feature-gate-unsafe_pin_internals.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-untagged_unions.rs
src/test/ui/feature-gates/feature-gate-untagged_unions.stderr
src/test/ui/feature-gates/feature-gate-used_with_arg.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-used_with_arg.stderr [new file with mode: 0644]
src/test/ui/fmt/format-args-capture-issue-93378.rs [new file with mode: 0644]
src/test/ui/fmt/format-args-capture-issue-93378.stderr [new file with mode: 0644]
src/test/ui/fmt/format-args-capture-issue-94010.rs [new file with mode: 0644]
src/test/ui/fmt/format-args-capture-issue-94010.stderr [new file with mode: 0644]
src/test/ui/fmt/format-args-capture-missing-variables.stderr
src/test/ui/fmt/format-args-capture.rs
src/test/ui/fmt/ifmt-bad-arg.stderr
src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs [new file with mode: 0644]
src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr [new file with mode: 0644]
src/test/ui/functions-closures/fn-help-with-err.rs [new file with mode: 0644]
src/test/ui/functions-closures/fn-help-with-err.stderr [new file with mode: 0644]
src/test/ui/generator/drop-control-flow.rs
src/test/ui/generic-associated-types/bugs/issue-80626.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-80626.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-86218.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-86218.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-87735.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-87735.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-87748.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-87748.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-87755.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-87755.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-87803.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-87803.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-88382.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-88382.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-88460.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-88460.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-88526.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-88526.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-89008.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/bugs/issue-89008.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/impl_bounds.stderr
src/test/ui/generic-associated-types/issue-74824.rs
src/test/ui/generic-associated-types/issue-74824.stderr
src/test/ui/generic-associated-types/issue-88595.rs
src/test/ui/generic-associated-types/issue-88595.stderr
src/test/ui/generic-associated-types/issue-90014.stderr
src/test/ui/generic-associated-types/issue-91139.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-91762.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-91762.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-92033.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-92033.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/self-outlives-lint.rs
src/test/ui/generic-associated-types/self-outlives-lint.stderr
src/test/ui/impl-trait/example-calendar.rs
src/test/ui/impl-trait/issue-55872-2.rs
src/test/ui/impl-trait/issue-55872-2.stderr
src/test/ui/impl-trait/issue-55872.rs
src/test/ui/impl-trait/issue-55872.stderr
src/test/ui/impl-trait/issues/issue-65581.rs
src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs [new file with mode: 0644]
src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr [new file with mode: 0644]
src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs [new file with mode: 0644]
src/test/ui/inference/char-as-str-multi.rs
src/test/ui/inference/char-as-str-multi.stderr
src/test/ui/issues/issue-14772.rs [deleted file]
src/test/ui/issues/issue-14772.stderr [deleted file]
src/test/ui/issues/issue-16538.mir.stderr
src/test/ui/issues/issue-16538.thir.stderr
src/test/ui/issues/issue-23036.rs
src/test/ui/issues/issue-23122-1.rs
src/test/ui/issues/issue-23122-2.rs
src/test/ui/issues/issue-23122-2.stderr
src/test/ui/issues/issue-25901.rs
src/test/ui/issues/issue-25901.stderr
src/test/ui/issues/issue-28561.rs
src/test/ui/issues/issue-33187.rs
src/test/ui/issues/issue-35570.stderr
src/test/ui/issues/issue-37051.rs
src/test/ui/issues/issue-39559-2.stderr
src/test/ui/issues/issue-55796.nll.stderr
src/test/ui/issues/issue-55796.rs
src/test/ui/issues/issue-55796.stderr
src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs
src/test/ui/issues/issue-85461.rs
src/test/ui/iterators/collect-into-slice.rs [new file with mode: 0644]
src/test/ui/iterators/collect-into-slice.stderr [new file with mode: 0644]
src/test/ui/kindck/kindck-copy.stderr
src/test/ui/lexer/lex-bad-char-literals-1.stderr
src/test/ui/macros/stringify.rs
src/test/ui/macros/unreachable-arg.edition_2021.stderr [new file with mode: 0644]
src/test/ui/macros/unreachable-arg.rs [new file with mode: 0644]
src/test/ui/macros/unreachable-format-arg.rs [new file with mode: 0644]
src/test/ui/macros/unreachable-format-args.edition_2015.stderr [new file with mode: 0644]
src/test/ui/macros/unreachable-format-args.rs [new file with mode: 0644]
src/test/ui/mismatched_types/cast-rfc0401.stderr
src/test/ui/never_type/issue-52443.rs
src/test/ui/never_type/issue-52443.stderr
src/test/ui/nll/issue-55825-const-fn.stderr
src/test/ui/nll/ty-outlives/issue-53789-2.rs
src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr
src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr
src/test/ui/non-fmt-panic.fixed
src/test/ui/non-fmt-panic.rs
src/test/ui/non-fmt-panic.stderr
src/test/ui/optimization-remark.rs
src/test/ui/panics/default-backtrace-ice.rs [new file with mode: 0644]
src/test/ui/panics/default-backtrace-ice.stderr [new file with mode: 0644]
src/test/ui/parser/bad-escape-suggest-raw-string.rs [new file with mode: 0644]
src/test/ui/parser/bad-escape-suggest-raw-string.stderr [new file with mode: 0644]
src/test/ui/parser/issues/issue-8537.stderr
src/test/ui/parser/issues/issue-93282.rs
src/test/ui/parser/issues/issue-93282.stderr
src/test/ui/parser/require-parens-for-chained-comparison.rs
src/test/ui/parser/require-parens-for-chained-comparison.stderr
src/test/ui/pin-macro/cant_access_internals.rs [new file with mode: 0644]
src/test/ui/pin-macro/cant_access_internals.stderr [new file with mode: 0644]
src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs [new file with mode: 0644]
src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr [new file with mode: 0644]
src/test/ui/proc-macro/quote-debug.stdout
src/test/ui/ptr_ops/issue-80309-safe.rs [new file with mode: 0644]
src/test/ui/ptr_ops/issue-80309.rs [new file with mode: 0644]
src/test/ui/regions/regions-implied-bounds-projection-gap-hr-1.stderr
src/test/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr
src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.rs
src/test/ui/rfc-2632-const-trait-impl/call-const-trait-method-fail.stderr
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.rs
src/test/ui/rfc-2632-const-trait-impl/call-generic-method-fail.stderr
src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs
src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr
src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.rs
src/test/ui/rfc-2632-const-trait-impl/const-default-method-bodies.stderr
src/test/ui/rfc-2632-const-trait-impl/cross-crate.gated.stderr
src/test/ui/rfc-2632-const-trait-impl/cross-crate.rs
src/test/ui/rfc-2632-const-trait-impl/cross-crate.stock.stderr
src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
src/test/ui/rfc-2632-const-trait-impl/issue-88155.rs
src/test/ui/rfc-2632-const-trait-impl/issue-88155.stderr
src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.rs
src/test/ui/rfc-2632-const-trait-impl/std-impl-gate.stock.stderr
src/test/ui/specialization/deafult-associated-type-bound-1.rs [deleted file]
src/test/ui/specialization/deafult-associated-type-bound-1.stderr [deleted file]
src/test/ui/specialization/deafult-associated-type-bound-2.rs [deleted file]
src/test/ui/specialization/deafult-associated-type-bound-2.stderr [deleted file]
src/test/ui/specialization/deafult-generic-associated-type-bound.rs [deleted file]
src/test/ui/specialization/deafult-generic-associated-type-bound.stderr [deleted file]
src/test/ui/specialization/default-associated-type-bound-1.rs [new file with mode: 0644]
src/test/ui/specialization/default-associated-type-bound-1.stderr [new file with mode: 0644]
src/test/ui/specialization/default-associated-type-bound-2.rs [new file with mode: 0644]
src/test/ui/specialization/default-associated-type-bound-2.stderr [new file with mode: 0644]
src/test/ui/specialization/default-generic-associated-type-bound.rs [new file with mode: 0644]
src/test/ui/specialization/default-generic-associated-type-bound.stderr [new file with mode: 0644]
src/test/ui/stability-attribute/missing-const-stability.rs
src/test/ui/stability-attribute/missing-const-stability.stderr
src/test/ui/static/static-vec-repeat-not-constant.stderr
src/test/ui/suggestions/args-instead-of-tuple-errors.rs
src/test/ui/suggestions/args-instead-of-tuple-errors.stderr
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/into-str.stderr
src/test/ui/suggestions/issue-71394-no-from-impl.stderr
src/test/ui/suggestions/issue-84973-negative.stderr
src/test/ui/suggestions/issue-86100-tuple-paren-comma.stderr
src/test/ui/symbol-names/verbose.rs [new file with mode: 0644]
src/test/ui/target-feature/tied-features-cli.one.stderr [new file with mode: 0644]
src/test/ui/target-feature/tied-features-cli.rs [new file with mode: 0644]
src/test/ui/target-feature/tied-features-cli.three.stderr [new file with mode: 0644]
src/test/ui/target-feature/tied-features-cli.two.stderr [new file with mode: 0644]
src/test/ui/target-feature/tied-features.rs [new file with mode: 0644]
src/test/ui/target-feature/tied-features.stderr [new file with mode: 0644]
src/test/ui/test-attrs/test-allow-fail-attr.rs [deleted file]
src/test/ui/test-attrs/test-on-macro.rs [deleted file]
src/test/ui/test-attrs/test-on-macro.stderr [deleted file]
src/test/ui/test-attrs/test-on-not-fn.rs [new file with mode: 0644]
src/test/ui/test-attrs/test-on-not-fn.stderr [new file with mode: 0644]
src/test/ui/trait-bounds/issue-93008.rs [new file with mode: 0644]
src/test/ui/trait-bounds/issue-93008.stderr [new file with mode: 0644]
src/test/ui/traits/associated_type_bound/check-trait-object-bounds-1.stderr
src/test/ui/traits/associated_type_bound/check-trait-object-bounds-4.stderr
src/test/ui/traits/issue-77982.stderr
src/test/ui/traits/issue-79458.stderr
src/test/ui/traits/negative-impls/auxiliary/foreign_trait.rs
src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.rs
src/test/ui/traits/negative-impls/explicitly-unimplemented-error-message.stderr
src/test/ui/traits/negative-impls/rely-on-negative-impl-in-coherence.rs
src/test/ui/traits/suggest-deferences/issue-62530.stderr
src/test/ui/try-trait/bad-interconversion.stderr
src/test/ui/type-alias-impl-trait/issue-53598.rs
src/test/ui/type-alias-impl-trait/issue-53598.stderr
src/test/ui/type-alias-impl-trait/issue-57700.rs
src/test/ui/type-alias-impl-trait/issue-57700.stderr
src/test/ui/type-alias-impl-trait/issue-60371.rs
src/test/ui/type-alias-impl-trait/issue-60371.stderr
src/test/ui/typeck/issue-91328.fixed
src/test/ui/typeck/issue-91328.rs
src/test/ui/typeck/issue-91328.stderr
src/test/ui/union/issue-41073.rs
src/test/ui/union/issue-41073.stderr
src/test/ui/union/union-custom-drop.rs
src/test/ui/union/union-custom-drop.stderr
src/test/ui/union/union-derive-clone.mirunsafeck.stderr
src/test/ui/union/union-derive-clone.thirunsafeck.stderr
src/test/ui/union/union-with-drop-fields.mirunsafeck.stderr
src/test/ui/union/union-with-drop-fields.rs
src/test/ui/union/union-with-drop-fields.thirunsafeck.stderr
src/tools/build-manifest/Cargo.toml
src/tools/build-manifest/src/main.rs
src/tools/cargo
src/tools/clippy/CHANGELOG.md
src/tools/clippy/clippy_dev/src/bless.rs
src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
src/tools/clippy/clippy_lints/src/default_union_representation.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/disallowed_methods.rs
src/tools/clippy/clippy_lints/src/disallowed_types.rs
src/tools/clippy/clippy_lints/src/eq_op.rs
src/tools/clippy/clippy_lints/src/explicit_write.rs
src/tools/clippy/clippy_lints/src/format_args.rs
src/tools/clippy/clippy_lints/src/formatting.rs
src/tools/clippy/clippy_lints/src/implicit_hasher.rs
src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
src/tools/clippy/clippy_lints/src/infinite_iter.rs
src/tools/clippy/clippy_lints/src/large_const_arrays.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.register_lints.rs
src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
src/tools/clippy/clippy_lints/src/lib.register_restriction.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/manual_memcpy.rs
src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
src/tools/clippy/clippy_lints/src/loops/single_element_loop.rs
src/tools/clippy/clippy_lints/src/loops/utils.rs
src/tools/clippy/clippy_lints/src/map_clone.rs
src/tools/clippy/clippy_lints/src/matches.rs [deleted file]
src/tools/clippy/clippy_lints/src/matches/infalliable_detructuring_match.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/match_bool.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/mod.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/single_match.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/chars_cmp.rs
src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs
src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/option_map_or_none.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_filter_map.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
src/tools/clippy/clippy_lints/src/methods/utils.rs
src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
src/tools/clippy/clippy_lints/src/methods/zst_offset.rs
src/tools/clippy/clippy_lints/src/misc.rs
src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs
src/tools/clippy/clippy_lints/src/mut_key.rs
src/tools/clippy/clippy_lints/src/mut_mutex_lock.rs
src/tools/clippy/clippy_lints/src/non_copy_const.rs
src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/ranges.rs
src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
src/tools/clippy/clippy_lints/src/swap.rs
src/tools/clippy/clippy_lints/src/trait_bounds.rs
src/tools/clippy/clippy_lints/src/transmute/mod.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_bool.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_char.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_float.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_num_to_bytes.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_ref_to_ref.rs
src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
src/tools/clippy/clippy_lints/src/transmute/unsound_collection_transmute.rs
src/tools/clippy/clippy_lints/src/transmute/useless_transmute.rs
src/tools/clippy/clippy_lints/src/types/box_collection.rs
src/tools/clippy/clippy_lints/src/types/option_option.rs
src/tools/clippy/clippy_lints/src/types/rc_buffer.rs
src/tools/clippy/clippy_lints/src/types/rc_mutex.rs
src/tools/clippy/clippy_lints/src/types/redundant_allocation.rs
src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
src/tools/clippy/clippy_lints/src/unwrap.rs
src/tools/clippy/clippy_lints/src/use_self.rs
src/tools/clippy/clippy_lints/src/utils/conf.rs
src/tools/clippy/clippy_lints/src/utils/inspector.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
src/tools/clippy/clippy_lints/src/write.rs
src/tools/clippy/clippy_utils/src/consts.rs
src/tools/clippy/clippy_utils/src/higher.rs
src/tools/clippy/clippy_utils/src/hir_utils.rs
src/tools/clippy/clippy_utils/src/lib.rs
src/tools/clippy/clippy_utils/src/macros.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/doc/common_tools_writing_lints.md
src/tools/clippy/rust-toolchain
src/tools/clippy/tests/compile-test.rs
src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/Cargo.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/clippy.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/src/main.rs [new file with mode: 0644]
src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/.clippy.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/Cargo.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/clippy.toml [new file with mode: 0644]
src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.rs [new file with mode: 0644]
src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-4968.rs
src/tools/clippy/tests/ui/crashes/ice-8250.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-8250.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/crashes/ice-8386.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/default_union_representation.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/default_union_representation.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/eq_op.rs
src/tools/clippy/tests/ui/eq_op.stderr
src/tools/clippy/tests/ui/expect_fun_call.fixed
src/tools/clippy/tests/ui/expect_fun_call.rs
src/tools/clippy/tests/ui/expect_fun_call.stderr
src/tools/clippy/tests/ui/explicit_counter_loop.stderr
src/tools/clippy/tests/ui/explicit_write.fixed
src/tools/clippy/tests/ui/explicit_write.rs
src/tools/clippy/tests/ui/explicit_write.stderr
src/tools/clippy/tests/ui/explicit_write_non_rustfix.rs [deleted file]
src/tools/clippy/tests/ui/explicit_write_non_rustfix.stderr [deleted file]
src/tools/clippy/tests/ui/get_unwrap.fixed
src/tools/clippy/tests/ui/get_unwrap.rs
src/tools/clippy/tests/ui/get_unwrap.stderr
src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
src/tools/clippy/tests/ui/manual_assert.edition2021.stderr
src/tools/clippy/tests/ui/manual_assert.rs
src/tools/clippy/tests/ui/manual_flatten.rs
src/tools/clippy/tests/ui/manual_flatten.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/non_expressive_names.stdout [deleted file]
src/tools/clippy/tests/ui/ptr_arg.rs
src/tools/clippy/tests/ui/single_match.rs
src/tools/clippy/tests/ui/single_match.stderr
src/tools/clippy/tests/ui/single_match_else.stderr
src/tools/clippy/tests/ui/starts_ends_with.fixed
src/tools/clippy/tests/ui/starts_ends_with.rs
src/tools/clippy/tests/ui/starts_ends_with.stderr
src/tools/clippy/tests/ui/transmute_undefined_repr.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/transmute_undefined_repr.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui_test/eq_op.rs [deleted file]
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/runtest.rs
src/tools/jsondocck/src/main.rs
src/tools/linkchecker/main.rs
src/tools/miri
src/tools/rls
src/tools/rust-analyzer
src/tools/rustdoc-js/tester.js
src/tools/tidy/Cargo.toml
src/tools/tidy/src/deps.rs
src/tools/tidy/src/error_codes_check.rs
triagebot.toml

index e97cd29bba5dcfd34208002113d486ad71c80179..97a31d3c97020777971fdb277b9ed5e07071178f 100644 (file)
@@ -319,9 +319,20 @@ jobs:
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
             os: macos-latest
-          - name: x86_64-apple
+          - name: x86_64-apple-1
             env:
-              SCRIPT: "./x.py --stage 2 test"
+              SCRIPT: "./x.py --stage 2 test --exclude src/test/ui --exclude src/test/rustdoc --exclude src/test/run-make-fulldeps"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.8
+              MACOSX_STD_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+              NO_OVERFLOW_CHECKS: 1
+            os: macos-latest
+          - name: x86_64-apple-2
+            env:
+              SCRIPT: "./x.py --stage 2 test src/test/ui src/test/rustdoc src/test/run-make-fulldeps"
               RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.8
index 87437a16fb392c2b09e3fca8beea5a3997f27243..ec6cb6ed2e4d3fdeb3ca5ff9d1274076f208ff1a 100644 (file)
@@ -71,6 +71,7 @@ __pycache__/
 ## Node
 node_modules
 package-lock.json
+package.json
 
 ## Rustdoc GUI tests
 src/test/rustdoc-gui/src/**.lock
index c60a0dd2c7c43a008e785973322e157a6b19ff19..9f54ed5bdab6d3abf747a47bc63c1931d10ce862 100644 (file)
@@ -34,7 +34,7 @@
 [submodule "src/llvm-project"]
        path = src/llvm-project
        url = https://github.com/rust-lang/llvm-project.git
-       branch = rustc/13.0-2021-09-30
+       branch = rustc/14.0-2022-02-09
 [submodule "src/doc/embedded-book"]
        path = src/doc/embedded-book
        url = https://github.com/rust-embedded/book.git
index ac221fa3a60e464ced301ce0e611295510ddbc30..d72e6ebcb65fa237194cd68c8ccb2721a4392abe 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -173,7 +173,7 @@ Kyle J Strand <batmanaod@gmail.com> <kyle.j.strand@gmail.com>
 Kyle J Strand <batmanaod@gmail.com> <kyle.strand@pieinsurance.com>
 Kyle J Strand <batmanaod@gmail.com> <kyle.strand@rms.com>
 Laurențiu Nicola <lnicola@dend.ro>
-lcnr <bastian_kauschke@hotmail.de>
+lcnr <rust@lcnr.de> <bastian_kauschke@hotmail.de>
 Lee Jeffery <leejeffery@gmail.com> Lee Jeffery <lee@leejeffery.co.uk>
 Lee Wondong <wdlee91@gmail.com>
 Lennart Kudling <github@kudling.de>
index 208ce841759b990e243e44f48a38b91f016c1903..fd65ed8d4a2d6fdf857dcf4f941016c140763144 100644 (file)
@@ -78,15 +78,6 @@ dependencies = [
  "yansi-term",
 ]
 
-[[package]]
-name = "ansi_term"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
-dependencies = [
- "winapi",
-]
-
 [[package]]
 name = "ansi_term"
 version = "0.12.1"
@@ -203,9 +194,9 @@ dependencies = [
 
 [[package]]
 name = "block-buffer"
-version = "0.9.0"
+version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324"
 dependencies = [
  "generic-array 0.14.4",
 ]
@@ -236,7 +227,6 @@ dependencies = [
  "pretty_assertions",
  "serde",
  "serde_json",
- "time",
  "toml",
  "winapi",
 ]
@@ -370,7 +360,7 @@ dependencies = [
  "pretty_env_logger",
  "rustc-workspace-hack",
  "rustfix 0.6.0",
- "semver 1.0.3",
+ "semver",
  "serde",
  "serde_ignored",
  "serde_json",
@@ -489,17 +479,6 @@ dependencies = [
  "winapi",
 ]
 
-[[package]]
-name = "cargo_metadata"
-version = "0.12.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345"
-dependencies = [
- "semver 0.11.0",
- "serde",
- "serde_json",
-]
-
 [[package]]
 name = "cargo_metadata"
 version = "0.14.0"
@@ -508,7 +487,7 @@ checksum = "c297bd3135f558552f99a0daa180876984ea2c4ffa7470314540dff8c654109a"
 dependencies = [
  "camino",
  "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "semver 1.0.3",
+ "semver",
  "serde",
  "serde_json",
 ]
@@ -615,7 +594,7 @@ version = "2.34.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
 dependencies = [
- "ansi_term 0.12.1",
+ "ansi_term",
  "atty",
  "bitflags",
  "strsim 0.8.0",
@@ -644,13 +623,13 @@ dependencies = [
 name = "clippy"
 version = "0.1.60"
 dependencies = [
- "cargo_metadata 0.14.0",
+ "cargo_metadata",
  "clippy_lints",
  "clippy_utils",
  "compiletest_rs",
  "derive-new",
  "filetime",
- "futures 0.3.12",
+ "futures 0.3.19",
  "if_chain",
  "itertools 0.10.1",
  "parking_lot",
@@ -658,7 +637,7 @@ dependencies = [
  "regex",
  "rustc-workspace-hack",
  "rustc_tools_util 0.2.0",
- "semver 1.0.3",
+ "semver",
  "serde",
  "syn",
  "tempfile",
@@ -671,7 +650,7 @@ name = "clippy_dev"
 version = "0.0.1"
 dependencies = [
  "bytecount",
- "cargo_metadata 0.14.0",
+ "cargo_metadata",
  "clap 2.34.0",
  "indoc",
  "itertools 0.10.1",
@@ -685,7 +664,7 @@ dependencies = [
 name = "clippy_lints"
 version = "0.1.60"
 dependencies = [
- "cargo_metadata 0.14.0",
+ "cargo_metadata",
  "clippy_utils",
  "if_chain",
  "itertools 0.10.1",
@@ -693,7 +672,7 @@ dependencies = [
  "quine-mc_cluskey",
  "regex-syntax",
  "rustc-semver",
- "semver 1.0.3",
+ "semver",
  "serde",
  "serde_json",
  "toml",
@@ -761,9 +740,9 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.67"
+version = "0.1.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a68c69e9451f1df4b215c9588c621670c12286b53e60fb5ec4b59aaa1138d18e"
+checksum = "80873f979f0a344a4ade87c2f70d9ccf5720b83b10c97ec7cd745895d021e85a"
 dependencies = [
  "cc",
  "rustc-std-workspace-core",
@@ -842,10 +821,13 @@ name = "coverage_test_macros"
 version = "0.0.0"
 
 [[package]]
-name = "cpuid-bool"
-version = "0.1.2"
+name = "cpufeatures"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
+checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469"
+dependencies = [
+ "libc",
+]
 
 [[package]]
 name = "crates-io"
@@ -912,6 +894,15 @@ dependencies = [
  "lazy_static",
 ]
 
+[[package]]
+name = "crypto-common"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06"
+dependencies = [
+ "generic-array 0.14.4",
+]
+
 [[package]]
 name = "crypto-hash"
 version = "0.3.4"
@@ -1026,11 +1017,12 @@ dependencies = [
 
 [[package]]
 name = "digest"
-version = "0.9.0"
+version = "0.10.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
+checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837"
 dependencies = [
- "generic-array 0.14.4",
+ "block-buffer 0.10.2",
+ "crypto-common",
 ]
 
 [[package]]
@@ -1324,15 +1316,15 @@ dependencies = [
 
 [[package]]
 name = "futures"
-version = "0.1.29"
+version = "0.1.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef"
+checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678"
 
 [[package]]
 name = "futures"
-version = "0.3.12"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da9052a1a50244d8d5aa9bf55cbc2fb6f357c86cc52e46c62ed390a7180cf150"
+checksum = "28560757fe2bb34e79f907794bb6b22ae8b0e5c669b638a1132f2592b19035b4"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -1345,9 +1337,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.12"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2d31b7ec7efab6eefc7c57233bb10b847986139d88cc2f5a02a1ae6871a1846"
+checksum = "ba3dda0b6588335f360afc675d0564c17a77a2bda81ca178a4b6081bd86c7f0b"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -1355,15 +1347,15 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.12"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79e5145dde8da7d1b3892dad07a9c98fc04bc39892b1ecc9692cf53e2b780a65"
+checksum = "d0c8ff0461b82559810cdccfde3215c3f373807f5e5232b71479bff7bb2583d7"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.12"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9e59fdc009a4b3096bf94f740a0f2424c082521f20a9b08c5c07c48d90fd9b9"
+checksum = "29d6d2ff5bb10fb95c85b8ce46538a2e5f5e7fdc755623a7d4529ab8a4ed9d2a"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -1373,17 +1365,16 @@ dependencies = [
 
 [[package]]
 name = "futures-io"
-version = "0.3.12"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28be053525281ad8259d47e4de5de657b25e7bac113458555bb4b70bc6870500"
+checksum = "b1f9d34af5a1aac6fb380f735fe510746c38067c5bf16c7fd250280503c971b2"
 
 [[package]]
 name = "futures-macro"
-version = "0.3.12"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c287d25add322d9f9abdcdc5927ca398917996600182178774032e9f8258fedd"
+checksum = "6dbd947adfffb0efc70599b3ddcf7b5597bb5fa9e245eb99f62b3a5f7bb8bd3c"
 dependencies = [
- "proc-macro-hack",
  "proc-macro2",
  "quote",
  "syn",
@@ -1391,26 +1382,23 @@ dependencies = [
 
 [[package]]
 name = "futures-sink"
-version = "0.3.12"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "caf5c69029bda2e743fddd0582d1083951d65cc9539aebf8812f36c3491342d6"
+checksum = "e3055baccb68d74ff6480350f8d6eb8fcfa3aa11bdc1a1ae3afdd0514617d508"
 
 [[package]]
 name = "futures-task"
-version = "0.3.12"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13de07eb8ea81ae445aca7b69f5f7bf15d7bf4912d8ca37d6645c77ae8a58d86"
-dependencies = [
- "once_cell",
-]
+checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
 
 [[package]]
 name = "futures-util"
-version = "0.3.12"
+version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "632a8cd0f2a4b3fdea1657f08bde063848c3bd00f9bbf6e256b8be78802e624b"
+checksum = "d9b5cf40b47a271f77a8b1bec03ca09044d99d2372c0de244e66430761127164"
 dependencies = [
- "futures 0.1.29",
+ "futures 0.1.31",
  "futures-channel",
  "futures-core",
  "futures-io",
@@ -1420,8 +1408,6 @@ dependencies = [
  "memchr",
  "pin-project-lite",
  "pin-utils",
- "proc-macro-hack",
- "proc-macro-nested",
  "slab",
 ]
 
@@ -1866,7 +1852,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a"
 dependencies = [
  "derive_more",
- "futures 0.3.12",
+ "futures 0.3.19",
  "jsonrpc-core",
  "jsonrpc-pubsub",
  "jsonrpc-server-utils",
@@ -1884,7 +1870,7 @@ version = "18.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb"
 dependencies = [
- "futures 0.3.12",
+ "futures 0.3.19",
  "futures-executor",
  "futures-util",
  "log",
@@ -1899,7 +1885,7 @@ version = "18.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0"
 dependencies = [
- "futures 0.3.12",
+ "futures 0.3.19",
  "jsonrpc-client-transports",
 ]
 
@@ -1921,7 +1907,7 @@ version = "18.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "382bb0206323ca7cda3dcd7e245cea86d37d02457a02a975e3378fb149a48845"
 dependencies = [
- "futures 0.3.12",
+ "futures 0.3.19",
  "jsonrpc-core",
  "jsonrpc-server-utils",
  "log",
@@ -1936,7 +1922,7 @@ version = "18.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011"
 dependencies = [
- "futures 0.3.12",
+ "futures 0.3.19",
  "jsonrpc-core",
  "lazy_static",
  "log",
@@ -1952,7 +1938,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4"
 dependencies = [
  "bytes",
- "futures 0.3.12",
+ "futures 0.3.19",
  "globset",
  "jsonrpc-core",
  "lazy_static",
@@ -2069,9 +2055,9 @@ dependencies = [
 
 [[package]]
 name = "linked-hash-map"
-version = "0.5.3"
+version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
+checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
 
 [[package]]
 name = "lint-docs"
@@ -2159,16 +2145,13 @@ checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
 
 [[package]]
 name = "markup5ever"
-version = "0.10.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aae38d669396ca9b707bfc3db254bc382ddb94f57cc5c235f34623a669a01dab"
+checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd"
 dependencies = [
  "log",
  "phf",
  "phf_codegen",
- "serde",
- "serde_derive",
- "serde_json",
  "string_cache",
  "string_cache_codegen",
  "tendril",
@@ -2203,13 +2186,11 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
 
 [[package]]
 name = "md-5"
-version = "0.9.1"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15"
+checksum = "e6a38fc55c8bbc10058782919516f88826e70320db6d206aebc49611d24216ae"
 dependencies = [
- "block-buffer 0.9.0",
- "digest 0.9.0",
- "opaque-debug 0.3.0",
+ "digest 0.10.2",
 ]
 
 [[package]]
@@ -2325,9 +2306,9 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "0.7.13"
+version = "0.7.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16"
+checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
 dependencies = [
  "libc",
  "log",
@@ -2411,9 +2392,9 @@ dependencies = [
 
 [[package]]
 name = "num_cpus"
-version = "1.13.0"
+version = "1.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
 dependencies = [
  "hermit-abi",
  "libc",
@@ -2465,12 +2446,6 @@ version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"
 
-[[package]]
-name = "opaque-debug"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
-
 [[package]]
 name = "opener"
 version = "0.5.0"
@@ -2503,9 +2478,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
 
 [[package]]
 name = "openssl-src"
-version = "111.16.0+1.1.1l"
+version = "111.17.0+1.1.1m"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ab2173f69416cf3ec12debb5823d244127d23a9b127d5a5189aa97c5fa2859f"
+checksum = "05d6a336abd10814198f66e2a91ccd7336611f30334119ca8ce300536666fcf4"
 dependencies = [
  "cc",
 ]
@@ -2598,7 +2573,7 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9981e32fb75e004cc148f5fb70342f393830e0a4aa62e3cc93b50976218d42b6"
 dependencies = [
- "futures 0.3.12",
+ "futures 0.3.19",
  "libc",
  "log",
  "rand 0.7.3",
@@ -2792,13 +2767,13 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 
 [[package]]
 name = "pretty_assertions"
-version = "0.6.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427"
+checksum = "1cab0e7c02cf376875e9335e0ba1da535775beb5450d21e1dffca068818ed98b"
 dependencies = [
- "ansi_term 0.11.0",
+ "ansi_term",
  "ctor",
- "difference",
+ "diff",
  "output_vt100",
 ]
 
@@ -2845,18 +2820,6 @@ dependencies = [
  "version_check",
 ]
 
-[[package]]
-name = "proc-macro-hack"
-version = "0.5.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
-
-[[package]]
-name = "proc-macro-nested"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086"
-
 [[package]]
 name = "proc-macro2"
 version = "1.0.30"
@@ -3164,12 +3127,12 @@ dependencies = [
  "anyhow",
  "cargo",
  "cargo-util",
- "cargo_metadata 0.14.0",
+ "cargo_metadata",
  "clippy_lints",
  "crossbeam-channel",
  "difference",
  "env_logger 0.9.0",
- "futures 0.3.12",
+ "futures 0.3.19",
  "heck",
  "home",
  "itertools 0.10.1",
@@ -3202,13 +3165,14 @@ dependencies = [
  "tokio-stream",
  "tokio-util",
  "toml",
+ "toml_edit",
  "url 2.2.2",
  "walkdir",
 ]
 
 [[package]]
 name = "rls-analysis"
-version = "0.18.2"
+version = "0.18.3"
 dependencies = [
  "derive-new",
  "env_logger 0.9.0",
@@ -3251,7 +3215,7 @@ version = "0.6.0"
 dependencies = [
  "clippy_lints",
  "env_logger 0.9.0",
- "futures 0.3.12",
+ "futures 0.3.19",
  "log",
  "rand 0.8.4",
  "rls-data",
@@ -4294,7 +4258,7 @@ dependencies = [
  "rustc_macros",
  "rustc_serialize",
  "scoped-tls",
- "sha-1 0.9.1",
+ "sha-1 0.10.0",
  "sha2",
  "tracing",
  "unicode-width",
@@ -4442,7 +4406,7 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
 dependencies = [
- "semver 1.0.3",
+ "semver",
 ]
 
 [[package]]
@@ -4453,7 +4417,7 @@ dependencies = [
  "askama",
  "atty",
  "expect-test",
- "itertools 0.9.0",
+ "itertools 0.10.1",
  "minifier",
  "pulldown-cmark",
  "rayon",
@@ -4528,7 +4492,7 @@ dependencies = [
  "annotate-snippets",
  "anyhow",
  "bytecount",
- "cargo_metadata 0.14.0",
+ "cargo_metadata",
  "derive-new",
  "diff",
  "dirs",
@@ -4618,16 +4582,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "semver"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
-dependencies = [
- "semver-parser",
- "serde",
-]
-
 [[package]]
 name = "semver"
 version = "1.0.3"
@@ -4637,15 +4591,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "semver-parser"
-version = "0.10.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
-dependencies = [
- "pest",
-]
-
 [[package]]
 name = "serde"
 version = "1.0.125"
@@ -4707,33 +4652,29 @@ dependencies = [
  "block-buffer 0.7.3",
  "digest 0.8.1",
  "fake-simd",
- "opaque-debug 0.2.3",
+ "opaque-debug",
 ]
 
 [[package]]
 name = "sha-1"
-version = "0.9.1"
+version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "170a36ea86c864a3f16dd2687712dd6646f7019f301e57537c7f4dc9f5916770"
+checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
 dependencies = [
- "block-buffer 0.9.0",
- "cfg-if 0.1.10",
- "cpuid-bool",
- "digest 0.9.0",
- "opaque-debug 0.3.0",
+ "cfg-if 1.0.0",
+ "cpufeatures",
+ "digest 0.10.2",
 ]
 
 [[package]]
 name = "sha2"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1"
+checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec"
 dependencies = [
- "block-buffer 0.9.0",
- "cfg-if 0.1.10",
- "cpuid-bool",
- "digest 0.9.0",
- "opaque-debug 0.3.0",
+ "cfg-if 1.0.0",
+ "cpufeatures",
+ "digest 0.10.2",
 ]
 
 [[package]]
@@ -5140,7 +5081,7 @@ dependencies = [
 name = "tidy"
 version = "0.1.0"
 dependencies = [
- "cargo_metadata 0.12.0",
+ "cargo_metadata",
  "crossbeam-utils",
  "lazy_static",
  "regex",
@@ -5304,7 +5245,7 @@ version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "245da694cc7fc4729f3f418b304cb57789f1bed2a78c575407ab8a23f53cb4d3"
 dependencies = [
- "ansi_term 0.12.1",
+ "ansi_term",
  "lazy_static",
  "matchers",
  "parking_lot",
@@ -5323,7 +5264,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3ce989c9962c7f61fe084dd4a230eec784649dfc2392467c790007c3a6e134e7"
 dependencies = [
- "ansi_term 0.12.1",
+ "ansi_term",
  "atty",
  "tracing-core",
  "tracing-log",
index aae2a669650141cbd4fb421b99c399f043383b42..a9422fa103ed83006cf055d19060b59395138a8a 100644 (file)
@@ -156,6 +156,7 @@ Language
 - [Macro attributes may follow `#[derive]` and will see the original (pre-`cfg`) input.][87220]
 - [Accept curly-brace macros in expressions, like `m!{ .. }.method()` and `m!{ .. }?`.][88690]
 - [Allow panicking in constant evaluation.][89508]
+- [Ignore derived `Clone` and `Debug` implementations during dead code analysis.][85200]
 
 Compiler
 --------
@@ -216,6 +217,9 @@ Cargo
 Compatibility notes
 -------------------
 
+- [Ignore derived `Clone` and `Debug` implementations during dead code analysis.][85200]
+  This will break some builds that set `#![deny(dead_code)]`.
+
 Internal changes
 ----------------
 These changes provide no direct user facing benefits, but represent significant
@@ -224,6 +228,7 @@ and related tools.
 
 - [Added an experimental backend for codegen with `libgccjit`.][87260]
 
+[85200]: https://github.com/rust-lang/rust/pull/85200/
 [86191]: https://github.com/rust-lang/rust/pull/86191/
 [87220]: https://github.com/rust-lang/rust/pull/87220/
 [87260]: https://github.com/rust-lang/rust/pull/87260/
index 7c19559ed91f59fc10c2d3fdfb0d4a7c4ebc094d..e9135b7163025aff04b91749d10314e4be7e2031 100644 (file)
@@ -54,7 +54,7 @@
 /// ```
 ///
 /// `'outer` is a label.
-#[derive(Clone, Encodable, Decodable, Copy, HashStable_Generic)]
+#[derive(Clone, Encodable, Decodable, Copy, HashStable_Generic, Eq, PartialEq)]
 pub struct Label {
     pub ident: Ident,
 }
index 612ee71f350f16e31b218607a8dabdd2bdbea7d4..f51b0086dc8b6d6be5b784c677f93c067505428c 100644 (file)
@@ -43,7 +43,7 @@ fn get_vertical_trim(lines: &[&str]) -> Option<(usize, usize)> {
         if i != 0 || j != lines.len() { Some((i, j)) } else { None }
     }
 
-    fn get_horizontal_trim(lines: &[&str], kind: CommentKind) -> Option<usize> {
+    fn get_horizontal_trim<'a>(lines: &'a [&str], kind: CommentKind) -> Option<String> {
         let mut i = usize::MAX;
         let mut first = true;
 
@@ -51,7 +51,8 @@ fn get_horizontal_trim(lines: &[&str], kind: CommentKind) -> Option<usize> {
         // present. However, we first need to strip the empty lines so they don't get in the middle
         // when we try to compute the "horizontal trim".
         let lines = if kind == CommentKind::Block {
-            let mut i = 0;
+            // Whatever happens, we skip the first line.
+            let mut i = if lines[0].trim_start().starts_with('*') { 0 } else { 1 };
             let mut j = lines.len();
 
             while i < j && lines[i].trim().is_empty() {
@@ -84,7 +85,7 @@ fn get_horizontal_trim(lines: &[&str], kind: CommentKind) -> Option<usize> {
                 return None;
             }
         }
-        Some(i)
+        if lines.is_empty() { None } else { Some(lines[0][..i].into()) }
     }
 
     let data_s = data.as_str();
@@ -102,8 +103,13 @@ fn get_horizontal_trim(lines: &[&str], kind: CommentKind) -> Option<usize> {
             changes = true;
             // remove a "[ \t]*\*" block from each line, if possible
             for line in lines.iter_mut() {
-                if horizontal + 1 < line.len() {
-                    *line = &line[horizontal + 1..];
+                if let Some(tmp) = line.strip_prefix(&horizontal) {
+                    *line = tmp;
+                    if kind == CommentKind::Block
+                        && (*line == "*" || line.starts_with("* ") || line.starts_with("**"))
+                    {
+                        *line = &line[1..];
+                    }
                 }
             }
         }
index 98f692a7724e2778b9410ff4e8d85ae8e59273dd..11d50603a1011fb84f483c82731bce45664789d8 100644 (file)
@@ -24,7 +24,7 @@ fn test_block_doc_comment_3() {
     create_default_session_globals_then(|| {
         let comment = "\n let a: *i32;\n *a = 5;\n";
         let stripped = beautify_doc_string(Symbol::intern(comment), CommentKind::Block);
-        assert_eq!(stripped.as_str(), " let a: *i32;\n *a = 5;");
+        assert_eq!(stripped.as_str(), "let a: *i32;\n*a = 5;");
     })
 }
 
@@ -41,3 +41,21 @@ fn test_line_doc_comment() {
         assert_eq!(stripped.as_str(), "!test");
     })
 }
+
+#[test]
+fn test_doc_blocks() {
+    create_default_session_globals_then(|| {
+        let stripped =
+            beautify_doc_string(Symbol::intern(" # Returns\n     *\n     "), CommentKind::Block);
+        assert_eq!(stripped.as_str(), " # Returns\n\n");
+
+        let stripped = beautify_doc_string(
+            Symbol::intern("\n     * # Returns\n     *\n     "),
+            CommentKind::Block,
+        );
+        assert_eq!(stripped.as_str(), " # Returns\n\n");
+
+        let stripped = beautify_doc_string(Symbol::intern("\n *     a\n "), CommentKind::Block);
+        assert_eq!(stripped.as_str(), "     a\n");
+    })
+}
index 89d411d4b36fe78a2f60e5bac14f7417e56bb5d3..5a85356d96daa065ea0b2022da73cb571cb21006 100644 (file)
@@ -373,7 +373,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                     err.emit();
                                 }
                                 Entry::Vacant(v) => {
-                                    v.insert(idx);
+                                    if r == reg {
+                                        v.insert(idx);
+                                    }
                                 }
                             }
                         };
index cacc36b616a1e05590762693c4db09376445738a..f48cf212a984bca1cbc3511f1c4cb2568674a7d9 100644 (file)
@@ -894,9 +894,6 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
             AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
         };
 
-        // Since `default impl` is not yet implemented, this is always true in impls.
-        let has_value = true;
-        let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
         let hir_id = self.lower_node_id(i.id);
         self.lower_attrs(hir_id, &i.attrs);
         let item = hir::ImplItem {
@@ -904,7 +901,6 @@ fn lower_impl_item(&mut self, i: &AssocItem) -> &'hir hir::ImplItem<'hir> {
             ident: self.lower_ident(i.ident),
             generics,
             vis: self.lower_visibility(&i.vis),
-            defaultness,
             kind,
             span: self.lower_span(i.span),
         };
index a6ecfa4520608a42cf1425844db1171b84313733..0a96e60d4d3af58cd667412635663304faa98eb2 100644 (file)
@@ -196,6 +196,54 @@ fn check_abi(&self, abi: ast::StrLit) {
                     "thiscall-unwind ABI is experimental and subject to change"
                 );
             }
+            "cdecl-unwind" => {
+                gate_feature_post!(
+                    &self,
+                    c_unwind,
+                    span,
+                    "cdecl-unwind ABI is experimental and subject to change"
+                );
+            }
+            "fastcall-unwind" => {
+                gate_feature_post!(
+                    &self,
+                    c_unwind,
+                    span,
+                    "fastcall-unwind ABI is experimental and subject to change"
+                );
+            }
+            "vectorcall-unwind" => {
+                gate_feature_post!(
+                    &self,
+                    c_unwind,
+                    span,
+                    "vectorcall-unwind ABI is experimental and subject to change"
+                );
+            }
+            "aapcs-unwind" => {
+                gate_feature_post!(
+                    &self,
+                    c_unwind,
+                    span,
+                    "aapcs-unwind ABI is experimental and subject to change"
+                );
+            }
+            "win64-unwind" => {
+                gate_feature_post!(
+                    &self,
+                    c_unwind,
+                    span,
+                    "win64-unwind ABI is experimental and subject to change"
+                );
+            }
+            "sysv64-unwind" => {
+                gate_feature_post!(
+                    &self,
+                    c_unwind,
+                    span,
+                    "sysv64-unwind ABI is experimental and subject to change"
+                );
+            }
             "wasm" => {
                 gate_feature_post!(
                     &self,
index 26d600cefc7c0bfd68fe18da57b0e4407a4fe461..ddce86f216538fc0732ae216bfadccf336e65889 100644 (file)
 //! methods called `Printer::scan_*`, and the 'PRINT' process is the
 //! method called `Printer::print`.
 
+mod convenience;
 mod ring;
 
 use ring::RingBuffer;
@@ -147,7 +148,7 @@ pub enum Breaks {
     Inconsistent,
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
 enum IndentStyle {
     /// Vertically aligned under whatever column this block begins at.
     ///
@@ -163,19 +164,20 @@ enum IndentStyle {
     Block { offset: isize },
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default, PartialEq)]
 pub struct BreakToken {
     offset: isize,
     blank_space: isize,
+    pre_break: Option<char>,
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
 pub struct BeginToken {
     indent: IndentStyle,
     breaks: Breaks,
 }
 
-#[derive(Clone)]
+#[derive(Clone, PartialEq)]
 pub enum Token {
     // In practice a string token contains either a `&'static str` or a
     // `String`. `Cow` is overkill for this because we never modify the data,
@@ -186,12 +188,6 @@ pub enum Token {
     End,
 }
 
-impl Token {
-    pub fn is_hardbreak_tok(&self) -> bool {
-        matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY }))
-    }
-}
-
 #[derive(Copy, Clone)]
 enum PrintFrame {
     Fits,
@@ -318,6 +314,12 @@ fn scan_string(&mut self, string: Cow<'static, str>) {
         }
     }
 
+    pub fn offset(&mut self, offset: isize) {
+        if let Some(BufEntry { token: Token::Break(token), .. }) = &mut self.buf.last_mut() {
+            token.offset += offset;
+        }
+    }
+
     fn check_stream(&mut self) {
         while self.right_total - self.left_total > self.space {
             if *self.scan_stack.front().unwrap() == self.buf.index_of_first() {
@@ -396,7 +398,9 @@ fn print_begin(&mut self, token: BeginToken, size: isize) {
         if size > self.space {
             self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks });
             self.indent = match token.indent {
-                IndentStyle::Block { offset } => (self.indent as isize + offset) as usize,
+                IndentStyle::Block { offset } => {
+                    usize::try_from(self.indent as isize + offset).unwrap()
+                }
                 IndentStyle::Visual => (MARGIN - self.space) as usize,
             };
         } else {
@@ -420,6 +424,9 @@ fn print_break(&mut self, token: BreakToken, size: isize) {
             self.pending_indentation += token.blank_space;
             self.space -= token.blank_space;
         } else {
+            if let Some(pre_break) = token.pre_break {
+                self.out.push(pre_break);
+            }
             self.out.push('\n');
             let indent = self.indent as isize + token.offset;
             self.pending_indentation = indent;
@@ -441,73 +448,4 @@ fn print_string(&mut self, string: &str) {
         self.out.push_str(string);
         self.space -= string.len() as isize;
     }
-
-    // Convenience functions to talk to the printer.
-
-    /// "raw box"
-    pub fn rbox(&mut self, indent: usize, breaks: Breaks) {
-        self.scan_begin(BeginToken {
-            indent: IndentStyle::Block { offset: indent as isize },
-            breaks,
-        })
-    }
-
-    /// Inconsistent breaking box
-    pub fn ibox(&mut self, indent: usize) {
-        self.rbox(indent, Breaks::Inconsistent)
-    }
-
-    /// Consistent breaking box
-    pub fn cbox(&mut self, indent: usize) {
-        self.rbox(indent, Breaks::Consistent)
-    }
-
-    pub fn visual_align(&mut self) {
-        self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent });
-    }
-
-    pub fn break_offset(&mut self, n: usize, off: isize) {
-        self.scan_break(BreakToken { offset: off, blank_space: n as isize })
-    }
-
-    pub fn end(&mut self) {
-        self.scan_end()
-    }
-
-    pub fn eof(mut self) -> String {
-        self.scan_eof();
-        self.out
-    }
-
-    pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
-        let string = wrd.into();
-        self.scan_string(string)
-    }
-
-    fn spaces(&mut self, n: usize) {
-        self.break_offset(n, 0)
-    }
-
-    pub fn zerobreak(&mut self) {
-        self.spaces(0)
-    }
-
-    pub fn space(&mut self) {
-        self.spaces(1)
-    }
-
-    pub fn hardbreak(&mut self) {
-        self.spaces(SIZE_INFINITY as usize)
-    }
-
-    pub fn is_beginning_of_line(&self) -> bool {
-        match self.last_token() {
-            Some(last_token) => last_token.is_hardbreak_tok(),
-            None => true,
-        }
-    }
-
-    pub fn hardbreak_tok_offset(off: isize) -> Token {
-        Token::Break(BreakToken { offset: off, blank_space: SIZE_INFINITY })
-    }
 }
diff --git a/compiler/rustc_ast_pretty/src/pp/convenience.rs b/compiler/rustc_ast_pretty/src/pp/convenience.rs
new file mode 100644 (file)
index 0000000..93310dd
--- /dev/null
@@ -0,0 +1,94 @@
+use crate::pp::{BeginToken, BreakToken, Breaks, IndentStyle, Printer, Token, SIZE_INFINITY};
+use std::borrow::Cow;
+
+impl Printer {
+    /// "raw box"
+    pub fn rbox(&mut self, indent: isize, breaks: Breaks) {
+        self.scan_begin(BeginToken { indent: IndentStyle::Block { offset: indent }, breaks })
+    }
+
+    /// Inconsistent breaking box
+    pub fn ibox(&mut self, indent: isize) {
+        self.rbox(indent, Breaks::Inconsistent)
+    }
+
+    /// Consistent breaking box
+    pub fn cbox(&mut self, indent: isize) {
+        self.rbox(indent, Breaks::Consistent)
+    }
+
+    pub fn visual_align(&mut self) {
+        self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent });
+    }
+
+    pub fn break_offset(&mut self, n: usize, off: isize) {
+        self.scan_break(BreakToken {
+            offset: off,
+            blank_space: n as isize,
+            ..BreakToken::default()
+        });
+    }
+
+    pub fn end(&mut self) {
+        self.scan_end()
+    }
+
+    pub fn eof(mut self) -> String {
+        self.scan_eof();
+        self.out
+    }
+
+    pub fn word<S: Into<Cow<'static, str>>>(&mut self, wrd: S) {
+        let string = wrd.into();
+        self.scan_string(string)
+    }
+
+    fn spaces(&mut self, n: usize) {
+        self.break_offset(n, 0)
+    }
+
+    pub fn zerobreak(&mut self) {
+        self.spaces(0)
+    }
+
+    pub fn space(&mut self) {
+        self.spaces(1)
+    }
+
+    pub fn hardbreak(&mut self) {
+        self.spaces(SIZE_INFINITY as usize)
+    }
+
+    pub fn is_beginning_of_line(&self) -> bool {
+        match self.last_token() {
+            Some(last_token) => last_token.is_hardbreak_tok(),
+            None => true,
+        }
+    }
+
+    pub fn hardbreak_tok_offset(off: isize) -> Token {
+        Token::Break(BreakToken {
+            offset: off,
+            blank_space: SIZE_INFINITY,
+            ..BreakToken::default()
+        })
+    }
+
+    pub fn trailing_comma(&mut self) {
+        self.scan_break(BreakToken { pre_break: Some(','), ..BreakToken::default() });
+    }
+
+    pub fn trailing_comma_or_space(&mut self) {
+        self.scan_break(BreakToken {
+            blank_space: 1,
+            pre_break: Some(','),
+            ..BreakToken::default()
+        });
+    }
+}
+
+impl Token {
+    pub fn is_hardbreak_tok(&self) -> bool {
+        *self == Printer::hardbreak_tok_offset(0)
+    }
+}
index b575dc21961337b0976f5ae4c0d06deabc33988b..b2c62383fb69af5600a325f4223d730c3b5d590b 100644 (file)
@@ -1,3 +1,4 @@
+mod delimited;
 mod expr;
 mod item;
 
@@ -23,6 +24,8 @@
 
 use std::borrow::Cow;
 
+pub use self::delimited::IterDelimited;
+
 pub enum MacHeader<'a> {
     Path(&'a ast::Path),
     Keyword(&'static str),
@@ -92,7 +95,7 @@ pub struct State<'a> {
     ann: &'a (dyn PpAnn + 'a),
 }
 
-crate const INDENT_UNIT: usize = 4;
+crate const INDENT_UNIT: isize = 4;
 
 /// Requires you to pass an input filename and reader so that
 /// it can scan the input text for comments to copy forward.
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs b/compiler/rustc_ast_pretty/src/pprust/state/delimited.rs
new file mode 100644 (file)
index 0000000..fe0640b
--- /dev/null
@@ -0,0 +1,41 @@
+use std::iter::Peekable;
+use std::mem;
+use std::ops::Deref;
+
+pub struct Delimited<I: Iterator> {
+    is_first: bool,
+    iter: Peekable<I>,
+}
+
+pub trait IterDelimited: Iterator + Sized {
+    fn delimited(self) -> Delimited<Self> {
+        Delimited { is_first: true, iter: self.peekable() }
+    }
+}
+
+impl<I: Iterator> IterDelimited for I {}
+
+pub struct IteratorItem<T> {
+    value: T,
+    pub is_first: bool,
+    pub is_last: bool,
+}
+
+impl<I: Iterator> Iterator for Delimited<I> {
+    type Item = IteratorItem<I::Item>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let value = self.iter.next()?;
+        let is_first = mem::replace(&mut self.is_first, false);
+        let is_last = self.iter.peek().is_none();
+        Some(IteratorItem { value, is_first, is_last })
+    }
+}
+
+impl<T> Deref for IteratorItem<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.value
+    }
+}
index 6a5bba30b8bca8b1ef0a0ad8faf5703d321a8ec3..6435f1b6141e35a66c82211ab67a2b27883ad402 100644 (file)
@@ -1,5 +1,5 @@
-use crate::pp::Breaks::{Consistent, Inconsistent};
-use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+use crate::pp::Breaks::Inconsistent;
+use crate::pprust::state::{AnnNode, IterDelimited, PrintState, State, INDENT_UNIT};
 
 use rustc_ast::ptr::P;
 use rustc_ast::util::parser::{self, AssocOp, Fixity};
@@ -117,38 +117,46 @@ fn print_expr_struct(
         } else {
             self.print_path(path, true, 0);
         }
+        self.nbsp();
         self.word("{");
-        self.commasep_cmnt(
-            Consistent,
-            fields,
-            |s, field| {
-                s.print_outer_attributes(&field.attrs);
-                s.ibox(INDENT_UNIT);
-                if !field.is_shorthand {
-                    s.print_ident(field.ident);
-                    s.word_space(":");
-                }
-                s.print_expr(&field.expr);
-                s.end();
-            },
-            |f| f.span,
-        );
-        match rest {
-            ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
-                self.ibox(INDENT_UNIT);
-                if !fields.is_empty() {
-                    self.word(",");
-                    self.space();
-                }
-                self.word("..");
-                if let ast::StructRest::Base(ref expr) = *rest {
-                    self.print_expr(expr);
-                }
-                self.end();
+        let has_rest = match rest {
+            ast::StructRest::Base(_) | ast::StructRest::Rest(_) => true,
+            ast::StructRest::None => false,
+        };
+        if fields.is_empty() && !has_rest {
+            self.word("}");
+            return;
+        }
+        self.cbox(0);
+        for field in fields.iter().delimited() {
+            self.maybe_print_comment(field.span.hi());
+            self.print_outer_attributes(&field.attrs);
+            if field.is_first {
+                self.space_if_not_bol();
+            }
+            if !field.is_shorthand {
+                self.print_ident(field.ident);
+                self.word_nbsp(":");
+            }
+            self.print_expr(&field.expr);
+            if !field.is_last || has_rest {
+                self.word_space(",");
+            } else {
+                self.trailing_comma_or_space();
             }
-            ast::StructRest::None if !fields.is_empty() => self.word(","),
-            _ => {}
         }
+        if has_rest {
+            if fields.is_empty() {
+                self.space();
+            }
+            self.word("..");
+            if let ast::StructRest::Base(expr) = rest {
+                self.print_expr(expr);
+            }
+            self.space();
+        }
+        self.offset(-INDENT_UNIT);
+        self.end();
         self.word("}");
     }
 
index dac84ae9d5fc87fcbf4fda40a9f247d88e29bd5e..d7e9ef0e50dd864e92700acdaa9d6a1809f0fa77 100644 (file)
@@ -1,5 +1,6 @@
 use crate::pp::Breaks::Inconsistent;
-use crate::pprust::state::{AnnNode, PrintState, State};
+use crate::pprust::state::delimited::IterDelimited;
+use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
 
 use rustc_ast as ast;
 use rustc_ast::GenericBound;
@@ -138,11 +139,10 @@ fn print_associated_type(
                 self.end(); // end outer head-block
             }
             ast::ItemKind::Use(ref tree) => {
-                self.head(visibility_qualified(&item.vis, "use"));
+                self.print_visibility(&item.vis);
+                self.word_nbsp("use");
                 self.print_use_tree(tree);
                 self.word(";");
-                self.end(); // end inner head-block
-                self.end(); // end outer head-block
             }
             ast::ItemKind::Static(ref ty, mutbl, ref body) => {
                 let def = ast::Defaultness::Final;
@@ -615,8 +615,8 @@ fn print_use_tree(&mut self, tree: &ast::UseTree) {
             ast::UseTreeKind::Simple(rename, ..) => {
                 self.print_path(&tree.prefix, false, 0);
                 if let Some(rename) = rename {
-                    self.space();
-                    self.word_space("as");
+                    self.nbsp();
+                    self.word_nbsp("as");
                     self.print_ident(rename);
                 }
             }
@@ -628,16 +628,36 @@ fn print_use_tree(&mut self, tree: &ast::UseTree) {
                 self.word("*");
             }
             ast::UseTreeKind::Nested(ref items) => {
-                if tree.prefix.segments.is_empty() {
-                    self.word("{");
-                } else {
+                if !tree.prefix.segments.is_empty() {
                     self.print_path(&tree.prefix, false, 0);
-                    self.word("::{");
+                    self.word("::");
+                }
+                if items.is_empty() {
+                    self.word("{}");
+                } else if items.len() == 1 {
+                    self.print_use_tree(&items[0].0);
+                } else {
+                    self.cbox(INDENT_UNIT);
+                    self.word("{");
+                    self.zerobreak();
+                    self.ibox(0);
+                    for use_tree in items.iter().delimited() {
+                        self.print_use_tree(&use_tree.0);
+                        if !use_tree.is_last {
+                            self.word(",");
+                            if let ast::UseTreeKind::Nested(_) = use_tree.0.kind {
+                                self.hardbreak();
+                            } else {
+                                self.space();
+                            }
+                        }
+                    }
+                    self.end();
+                    self.trailing_comma();
+                    self.offset(-INDENT_UNIT);
+                    self.word("}");
+                    self.end();
                 }
-                self.commasep(Inconsistent, &items, |this, &(ref tree, _)| {
-                    this.print_use_tree(tree)
-                });
-                self.word("}");
             }
         }
     }
index 8c5beb1025803ec05b2450e6dd72793675866afe..dca7f5dd48769f5a7455dc5ee9f16c763e3714c2 100644 (file)
@@ -604,7 +604,7 @@ pub fn eval_condition(
     }
 }
 
-#[derive(Debug, Encodable, Decodable, Clone, HashStable_Generic)]
+#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
 pub struct Deprecation {
     pub since: Option<Symbol>,
     /// The note to issue a reason.
index 5702203d7c4ffba938aea53c89e71a1dbf7ba9bf..7140cda8e4e51d42e7b9fa5850962f15460a80ea 100644 (file)
@@ -327,7 +327,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         verb: &str,
         optional_adverb_for_moved: &str,
         moved_path: Option<String>,
-    ) -> DiagnosticBuilder<'cx> {
+    ) -> DiagnosticBuilder<'tcx> {
         let moved_path = moved_path.map(|mp| format!(": `{}`", mp)).unwrap_or_default();
 
         struct_span_err!(
index a40f148cdf88c02a32706c7aeac8080a0f53314b..22edee33c5c1b6c978a9f54fb9384ea53821a845 100644 (file)
@@ -60,8 +60,8 @@ fn visit_substs(&mut self, substs: &SubstsRef<'tcx>, location: Location) {
 
     /// We sometimes have `region` within an rvalue, or within a
     /// call. Make them live at the location where they appear.
-    fn visit_region(&mut self, region: &ty::Region<'tcx>, location: Location) {
-        self.add_regular_live_constraint(*region, location);
+    fn visit_region(&mut self, region: ty::Region<'tcx>, location: Location) {
+        self.add_regular_live_constraint(region, location);
         self.super_region(region);
     }
 
index 96326ef2d5a07aa7ad0e07bb4a5d4a594a778c34..2a906e41b8cd5cc2640e99d7c0912affbc7b5066 100644 (file)
@@ -55,7 +55,7 @@ impl<'tcx> UniverseInfo<'tcx> {
                     found,
                     TypeError::RegionsPlaceholderMismatch,
                 );
-                err.buffer(&mut mbcx.errors_buffer);
+                mbcx.buffer_error(err);
             }
             UniverseInfoInner::TypeOp(ref type_op_info) => {
                 type_op_info.report_error(mbcx, placeholder, error_element, cause);
@@ -64,11 +64,9 @@ impl<'tcx> UniverseInfo<'tcx> {
                 // FIXME: This error message isn't great, but it doesn't show
                 // up in the existing UI tests. Consider investigating this
                 // some more.
-                mbcx.infcx
-                    .tcx
-                    .sess
-                    .struct_span_err(cause.span, "higher-ranked subtype error")
-                    .buffer(&mut mbcx.errors_buffer);
+                mbcx.buffer_error(
+                    mbcx.infcx.tcx.sess.struct_span_err(cause.span, "higher-ranked subtype error"),
+                );
             }
         }
     }
@@ -144,12 +142,10 @@ fn report_error(
         let tcx = mbcx.infcx.tcx;
         let base_universe = self.base_universe();
 
-        let adjusted_universe = if let Some(adjusted) =
+        let Some(adjusted_universe) =
             placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
-        {
-            adjusted
-        } else {
-            self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer);
+        else {
+            mbcx.buffer_error(self.fallback_error(tcx, cause.span));
             return;
         };
 
@@ -178,9 +174,9 @@ fn report_error(
         let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
 
         if let Some(nice_error) = nice_error {
-            nice_error.buffer(&mut mbcx.errors_buffer);
+            mbcx.buffer_error(nice_error);
         } else {
-            self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
+            mbcx.buffer_error(self.fallback_error(tcx, span));
         }
     }
 }
@@ -358,8 +354,8 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
     })?;
 
     debug!(?sub_region, "cause = {:#?}", cause);
-    let nice_error = match (error_region, sub_region) {
-        (Some(error_region), &ty::ReVar(vid)) => NiceRegionError::new(
+    let nice_error = match (error_region, *sub_region) {
+        (Some(error_region), ty::ReVar(vid)) => NiceRegionError::new(
             infcx,
             RegionResolutionError::SubSupConflict(
                 vid,
@@ -376,7 +372,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
             RegionResolutionError::ConcreteFailure(cause.clone(), error_region, placeholder_region),
         ),
         // Note universe here is wrong...
-        (None, &ty::ReVar(vid)) => NiceRegionError::new(
+        (None, ty::ReVar(vid)) => NiceRegionError::new(
             infcx,
             RegionResolutionError::UpperBoundUniverseConflict(
                 vid,
index ba111d394ec26bc20dd81ddd1ae4aa2a5f5d200a..fce5ed0ef42390539b10fbdc8d97373ab3269061 100644 (file)
@@ -1,4 +1,5 @@
 use either::Either;
+use rustc_const_eval::util::{CallDesugaringKind, CallKind};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
@@ -26,7 +27,7 @@
 
 use super::{
     explain_borrow::{BorrowExplanation, LaterUseKind},
-    FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
+    IncludingDowncast, RegionName, RegionNameSource, UseSpans,
 };
 
 #[derive(Debug)]
@@ -104,9 +105,9 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                 format!("{} occurs due to use{}", desired_action.as_noun(), use_spans.describe()),
             );
 
-            err.buffer(&mut self.errors_buffer);
+            self.buffer_error(err);
         } else {
-            if let Some((reported_place, _)) = self.move_error_reported.get(&move_out_indices) {
+            if let Some((reported_place, _)) = self.has_move_error(&move_out_indices) {
                 if self.prefixes(*reported_place, PrefixSet::All).any(|p| p == used_place) {
                     debug!(
                         "report_use_of_moved_or_uninitialized place: error suppressed \
@@ -195,7 +196,9 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                         .map(|n| format!("`{}`", n))
                         .unwrap_or_else(|| "value".to_owned());
                     match kind {
-                        FnSelfUseKind::FnOnceCall => {
+                        CallKind::FnCall { fn_trait_id, .. }
+                            if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
+                        {
                             err.span_label(
                                 fn_call_span,
                                 &format!(
@@ -208,7 +211,8 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                                 "this value implements `FnOnce`, which causes it to be moved when called",
                             );
                         }
-                        FnSelfUseKind::Operator { self_arg } => {
+                        CallKind::Operator { self_arg, .. } => {
+                            let self_arg = self_arg.unwrap();
                             err.span_label(
                                 fn_call_span,
                                 &format!(
@@ -235,12 +239,9 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                                 );
                             }
                         }
-                        FnSelfUseKind::Normal {
-                            self_arg,
-                            implicit_into_iter,
-                            is_option_or_result,
-                        } => {
-                            if implicit_into_iter {
+                        CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
+                            let self_arg = self_arg.unwrap();
+                            if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
                                 err.span_label(
                                     fn_call_span,
                                     &format!(
@@ -305,8 +306,8 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                                     );
                             }
                         }
-                        // Deref::deref takes &self, which cannot cause a move
-                        FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
+                        // Other desugarings takes &self, which cannot cause a move
+                        _ => unreachable!(),
                     }
                 } else {
                     err.span_label(
@@ -433,7 +434,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
             }
 
             if let UseSpans::FnSelfUse {
-                kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty },
+                kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. },
                 ..
             } = use_spans
             {
@@ -449,12 +450,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                 }
             }
 
-            if let Some((_, mut old_err)) =
-                self.move_error_reported.insert(move_out_indices, (used_place, err))
-            {
-                // Cancel the old error so it doesn't ICE.
-                old_err.cancel();
-            }
+            self.buffer_move_error(move_out_indices, (used_place, err));
         }
     }
 
@@ -503,7 +499,7 @@ pub(crate) fn report_move_out_while_borrowed(
                 Some(borrow_span),
                 None,
             );
-        err.buffer(&mut self.errors_buffer);
+        self.buffer_error(err);
     }
 
     pub(crate) fn report_use_while_mutably_borrowed(
@@ -1021,7 +1017,7 @@ pub(crate) fn report_borrowed_value_does_not_live_long_enough(
         if self.body.local_decls[borrowed_local].is_ref_to_thread_local() {
             let err =
                 self.report_thread_local_value_does_not_live_long_enough(drop_span, borrow_span);
-            err.buffer(&mut self.errors_buffer);
+            self.buffer_error(err);
             return;
         }
 
@@ -1113,7 +1109,7 @@ pub(crate) fn report_borrowed_value_does_not_live_long_enough(
             ),
         };
 
-        err.buffer(&mut self.errors_buffer);
+        self.buffer_error(err);
     }
 
     fn report_local_value_does_not_live_long_enough(
@@ -1295,7 +1291,7 @@ fn report_borrow_conflicts_with_destructor(
             None,
         );
 
-        err.buffer(&mut self.errors_buffer);
+        self.buffer_error(err);
     }
 
     fn report_thread_local_value_does_not_live_long_enough(
@@ -1810,7 +1806,7 @@ pub(crate) fn report_illegal_mutation_of_borrowed(
                     loan.kind.describe_mutability(),
                 );
 
-                err.buffer(&mut self.errors_buffer);
+                self.buffer_error(err);
 
                 return;
             }
@@ -1836,7 +1832,7 @@ pub(crate) fn report_illegal_mutation_of_borrowed(
 
         self.explain_deref_coercion(loan, &mut err);
 
-        err.buffer(&mut self.errors_buffer);
+        self.buffer_error(err);
     }
 
     fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) {
@@ -1938,7 +1934,7 @@ pub(crate) fn report_illegal_reassignment(
             }
         }
         err.span_label(span, msg);
-        err.buffer(&mut self.errors_buffer);
+        self.buffer_error(err);
     }
 
     fn classify_drop_access_kind(&self, place: PlaceRef<'tcx>) -> StorageDeadOrDrop<'tcx> {
@@ -2328,7 +2324,7 @@ fn annotate_fn_sig(
                 // This is also case 2 from above but for functions, return type is still an
                 // anonymous reference so we select the first argument.
                 let argument_span = fn_decl.inputs.first()?.span;
-                let argument_ty = sig.inputs().skip_binder().first()?;
+                let argument_ty = *sig.inputs().skip_binder().first()?;
 
                 let return_span = fn_decl.output.span();
                 let return_ty = sig.output().skip_binder();
@@ -2383,27 +2379,27 @@ pub(crate) fn emit(
         diag: &mut DiagnosticBuilder<'_>,
     ) -> String {
         match self {
-            AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
+            &AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span } => {
                 diag.span_label(
-                    *argument_span,
+                    argument_span,
                     format!("has type `{}`", cx.get_name_for_ty(argument_ty, 0)),
                 );
 
                 cx.get_region_name_for_ty(argument_ty, 0)
             }
-            AnnotatedBorrowFnSignature::AnonymousFunction {
+            &AnnotatedBorrowFnSignature::AnonymousFunction {
                 argument_ty,
                 argument_span,
                 return_ty,
                 return_span,
             } => {
                 let argument_ty_name = cx.get_name_for_ty(argument_ty, 0);
-                diag.span_label(*argument_span, format!("has type `{}`", argument_ty_name));
+                diag.span_label(argument_span, format!("has type `{}`", argument_ty_name));
 
                 let return_ty_name = cx.get_name_for_ty(return_ty, 0);
                 let types_equal = return_ty_name == argument_ty_name;
                 diag.span_label(
-                    *return_span,
+                    return_span,
                     format!(
                         "{}has type `{}`",
                         if types_equal { "also " } else { "" },
@@ -2423,7 +2419,7 @@ pub(crate) fn emit(
             }
             AnnotatedBorrowFnSignature::NamedFunction { arguments, return_ty, return_span } => {
                 // Region of return type and arguments checked to be the same earlier.
-                let region_name = cx.get_region_name_for_ty(return_ty, 0);
+                let region_name = cx.get_region_name_for_ty(*return_ty, 0);
                 for (_, argument_span) in arguments {
                     diag.span_label(*argument_span, format!("has lifetime `{}`", region_name));
                 }
index 84acfbf941d05ee0298c520c0f9291326c037956..73b0d3982850469470f8dd6eda073a321034adb8 100644 (file)
@@ -1,10 +1,10 @@
 //! Borrow checker diagnostics.
 
+use rustc_const_eval::util::call_kind;
 use rustc_errors::DiagnosticBuilder;
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItemGroup;
 use rustc_hir::GeneratorKind;
 use rustc_middle::mir::{
     AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
@@ -13,7 +13,7 @@
 use rustc_middle::ty::print::Print;
 use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
 use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
-use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
+use rustc_span::{symbol::sym, Span};
 use rustc_target::abi::VariantIdx;
 
 use super::borrow_set::BorrowData;
@@ -37,7 +37,7 @@
 crate use outlives_suggestion::OutlivesSuggestionBuilder;
 crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
 crate use region_name::{RegionName, RegionNameSource};
-use rustc_span::symbol::Ident;
+crate use rustc_const_eval::util::CallKind;
 
 pub(super) struct IncludingDowncast(pub(super) bool);
 
@@ -331,7 +331,7 @@ fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
         match place {
             PlaceRef { local, projection: [] } => {
                 let local = &self.body.local_decls[local];
-                self.describe_field_from_ty(&local.ty, field, None)
+                self.describe_field_from_ty(local.ty, field, None)
             }
             PlaceRef { local, projection: [proj_base @ .., elem] } => match elem {
                 ProjectionElem::Deref => {
@@ -339,10 +339,10 @@ fn describe_field(&self, place: PlaceRef<'tcx>, field: Field) -> String {
                 }
                 ProjectionElem::Downcast(_, variant_index) => {
                     let base_ty = place.ty(self.body, self.infcx.tcx).ty;
-                    self.describe_field_from_ty(&base_ty, field, Some(*variant_index))
+                    self.describe_field_from_ty(base_ty, field, Some(*variant_index))
                 }
                 ProjectionElem::Field(_, field_type) => {
-                    self.describe_field_from_ty(&field_type, field, None)
+                    self.describe_field_from_ty(*field_type, field, None)
                 }
                 ProjectionElem::Index(..)
                 | ProjectionElem::ConstantIndex { .. }
@@ -362,7 +362,7 @@ fn describe_field_from_ty(
     ) -> String {
         if ty.is_box() {
             // If the type is a box, the field is described from the boxed type
-            self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index)
+            self.describe_field_from_ty(ty.boxed_ty(), field, variant_index)
         } else {
             match *ty.kind() {
                 ty::Adt(def, _) => {
@@ -376,10 +376,10 @@ fn describe_field_from_ty(
                 }
                 ty::Tuple(_) => field.index().to_string(),
                 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
-                    self.describe_field_from_ty(&ty, field, variant_index)
+                    self.describe_field_from_ty(ty, field, variant_index)
                 }
                 ty::Array(ty, _) | ty::Slice(ty) => {
-                    self.describe_field_from_ty(&ty, field, variant_index)
+                    self.describe_field_from_ty(ty, field, variant_index)
                 }
                 ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
                     // We won't be borrowck'ing here if the closure came from another crate,
@@ -497,14 +497,14 @@ pub(super) fn get_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> String {
         // We need to add synthesized lifetimes where appropriate. We do
         // this by hooking into the pretty printer and telling it to label the
         // lifetimes without names with the value `'0`.
-        match ty.kind() {
-            ty::Ref(
-                ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
-                | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }),
-                _,
-                _,
-            ) => printer.region_highlight_mode.highlighting_bound_region(*br, counter),
-            _ => {}
+        if let ty::Ref(region, ..) = ty.kind() {
+            match **region {
+                ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
+                | ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
+                    printer.region_highlight_mode.highlighting_bound_region(br, counter)
+                }
+                _ => {}
+            }
         }
 
         let _ = ty.print(printer);
@@ -517,19 +517,17 @@ pub(super) fn get_region_name_for_ty(&self, ty: Ty<'tcx>, counter: usize) -> Str
         let mut s = String::new();
         let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS);
 
-        let region = match ty.kind() {
-            ty::Ref(region, _, _) => {
-                match region {
-                    ty::RegionKind::ReLateBound(_, ty::BoundRegion { kind: br, .. })
-                    | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
-                        printer.region_highlight_mode.highlighting_bound_region(*br, counter)
-                    }
-                    _ => {}
+        let region = if let ty::Ref(region, ..) = ty.kind() {
+            match **region {
+                ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
+                | ty::RePlaceholder(ty::PlaceholderRegion { name: br, .. }) => {
+                    printer.region_highlight_mode.highlighting_bound_region(br, counter)
                 }
-
-                region
+                _ => {}
             }
-            _ => bug!("ty for annotation of borrow region is not a reference"),
+            region
+        } else {
+            bug!("ty for annotation of borrow region is not a reference");
         };
 
         let _ = region.print(printer);
@@ -563,7 +561,7 @@ pub(super) enum UseSpans<'tcx> {
         fn_call_span: Span,
         /// The definition span of the method being called
         fn_span: Span,
-        kind: FnSelfUseKind<'tcx>,
+        kind: CallKind<'tcx>,
     },
     /// This access is caused by a `match` or `if let` pattern.
     PatUse(Span),
@@ -571,38 +569,15 @@ pub(super) enum UseSpans<'tcx> {
     OtherUse(Span),
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub(super) enum FnSelfUseKind<'tcx> {
-    /// A normal method call of the form `receiver.foo(a, b, c)`
-    Normal {
-        self_arg: Ident,
-        implicit_into_iter: bool,
-        /// Whether the self type of the method call has an `.as_ref()` method.
-        /// Used for better diagnostics.
-        is_option_or_result: bool,
-    },
-    /// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
-    FnOnceCall,
-    /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
-    Operator { self_arg: Ident },
-    DerefCoercion {
-        /// The `Span` of the `Target` associated type
-        /// in the `Deref` impl we are using.
-        deref_target: Span,
-        /// The type `T::Deref` we are dereferencing to
-        deref_target_ty: Ty<'tcx>,
-    },
-}
-
 impl UseSpans<'_> {
     pub(super) fn args_or_use(self) -> Span {
         match self {
             UseSpans::ClosureUse { args_span: span, .. }
             | UseSpans::PatUse(span)
             | UseSpans::OtherUse(span) => span,
-            UseSpans::FnSelfUse {
-                fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
-            } => fn_call_span,
+            UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
+                fn_call_span
+            }
             UseSpans::FnSelfUse { var_span, .. } => var_span,
         }
     }
@@ -613,9 +588,9 @@ pub(super) fn var_or_use_path_span(self) -> Span {
             UseSpans::ClosureUse { path_span: span, .. }
             | UseSpans::PatUse(span)
             | UseSpans::OtherUse(span) => span,
-            UseSpans::FnSelfUse {
-                fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
-            } => fn_call_span,
+            UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
+                fn_call_span
+            }
             UseSpans::FnSelfUse { var_span, .. } => var_span,
         }
     }
@@ -626,9 +601,9 @@ pub(super) fn var_or_use(self) -> Span {
             UseSpans::ClosureUse { capture_kind_span: span, .. }
             | UseSpans::PatUse(span)
             | UseSpans::OtherUse(span) => span,
-            UseSpans::FnSelfUse {
-                fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
-            } => fn_call_span,
+            UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
+                fn_call_span
+            }
             UseSpans::FnSelfUse { var_span, .. } => var_span,
         }
     }
@@ -892,79 +867,30 @@ pub(super) fn move_spans(
             kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, ..
         }) = &self.body[location.block].terminator
         {
-            let (method_did, method_substs) = if let Some(info) =
+            let Some((method_did, method_substs)) =
                 rustc_const_eval::util::find_self_call(
                     self.infcx.tcx,
                     &self.body,
                     target_temp,
                     location.block,
-                ) {
-                info
-            } else {
+                )
+            else {
                 return normal_ret;
             };
 
-            let tcx = self.infcx.tcx;
-            let parent = tcx.parent(method_did);
-            let is_fn_once = parent == tcx.lang_items().fn_once_trait();
-            let is_operator = !from_hir_call
-                && parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
-            let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
-            let fn_call_span = *fn_span;
-
-            let self_arg = tcx.fn_arg_names(method_did)[0];
-
-            debug!(
-                "terminator = {:?} from_hir_call={:?}",
-                self.body[location.block].terminator, from_hir_call
+            let kind = call_kind(
+                self.infcx.tcx,
+                self.param_env,
+                method_did,
+                method_substs,
+                *fn_span,
+                *from_hir_call,
+                Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
             );
 
-            // Check for a 'special' use of 'self' -
-            // an FnOnce call, an operator (e.g. `<<`), or a
-            // deref coercion.
-            let kind = if is_fn_once {
-                Some(FnSelfUseKind::FnOnceCall)
-            } else if is_operator {
-                Some(FnSelfUseKind::Operator { self_arg })
-            } else if is_deref {
-                let deref_target =
-                    tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
-                        Instance::resolve(tcx, self.param_env, deref_target, method_substs)
-                            .transpose()
-                    });
-                if let Some(Ok(instance)) = deref_target {
-                    let deref_target_ty = instance.ty(tcx, self.param_env);
-                    Some(FnSelfUseKind::DerefCoercion {
-                        deref_target: tcx.def_span(instance.def_id()),
-                        deref_target_ty,
-                    })
-                } else {
-                    None
-                }
-            } else {
-                None
-            };
-
-            let kind = kind.unwrap_or_else(|| {
-                // This isn't a 'special' use of `self`
-                debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
-                let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
-                    && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
-                let parent_self_ty = parent
-                    .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
-                    .and_then(|did| match tcx.type_of(did).kind() {
-                        ty::Adt(def, ..) => Some(def.did),
-                        _ => None,
-                    });
-                let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
-                    matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
-                });
-                FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
-            });
-
             return FnSelfUse {
                 var_span: stmt.source_info.span,
-                fn_call_span,
+                fn_call_span: *fn_span,
                 fn_span: self
                     .infcx
                     .tcx
index 692c20d7dfe34ebed24443a863b7966d356528c7..cc6566882ad5d800e21098dec46b597e1fb2fa8d 100644 (file)
@@ -1,3 +1,4 @@
+use rustc_const_eval::util::CallDesugaringKind;
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::mir::*;
@@ -8,7 +9,7 @@
 use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
 
-use crate::diagnostics::{FnSelfUseKind, UseSpans};
+use crate::diagnostics::{CallKind, UseSpans};
 use crate::prefixes::PrefixSet;
 use crate::MirBorrowckCtxt;
 
@@ -245,18 +246,18 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
             );
             (
                 match kind {
-                    IllegalMoveOriginKind::BorrowedContent { target_place } => self
+                    &IllegalMoveOriginKind::BorrowedContent { target_place } => self
                         .report_cannot_move_from_borrowed_content(
                             original_path,
-                            *target_place,
+                            target_place,
                             span,
                             use_spans,
                         ),
-                    IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
+                    &IllegalMoveOriginKind::InteriorOfTypeWithDestructor { container_ty: ty } => {
                         self.cannot_move_out_of_interior_of_drop(span, ty)
                     }
-                    IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
-                        self.cannot_move_out_of_interior_noncopy(span, ty, Some(*is_index))
+                    &IllegalMoveOriginKind::InteriorOfSliceOrArray { ty, is_index } => {
+                        self.cannot_move_out_of_interior_noncopy(span, ty, Some(is_index))
                     }
                 },
                 span,
@@ -264,7 +265,7 @@ fn report(&mut self, error: GroupedMoveError<'tcx>) {
         };
 
         self.add_move_hints(error, &mut err, err_span);
-        err.buffer(&mut self.errors_buffer);
+        self.buffer_error(err);
     }
 
     fn report_cannot_move_from_static(
@@ -410,7 +411,8 @@ fn report_cannot_move_from_borrowed_content(
                 Applicability::MaybeIncorrect,
             );
         } else if let Some(UseSpans::FnSelfUse {
-            kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. },
+            kind:
+                CallKind::Normal { desugaring: Some((CallDesugaringKind::ForLoopIntoIter, _)), .. },
             ..
         }) = use_spans
         {
index 049c3aab97933a6bcc2b8c7eb4b58c056a904f0a..7d0dde53c2b6d5481c2ef0f352f88a2938b407c7 100644 (file)
@@ -626,7 +626,7 @@ pub(crate) fn report_mutability_error(
             }
         }
 
-        err.buffer(&mut self.errors_buffer);
+        self.buffer_error(err);
     }
 
     /// User cannot make signature of a trait mutable without changing the
@@ -639,11 +639,9 @@ fn is_error_in_trait(&self, local: Local) -> (bool, Option<Span>) {
         let hir_map = self.infcx.tcx.hir();
         let my_def = self.body.source.def_id();
         let my_hir = hir_map.local_def_id_to_hir_id(my_def.as_local().unwrap());
-        let td = if let Some(a) =
+        let Some(td) =
             self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x))
-        {
-            a
-        } else {
+        else {
             return (false, None);
         };
         (
@@ -763,7 +761,7 @@ fn suggest_similar_mut_method_for_for_loop(&self, err: &mut DiagnosticBuilder<'_
             HirId, ImplItem, ImplItemKind, Item, ItemKind,
         };
 
-        fn maybe_body_id_of_fn(hir_map: &Map<'_>, id: HirId) -> Option<BodyId> {
+        fn maybe_body_id_of_fn(hir_map: Map<'_>, id: HirId) -> Option<BodyId> {
             match hir_map.find(id) {
                 Some(Node::Item(Item { kind: ItemKind::Fn(_, _, body_id), .. }))
                 | Some(Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })) => {
@@ -774,7 +772,7 @@ fn maybe_body_id_of_fn(hir_map: &Map<'_>, id: HirId) -> Option<BodyId> {
         }
         let hir_map = self.infcx.tcx.hir();
         let mir_body_hir_id = self.mir_hir_id();
-        if let Some(fn_body_id) = maybe_body_id_of_fn(&hir_map, mir_body_hir_id) {
+        if let Some(fn_body_id) = maybe_body_id_of_fn(hir_map, mir_body_hir_id) {
             if let Block(
                 hir::Block {
                     expr:
index 723b57ed970ad6bb16bac57787f39029e9ea4f4f..21f00af5c0cef1bd3efecde471d2fbd20fc23a4b 100644 (file)
@@ -256,6 +256,6 @@ fn compile_all_suggestions(
         diag.sort_span = mir_span.shrink_to_hi();
 
         // Buffer the diagnostic
-        diag.buffer(&mut mbcx.errors_buffer);
+        mbcx.buffer_error(diag);
     }
 }
index df23eaf24bc6da8136d53abf83f04f078ba1d49b..ca1e77ff8fdc05a8e003d26044a78062a25ce69c 100644 (file)
@@ -139,7 +139,7 @@ pub(super) fn to_error_region_vid(&self, r: RegionVid) -> Option<RegionVid> {
 
     /// Returns `true` if a closure is inferred to be an `FnMut` closure.
     fn is_closure_fn_mut(&self, fr: RegionVid) -> bool {
-        if let Some(ty::ReFree(free_region)) = self.to_error_region(fr) {
+        if let Some(ty::ReFree(free_region)) = self.to_error_region(fr).as_deref() {
             if let ty::BoundRegionKind::BrEnv = free_region.bound_region {
                 if let DefiningTy::Closure(_, substs) =
                     self.regioncx.universal_regions().defining_ty
@@ -168,14 +168,12 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
                     let type_test_span = type_test.locations.span(&self.body);
 
                     if let Some(lower_bound_region) = lower_bound_region {
-                        self.infcx
-                            .construct_generic_bound_failure(
-                                type_test_span,
-                                None,
-                                type_test.generic_kind,
-                                lower_bound_region,
-                            )
-                            .buffer(&mut self.errors_buffer);
+                        self.buffer_error(self.infcx.construct_generic_bound_failure(
+                            type_test_span,
+                            None,
+                            type_test.generic_kind,
+                            lower_bound_region,
+                        ));
                     } else {
                         // FIXME. We should handle this case better. It
                         // indicates that we have e.g., some region variable
@@ -186,27 +184,22 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
                         // to report it; we could probably handle it by
                         // iterating over the universal regions and reporting
                         // an error that multiple bounds are required.
-                        self.infcx
-                            .tcx
-                            .sess
-                            .struct_span_err(
-                                type_test_span,
-                                &format!("`{}` does not live long enough", type_test.generic_kind),
-                            )
-                            .buffer(&mut self.errors_buffer);
+                        self.buffer_error(self.infcx.tcx.sess.struct_span_err(
+                            type_test_span,
+                            &format!("`{}` does not live long enough", type_test.generic_kind),
+                        ));
                     }
                 }
 
                 RegionErrorKind::UnexpectedHiddenRegion { span, hidden_ty, member_region } => {
                     let named_ty = self.regioncx.name_regions(self.infcx.tcx, hidden_ty);
                     let named_region = self.regioncx.name_regions(self.infcx.tcx, member_region);
-                    unexpected_hidden_region_diagnostic(
+                    self.buffer_error(unexpected_hidden_region_diagnostic(
                         self.infcx.tcx,
                         span,
                         named_ty,
                         named_region,
-                    )
-                    .buffer(&mut self.errors_buffer);
+                    ));
                 }
 
                 RegionErrorKind::BoundUniversalRegionError {
@@ -285,7 +278,7 @@ pub(crate) fn report_region_error(
         if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
             let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
             if let Some(diag) = nice.try_report_from_nll() {
-                diag.buffer(&mut self.errors_buffer);
+                self.buffer_error(diag);
                 return;
             }
         }
@@ -375,7 +368,7 @@ pub(crate) fn report_region_error(
             }
         }
 
-        diag.buffer(&mut self.errors_buffer);
+        self.buffer_error(diag);
     }
 
     /// Report a specialized error when `FnMut` closures return a reference to a captured variable.
@@ -635,8 +628,8 @@ fn add_static_impl_trait_suggestion(
         fr_name: RegionName,
         outlived_fr: RegionVid,
     ) {
-        if let (Some(f), Some(ty::RegionKind::ReStatic)) =
-            (self.to_error_region(fr), self.to_error_region(outlived_fr))
+        if let (Some(f), Some(ty::ReStatic)) =
+            (self.to_error_region(fr), self.to_error_region(outlived_fr).as_deref())
         {
             if let Some(&ty::Opaque(did, substs)) = self
                 .infcx
@@ -659,7 +652,7 @@ fn add_static_impl_trait_suggestion(
                             bound.kind().skip_binder()
                         {
                             let r = r.subst(self.infcx.tcx, substs);
-                            if let ty::RegionKind::ReStatic = r {
+                            if r.is_static() {
                                 found = true;
                                 break;
                             } else {
index 3409f14c98b733b3054b4b92465e31908c7382b4..3bcc9f7be384fd19772af99ffebe2750d0c11452 100644 (file)
@@ -264,7 +264,7 @@ fn give_name_from_error_region(&self, fr: RegionVid) -> Option<RegionName> {
         let tcx = self.infcx.tcx;
 
         debug!("give_region_a_name: error_region = {:?}", error_region);
-        match error_region {
+        match *error_region {
             ty::ReEarlyBound(ebr) => {
                 if ebr.has_name() {
                     let span = tcx.hir().span_if_local(ebr.def_id).unwrap_or(DUMMY_SP);
@@ -433,7 +433,7 @@ fn highlight_if_we_cannot_match_hir_ty(
         span: Span,
         counter: usize,
     ) -> RegionNameHighlight {
-        let mut highlight = RegionHighlightMode::default();
+        let mut highlight = RegionHighlightMode::new(self.infcx.tcx);
         highlight.highlighting_region_vid(needle_fr, counter);
         let type_name =
             self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name;
@@ -500,7 +500,7 @@ fn highlight_if_we_can_match_hir_ty(
                     }
 
                     // Otherwise, let's descend into the referent types.
-                    search_stack.push((referent_ty, &referent_hir_ty.ty));
+                    search_stack.push((*referent_ty, &referent_hir_ty.ty));
                 }
 
                 // Match up something like `Foo<'1>`
@@ -539,7 +539,7 @@ fn highlight_if_we_can_match_hir_ty(
 
                 (ty::Slice(elem_ty), hir::TyKind::Slice(elem_hir_ty))
                 | (ty::Array(elem_ty, _), hir::TyKind::Array(elem_hir_ty, _)) => {
-                    search_stack.push((elem_ty, elem_hir_ty));
+                    search_stack.push((*elem_ty, elem_hir_ty));
                 }
 
                 (ty::RawPtr(mut_ty), hir::TyKind::Ptr(mut_hir_ty)) => {
@@ -818,7 +818,7 @@ fn give_name_if_anonymous_region_appears_in_yield_ty(
             return None;
         }
 
-        let mut highlight = RegionHighlightMode::default();
+        let mut highlight = RegionHighlightMode::new(tcx);
         highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap());
         let type_name =
             self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name;
index 5597a8b091554769adc7dd0f07be095b02ea8739..459b03b0fad65017746ed5c33738f6cf5aa5b335 100644 (file)
@@ -175,10 +175,13 @@ fn do_mir_borrowck<'a, 'tcx>(
         }
     }
 
+    let mut errors = error::BorrowckErrors::new();
+
     // Gather the upvars of a closure, if any.
     let tables = tcx.typeck_opt_const_arg(def);
     if let Some(ErrorReported) = tables.tainted_by_errors {
         infcx.set_tainted_by_errors();
+        errors.set_tainted_by_errors();
     }
     let upvars: Vec<_> = tables
         .closure_min_captures_flattened(def.did.to_def_id())
@@ -205,7 +208,6 @@ fn do_mir_borrowck<'a, 'tcx>(
     let location_table_owned = LocationTable::new(body);
     let location_table = &location_table_owned;
 
-    let mut errors_buffer = Vec::new();
     let (move_data, move_errors): (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>) =
         match MoveData::gather_moves(&body, tcx, param_env) {
             Ok(move_data) => (move_data, Vec::new()),
@@ -263,7 +265,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         &regioncx,
         &opt_closure_req,
         &opaque_type_values,
-        &mut errors_buffer,
+        &mut errors,
     );
 
     // The various `flow_*` structures can be large. We drop `flow_inits` here
@@ -310,9 +312,7 @@ fn do_mir_borrowck<'a, 'tcx>(
                 access_place_error_reported: Default::default(),
                 reservation_error_reported: Default::default(),
                 reservation_warnings: Default::default(),
-                move_error_reported: BTreeMap::new(),
                 uninitialized_error_reported: Default::default(),
-                errors_buffer,
                 regioncx: regioncx.clone(),
                 used_mut: Default::default(),
                 used_mut_upvars: SmallVec::new(),
@@ -323,9 +323,10 @@ fn do_mir_borrowck<'a, 'tcx>(
                 region_names: RefCell::default(),
                 next_region_name: RefCell::new(1),
                 polonius_output: None,
+                errors,
             };
             promoted_mbcx.report_move_errors(move_errors);
-            errors_buffer = promoted_mbcx.errors_buffer;
+            errors = promoted_mbcx.errors;
         };
     }
 
@@ -343,9 +344,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         access_place_error_reported: Default::default(),
         reservation_error_reported: Default::default(),
         reservation_warnings: Default::default(),
-        move_error_reported: BTreeMap::new(),
         uninitialized_error_reported: Default::default(),
-        errors_buffer,
         regioncx: Rc::clone(&regioncx),
         used_mut: Default::default(),
         used_mut_upvars: SmallVec::new(),
@@ -356,6 +355,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         region_names: RefCell::default(),
         next_region_name: RefCell::new(1),
         polonius_output,
+        errors,
     };
 
     // Compute and report region errors, if any.
@@ -398,7 +398,7 @@ fn do_mir_borrowck<'a, 'tcx>(
                 diag.message = initial_diag.styled_message().clone();
                 diag.span = initial_diag.span.clone();
 
-                diag.buffer(&mut mbcx.errors_buffer);
+                mbcx.buffer_error(diag);
             },
         );
         initial_diag.cancel();
@@ -423,7 +423,7 @@ fn do_mir_borrowck<'a, 'tcx>(
     mbcx.gather_used_muts(temporary_used_locals, unused_mut_locals);
 
     debug!("mbcx.used_mut: {:?}", mbcx.used_mut);
-    let used_mut = mbcx.used_mut;
+    let used_mut = std::mem::take(&mut mbcx.used_mut);
     for local in mbcx.body.mut_vars_and_args_iter().filter(|local| !used_mut.contains(local)) {
         let local_decl = &mbcx.body.local_decls[local];
         let lint_root = match &mbcx.body.source_scopes[local_decl.source_info.scope].local_data {
@@ -460,23 +460,13 @@ fn do_mir_borrowck<'a, 'tcx>(
         })
     }
 
-    // Buffer any move errors that we collected and de-duplicated.
-    for (_, (_, diag)) in mbcx.move_error_reported {
-        diag.buffer(&mut mbcx.errors_buffer);
-    }
-
-    if !mbcx.errors_buffer.is_empty() {
-        mbcx.errors_buffer.sort_by_key(|diag| diag.sort_span);
-
-        for diag in mbcx.errors_buffer.drain(..) {
-            mbcx.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag);
-        }
-    }
+    let tainted_by_errors = mbcx.emit_errors();
 
     let result = BorrowCheckResult {
         concrete_opaque_types: opaque_type_values,
         closure_requirements: opt_closure_req,
         used_mut_upvars: mbcx.used_mut_upvars,
+        tainted_by_errors,
     };
 
     let body_with_facts = if return_body_with_facts {
@@ -553,26 +543,9 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
     /// for the activation of the borrow.
     reservation_warnings:
         FxHashMap<BorrowIndex, (Place<'tcx>, Span, Location, BorrowKind, BorrowData<'tcx>)>,
-    /// This field keeps track of move errors that are to be reported for given move indices.
-    ///
-    /// There are situations where many errors can be reported for a single move out (see #53807)
-    /// and we want only the best of those errors.
-    ///
-    /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
-    /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
-    /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
-    /// all move errors have been reported, any diagnostics in this map are added to the buffer
-    /// to be emitted.
-    ///
-    /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
-    /// when errors in the map are being re-added to the error buffer so that errors with the
-    /// same primary span come out in a consistent order.
-    move_error_reported: BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'cx>)>,
     /// This field keeps track of errors reported in the checking of uninitialized variables,
     /// so that we don't report seemingly duplicate errors.
     uninitialized_error_reported: FxHashSet<PlaceRef<'tcx>>,
-    /// Errors to be reported buffer
-    errors_buffer: Vec<Diagnostic>,
     /// This field keeps track of all the local variables that are declared mut and are mutated.
     /// Used for the warning issued by an unused mutable local variable.
     used_mut: FxHashSet<Local>,
@@ -604,6 +577,8 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
 
     /// Results of Polonius analysis.
     polonius_output: Option<Rc<PoloniusOutput>>,
+
+    errors: error::BorrowckErrors<'tcx>,
 }
 
 // Check that:
@@ -1027,7 +1002,6 @@ fn access_place(
 
         if conflict_error || mutability_error {
             debug!("access_place: logging error place_span=`{:?}` kind=`{:?}`", place_span, kind);
-
             self.access_place_error_reported.insert((place_span.0, place_span.1));
         }
     }
@@ -1107,12 +1081,14 @@ fn check_access_for_conflict(
                     error_reported = true;
                     match kind {
                         ReadKind::Copy => {
-                            this.report_use_while_mutably_borrowed(location, place_span, borrow)
-                                .buffer(&mut this.errors_buffer);
+                            let err = this
+                                .report_use_while_mutably_borrowed(location, place_span, borrow);
+                            this.buffer_error(err);
                         }
                         ReadKind::Borrow(bk) => {
-                            this.report_conflicting_borrow(location, place_span, bk, borrow)
-                                .buffer(&mut this.errors_buffer);
+                            let err =
+                                this.report_conflicting_borrow(location, place_span, bk, borrow);
+                            this.buffer_error(err);
                         }
                     }
                     Control::Break
@@ -1162,8 +1138,9 @@ fn check_access_for_conflict(
                     error_reported = true;
                     match kind {
                         WriteKind::MutableBorrow(bk) => {
-                            this.report_conflicting_borrow(location, place_span, bk, borrow)
-                                .buffer(&mut this.errors_buffer);
+                            let err =
+                                this.report_conflicting_borrow(location, place_span, bk, borrow);
+                            this.buffer_error(err);
                         }
                         WriteKind::StorageDeadOrDrop => this
                             .report_borrowed_value_does_not_live_long_enough(
@@ -1570,7 +1547,7 @@ fn check_for_local_borrow(&mut self, borrow: &BorrowData<'tcx>, yield_span: Span
                 yield_span,
             );
 
-            err.buffer(&mut self.errors_buffer);
+            self.buffer_error(err);
         }
     }
 
@@ -2046,10 +2023,9 @@ fn check_access_permissions(
                 | WriteKind::MutableBorrow(BorrowKind::Shared)
                 | WriteKind::MutableBorrow(BorrowKind::Shallow),
             ) => {
-                if let (Err(_), true) = (
-                    self.is_mutable(place.as_ref(), is_local_mutation_allowed),
-                    self.errors_buffer.is_empty(),
-                ) {
+                if self.is_mutable(place.as_ref(), is_local_mutation_allowed).is_err()
+                    && !self.has_buffered_errors()
+                {
                     // rust-lang/rust#46908: In pure NLL mode this code path should be
                     // unreachable, but we use `delay_span_bug` because we can hit this when
                     // dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug`
@@ -2301,6 +2277,103 @@ fn is_upvar_field_projection(&self, place_ref: PlaceRef<'tcx>) -> Option<Field>
     }
 }
 
+mod error {
+    use super::*;
+
+    pub struct BorrowckErrors<'tcx> {
+        /// This field keeps track of move errors that are to be reported for given move indices.
+        ///
+        /// There are situations where many errors can be reported for a single move out (see #53807)
+        /// and we want only the best of those errors.
+        ///
+        /// The `report_use_of_moved_or_uninitialized` function checks this map and replaces the
+        /// diagnostic (if there is one) if the `Place` of the error being reported is a prefix of the
+        /// `Place` of the previous most diagnostic. This happens instead of buffering the error. Once
+        /// all move errors have been reported, any diagnostics in this map are added to the buffer
+        /// to be emitted.
+        ///
+        /// `BTreeMap` is used to preserve the order of insertions when iterating. This is necessary
+        /// when errors in the map are being re-added to the error buffer so that errors with the
+        /// same primary span come out in a consistent order.
+        buffered_move_errors:
+            BTreeMap<Vec<MoveOutIndex>, (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>)>,
+        /// Errors to be reported buffer
+        buffered: Vec<Diagnostic>,
+        /// Set to Some if we emit an error during borrowck
+        tainted_by_errors: Option<ErrorReported>,
+    }
+
+    impl BorrowckErrors<'_> {
+        pub fn new() -> Self {
+            BorrowckErrors {
+                buffered_move_errors: BTreeMap::new(),
+                buffered: Default::default(),
+                tainted_by_errors: None,
+            }
+        }
+
+        pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
+            self.tainted_by_errors = Some(ErrorReported {});
+            t.buffer(&mut self.buffered);
+        }
+
+        pub fn set_tainted_by_errors(&mut self) {
+            self.tainted_by_errors = Some(ErrorReported {});
+        }
+    }
+
+    impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
+        pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
+            self.errors.buffer_error(t);
+        }
+
+        pub fn buffer_move_error(
+            &mut self,
+            move_out_indices: Vec<MoveOutIndex>,
+            place_and_err: (PlaceRef<'tcx>, DiagnosticBuilder<'tcx>),
+        ) -> bool {
+            if let Some((_, mut diag)) =
+                self.errors.buffered_move_errors.insert(move_out_indices, place_and_err)
+            {
+                // Cancel the old diagnostic so we don't ICE
+                diag.cancel();
+                false
+            } else {
+                true
+            }
+        }
+
+        pub fn emit_errors(&mut self) -> Option<ErrorReported> {
+            // 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);
+            }
+
+            if !self.errors.buffered.is_empty() {
+                self.errors.buffered.sort_by_key(|diag| diag.sort_span);
+
+                for diag in self.errors.buffered.drain(..) {
+                    self.infcx.tcx.sess.diagnostic().emit_diagnostic(&diag);
+                }
+            }
+
+            self.errors.tainted_by_errors
+        }
+
+        pub fn has_buffered_errors(&self) -> bool {
+            self.errors.buffered.is_empty()
+        }
+
+        pub fn has_move_error(
+            &self,
+            move_out_indices: &[MoveOutIndex],
+        ) -> Option<&(PlaceRef<'tcx>, DiagnosticBuilder<'cx>)> {
+            self.errors.buffered_move_errors.get(move_out_indices)
+        }
+    }
+}
+
 /// The degree of overlap between 2 places for borrow-checking.
 enum Overlap {
     /// The places might partially overlap - in this case, we give
index 6ffab16577908fcbc747a0a4ff2d5b72620628fb..a16bdf286738c8929ee77c5761327b3142214bf9 100644 (file)
@@ -1,7 +1,6 @@
 //! The entry point of the NLL borrow checker.
 
 use rustc_data_structures::vec_map::VecMap;
-use rustc_errors::Diagnostic;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
@@ -9,7 +8,7 @@
     BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
     Promoted,
 };
-use rustc_middle::ty::{self, OpaqueTypeKey, RegionKind, RegionVid, Ty};
+use rustc_middle::ty::{self, OpaqueTypeKey, Region, RegionVid, Ty};
 use rustc_span::symbol::sym;
 use std::env;
 use std::fmt::Debug;
@@ -373,7 +372,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
     regioncx: &RegionInferenceContext<'tcx>,
     closure_region_requirements: &Option<ClosureRegionRequirements<'_>>,
     opaque_type_values: &VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
-    errors_buffer: &mut Vec<Diagnostic>,
+    errors: &mut crate::error::BorrowckErrors<'tcx>,
 ) {
     let tcx = infcx.tcx;
     let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
@@ -418,7 +417,7 @@ pub(super) fn dump_annotation<'a, 'tcx>(
         err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values));
     }
 
-    err.buffer(errors_buffer);
+    errors.buffer_error(err);
 }
 
 fn for_each_region_constraint(
@@ -444,9 +443,9 @@ pub trait ToRegionVid {
     fn to_region_vid(self) -> RegionVid;
 }
 
-impl<'tcx> ToRegionVid for &'tcx RegionKind {
+impl<'tcx> ToRegionVid for Region<'tcx> {
     fn to_region_vid(self) -> RegionVid {
-        if let ty::ReVar(vid) = self { *vid } else { bug!("region is not an ReVar: {:?}", self) }
+        if let ty::ReVar(vid) = *self { vid } else { bug!("region is not an ReVar: {:?}", self) }
     }
 }
 
index d9120ff245735084f3d9dc2ca4050090d0287e05..abd6a15334c90e6a6388ca34513d1778240ca78f 100644 (file)
@@ -1169,7 +1169,7 @@ fn eval_verify_bound(
 
         match verify_bound {
             VerifyBound::IfEq(test_ty, verify_bound1) => {
-                self.eval_if_eq(tcx, body, generic_ty, lower_bound, test_ty, verify_bound1)
+                self.eval_if_eq(tcx, body, generic_ty, lower_bound, *test_ty, verify_bound1)
             }
 
             VerifyBound::IsEmpty => {
@@ -1178,7 +1178,7 @@ fn eval_verify_bound(
             }
 
             VerifyBound::OutlivedBy(r) => {
-                let r_vid = self.to_region_vid(r);
+                let r_vid = self.to_region_vid(*r);
                 self.eval_outlives(r_vid, lower_bound)
             }
 
index 76b3be7976c61e9b8def72466f0d6a39f95f8cfb..60c48d8a7648ec65dc29b9bc9c521bb28fac327a 100644 (file)
@@ -133,7 +133,7 @@ pub(crate) fn name_regions<T>(&self, tcx: TyCtxt<'tcx>, ty: T) -> T
                         for vid in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
                             match self.definitions[vid].external_name {
                                 None => {}
-                                Some(&ty::ReStatic) => {}
+                                Some(region) if region.is_static() => {}
                                 Some(region) => return region,
                             }
                         }
@@ -183,7 +183,7 @@ fn check_opaque_type_parameter_valid(
     for (i, arg) in opaque_type_key.substs.iter().enumerate() {
         let arg_is_param = match arg.unpack() {
             GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
-            GenericArgKind::Lifetime(ty::ReStatic) => {
+            GenericArgKind::Lifetime(lt) if lt.is_static() => {
                 tcx.sess
                     .struct_span_err(span, "non-defining opaque type use in defining scope")
                     .span_label(
@@ -196,9 +196,9 @@ fn check_opaque_type_parameter_valid(
                 return false;
             }
             GenericArgKind::Lifetime(lt) => {
-                matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_))
+                matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
             }
-            GenericArgKind::Const(ct) => matches!(ct.val, ty::ConstKind::Param(_)),
+            GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)),
         };
 
         if arg_is_param {
index 4b6cab24cdb70457537d01f21608a3cacea06e68..2876d60527fe7714feacb811f933b9321f7ea16f 100644 (file)
@@ -57,7 +57,7 @@ fn tcx(&self) -> TyCtxt<'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     fn visit_ty(&mut self, ty: &mut Ty<'tcx>, ty_context: TyContext) {
-        *ty = self.renumber_regions(ty);
+        *ty = self.renumber_regions(*ty);
 
         debug!(?ty);
     }
@@ -72,12 +72,12 @@ fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, location: Location) {
     #[instrument(skip(self), level = "debug")]
     fn visit_region(&mut self, region: &mut ty::Region<'tcx>, location: Location) {
         let old_region = *region;
-        *region = self.renumber_regions(&old_region);
+        *region = self.renumber_regions(old_region);
 
         debug!(?region);
     }
 
-    fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _location: Location) {
-        *constant = self.renumber_regions(&*constant);
+    fn visit_const(&mut self, constant: &mut ty::Const<'tcx>, _location: Location) {
+        *constant = self.renumber_regions(*constant);
     }
 }
index a3b39591f8db261891835ea878a1dfc8a5445560..5022cb98b821d0786565e1a81cbc76e60d0f6396 100644 (file)
@@ -105,8 +105,8 @@ pub(super) fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx
                 // create new region variables, which can't be done later when
                 // verifying these bounds.
                 if t1.has_placeholders() {
-                    t1 = tcx.fold_regions(&t1, &mut false, |r, _| match *r {
-                        ty::RegionKind::RePlaceholder(placeholder) => {
+                    t1 = tcx.fold_regions(t1, &mut false, |r, _| match *r {
+                        ty::RePlaceholder(placeholder) => {
                             self.constraints.placeholder_region(self.infcx, placeholder)
                         }
                         _ => r,
@@ -142,8 +142,8 @@ fn verify_to_type_test(
     }
 
     fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
-        if let ty::RePlaceholder(placeholder) = r {
-            self.constraints.placeholder_region(self.infcx, *placeholder).to_region_vid()
+        if let ty::RePlaceholder(placeholder) = *r {
+            self.constraints.placeholder_region(self.infcx, placeholder).to_region_vid()
         } else {
             self.universal_regions.to_region_vid(r)
         }
index fec6bdf314b1d6c848748af6c511bba32fb9d842..9a028147a4b60a2db2648e3fb91e223bc26d4bbb 100644 (file)
@@ -358,7 +358,7 @@ fn add_outlives_bounds<I>(&mut self, outlives_bounds: I)
                     // `where Type:` is lowered to `where Type: 'empty` so that
                     // we check `Type` is well formed, but there's no use for
                     // this bound here.
-                    if let ty::ReEmpty(_) = r1 {
+                    if r1.is_empty() {
                         return;
                     }
 
index 73103643e3e16f2253edb83e036f440c25aa8930..46924f50d2e1ba50f7696db2796d1082e45896ee 100644 (file)
@@ -383,7 +383,7 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
         } else {
             let tcx = self.tcx();
             let maybe_uneval = match constant.literal {
-                ConstantKind::Ty(ct) => match ct.val {
+                ConstantKind::Ty(ct) => match ct.val() {
                     ty::ConstKind::Unevaluated(uv) => Some(uv),
                     _ => None,
                 },
@@ -482,7 +482,7 @@ fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
                     // then remove the outermost reference so we can check the
                     // type annotation for the remaining type.
                     if let ty::Ref(_, rty, _) = local_decl.ty.kind() {
-                        rty
+                        *rty
                     } else {
                         bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty);
                     }
@@ -716,7 +716,7 @@ fn sanitize_projection(
                 PlaceTy::from_ty(match base_ty.kind() {
                     ty::Array(inner, _) => {
                         assert!(!from_end, "array subslices should not use from_end");
-                        tcx.mk_array(inner, to - from)
+                        tcx.mk_array(*inner, to - from)
                     }
                     ty::Slice(..) => {
                         assert!(from_end, "slice subslices should use from_end");
@@ -1737,7 +1737,7 @@ fn check_call_inputs(
                 ConstraintCategory::Boring
             };
             if let Err(terr) =
-                self.sub_types(op_arg_ty, fn_arg, term_location.to_locations(), category)
+                self.sub_types(op_arg_ty, *fn_arg, term_location.to_locations(), category)
             {
                 span_mirbug!(
                     self,
@@ -1956,7 +1956,7 @@ fn aggregate_field_ty(
     fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
         if let Operand::Constant(constant) = op {
             let maybe_uneval = match constant.literal {
-                ConstantKind::Ty(ct) => match ct.val {
+                ConstantKind::Ty(ct) => match ct.val() {
                     ty::ConstKind::Unevaluated(uv) => Some(uv),
                     _ => None,
                 },
@@ -2048,7 +2048,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                 }
             }
 
-            Rvalue::NullaryOp(_, ty) => {
+            &Rvalue::NullaryOp(_, ty) => {
                 let trait_ref = ty::TraitRef {
                     def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
                     substs: tcx.mk_substs_trait(ty, &[]),
@@ -2066,7 +2066,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
 
                 let trait_ref = ty::TraitRef {
                     def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
-                    substs: tcx.mk_substs_trait(ty, &[]),
+                    substs: tcx.mk_substs_trait(*ty, &[]),
                 };
 
                 self.prove_trait_ref(
@@ -2093,7 +2093,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                         let ty_fn_ptr_from = tcx.mk_fn_ptr(fn_sig);
 
                         if let Err(terr) = self.eq_types(
-                            ty,
+                            *ty,
                             ty_fn_ptr_from,
                             location.to_locations(),
                             ConstraintCategory::Cast,
@@ -2117,7 +2117,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                         let ty_fn_ptr_from = tcx.mk_fn_ptr(tcx.signature_unclosure(sig, *unsafety));
 
                         if let Err(terr) = self.eq_types(
-                            ty,
+                            *ty,
                             ty_fn_ptr_from,
                             location.to_locations(),
                             ConstraintCategory::Cast,
@@ -2146,7 +2146,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                         let ty_fn_ptr_from = tcx.safe_to_unsafe_fn_ty(fn_sig);
 
                         if let Err(terr) = self.eq_types(
-                            ty,
+                            *ty,
                             ty_fn_ptr_from,
                             location.to_locations(),
                             ConstraintCategory::Cast,
@@ -2209,8 +2209,8 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                             }
                         };
                         if let Err(terr) = self.sub_types(
-                            ty_from,
-                            ty_to,
+                            *ty_from,
+                            *ty_to,
                             location.to_locations(),
                             ConstraintCategory::Cast,
                         ) {
@@ -2278,8 +2278,8 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                         }
 
                         if let Err(terr) = self.sub_types(
-                            ty_elem,
-                            ty_to,
+                            *ty_elem,
+                            *ty_to,
                             location.to_locations(),
                             ConstraintCategory::Cast,
                         ) {
@@ -2297,7 +2297,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                     CastKind::Misc => {
                         let ty_from = op.ty(body, tcx);
                         let cast_ty_from = CastTy::from_ty(ty_from);
-                        let cast_ty_to = CastTy::from_ty(ty);
+                        let cast_ty_to = CastTy::from_ty(*ty);
                         match (cast_ty_from, cast_ty_to) {
                             (None, _)
                             | (_, None | Some(CastTy::FnPtr))
@@ -2318,7 +2318,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
             }
 
             Rvalue::Ref(region, _borrow_kind, borrowed_place) => {
-                self.add_reborrow_constraint(&body, location, region, borrowed_place);
+                self.add_reborrow_constraint(&body, location, *region, borrowed_place);
             }
 
             Rvalue::BinaryOp(
index cc3fe0a123c55bc79803e994cddc189e71f13c85..590a7a91641557700b77108b9c4189230c43bf99 100644 (file)
@@ -117,7 +117,7 @@ fn push_outlives(
 
     // We don't have to worry about the equality of consts during borrow checking
     // as consts always have a static lifetime.
-    fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {}
+    fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {}
 
     fn normalization() -> NormalizationStrategy {
         NormalizationStrategy::Eager
index 16a903d5e593f75dd306d4859ee929aec251d94e..72de3805467dc87baa4ea24eb8cee2615fef3a31 100644 (file)
@@ -323,7 +323,7 @@ pub fn named_universal_regions<'s>(
 
     /// See `UniversalRegionIndices::to_region_vid`.
     pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
-        if let ty::ReEmpty(ty::UniverseIndex::ROOT) = r {
+        if let ty::ReEmpty(ty::UniverseIndex::ROOT) = *r {
             self.root_empty
         } else {
             self.indices.to_region_vid(r)
@@ -512,7 +512,7 @@ fn build(self) -> UniversalRegions<'tcx> {
             first_local_index,
             num_universals,
             defining_ty,
-            unnormalized_output_ty,
+            unnormalized_output_ty: *unnormalized_output_ty,
             unnormalized_input_tys,
             yield_ty,
         }
@@ -805,7 +805,7 @@ fn insert_late_bound_region(&mut self, r: ty::Region<'tcx>, vid: ty::RegionVid)
     /// during initialization. Relies on the `indices` map having been
     /// fully initialized.
     pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
-        if let ty::ReVar(..) = r {
+        if let ty::ReVar(..) = *r {
             r.to_region_vid()
         } else {
             *self
index 1a6e56947916f41182136d3d9c96f38cc193c701..ac37c4973d8709c09bdc8c4f85cfe675e8d7fc44 100644 (file)
@@ -700,11 +700,11 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                                 Some(idx)
                             }
                         }
-                        parse::ArgumentNamed(name) => match args.named_args.get(&name) {
+                        parse::ArgumentNamed(name, span) => match args.named_args.get(&name) {
                             Some(&idx) => Some(idx),
                             None => {
                                 let msg = format!("there is no argument named `{}`", name);
-                                ecx.struct_span_err(span, &msg).emit();
+                                ecx.struct_span_err(template_span.from_inner(span), &msg).emit();
                                 None
                             }
                         },
index 1e2646e4d348faa5f72614ade0978ac7b01d988c..9a45dec55f30b0d7e41e8b213013537d6cc7d5a0 100644 (file)
@@ -1,4 +1,4 @@
-use crate::panic::use_panic_2021;
+use crate::edition_panic::use_panic_2021;
 use rustc_ast::ptr::P;
 use rustc_ast::token;
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
index eb08170959bfb1e5f9bd63e08cb33255f037b67d..c06af5206d5b1b04205ab22fdde8ccd290b48f1a 100644 (file)
@@ -6,9 +6,7 @@
 
 /// Emits errors for literal expressions that are invalid inside and outside of an array.
 fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_nested: bool) {
-    let lit = if let ast::ExprKind::Lit(lit) = &expr.kind {
-        lit
-    } else {
+    let ast::ExprKind::Lit(lit) = &expr.kind else {
         unreachable!();
     };
     match lit.kind {
index 8c53094b6249669d0ef78dd9b80ed48a3f242d39..1d1eee88a68e614780634da880552b8b5df231dd 100644 (file)
@@ -222,9 +222,6 @@ fn validate_default_attribute(
             "this method must only be called with a variant that has a `#[default]` attribute",
         ),
         [first, rest @ ..] => {
-            // FIXME(jhpratt) Do we want to perform this check? It doesn't exist
-            // for `#[inline]`, `#[non_exhaustive]`, and presumably others.
-
             let suggestion_text =
                 if rest.len() == 1 { "try removing this" } else { "try removing these" };
 
index 367a5aa732370a0dff03491b22f151322989206e..0ca7988ca152f6c48059a6c494fec820493bb688 100644 (file)
@@ -134,7 +134,7 @@ fn inject_impl_of_structural_trait(
 
     // Create the type of `self`.
     //
-    // in addition, remove defaults from type params (impls cannot have them).
+    // in addition, remove defaults from generic params (impls cannot have them).
     let self_params: Vec<_> = generics
         .params
         .iter_mut()
diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs
new file mode 100644 (file)
index 0000000..518b88d
--- /dev/null
@@ -0,0 +1,86 @@
+use rustc_ast::ptr::P;
+use rustc_ast::tokenstream::{DelimSpan, TokenStream};
+use rustc_ast::*;
+use rustc_expand::base::*;
+use rustc_span::edition::Edition;
+use rustc_span::symbol::sym;
+use rustc_span::Span;
+
+// This expands to either
+// - `$crate::panic::panic_2015!(...)` or
+// - `$crate::panic::panic_2021!(...)`
+// depending on the edition.
+//
+// This is used for both std::panic!() and core::panic!().
+//
+// `$crate` will refer to either the `std` or `core` crate depending on which
+// one we're expanding from.
+pub fn expand_panic<'cx>(
+    cx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: TokenStream,
+) -> Box<dyn MacResult + 'cx> {
+    let mac = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 };
+    expand(mac, cx, sp, tts)
+}
+
+// This expands to either
+// - `$crate::panic::unreachable_2015!(...)` or
+// - `$crate::panic::unreachable_2021!(...)`
+// depending on the edition.
+pub fn expand_unreachable<'cx>(
+    cx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: TokenStream,
+) -> Box<dyn MacResult + 'cx> {
+    let mac = if use_panic_2021(sp) { sym::unreachable_2021 } else { sym::unreachable_2015 };
+    expand(mac, cx, sp, tts)
+}
+
+fn expand<'cx>(
+    mac: rustc_span::Symbol,
+    cx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: TokenStream,
+) -> Box<dyn MacResult + 'cx> {
+    let sp = cx.with_call_site_ctxt(sp);
+
+    MacEager::expr(
+        cx.expr(
+            sp,
+            ExprKind::MacCall(MacCall {
+                path: Path {
+                    span: sp,
+                    segments: cx
+                        .std_path(&[sym::panic, mac])
+                        .into_iter()
+                        .map(|ident| PathSegment::from_ident(ident))
+                        .collect(),
+                    tokens: None,
+                },
+                args: P(MacArgs::Delimited(
+                    DelimSpan::from_single(sp),
+                    MacDelimiter::Parenthesis,
+                    tts,
+                )),
+                prior_type_ascription: None,
+            }),
+        ),
+    )
+}
+
+pub fn use_panic_2021(mut span: Span) -> bool {
+    // To determine the editon, we check the first span up the expansion
+    // stack that does not have #[allow_internal_unstable(edition_panic)].
+    // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.)
+    loop {
+        let expn = span.ctxt().outer_expn_data();
+        if let Some(features) = expn.allow_internal_unstable {
+            if features.iter().any(|&f| f == sym::edition_panic) {
+                span = expn.call_site;
+                continue;
+            }
+        }
+        break expn.edition >= Edition::Edition2021;
+    }
+}
index aaa6580acc6f08543d8895009306d3fc29229f32..6141d00f69712ab39e35c288bb4be8e8d9e46777 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_expand::base::{self, *};
 use rustc_parse_format as parse;
 use rustc_span::symbol::{sym, Ident, Symbol};
-use rustc_span::{MultiSpan, Span};
+use rustc_span::{InnerSpan, MultiSpan, Span};
 use smallvec::SmallVec;
 
 use std::borrow::Cow;
@@ -25,7 +25,8 @@ enum ArgumentType {
 
 enum Position {
     Exact(usize),
-    Named(Symbol),
+    Capture(usize),
+    Named(Symbol, InnerSpan),
 }
 
 struct Context<'a, 'b> {
@@ -49,6 +50,8 @@ struct Context<'a, 'b> {
     /// * `arg_unique_types` (in simplified JSON): `[["o", "x"], ["o", "x"], ["o", "x"]]`
     /// * `names` (in JSON): `{"foo": 2}`
     args: Vec<P<ast::Expr>>,
+    /// The number of arguments that were added by implicit capturing.
+    num_captured_args: usize,
     /// Placeholder slot numbers indexed by argument.
     arg_types: Vec<Vec<usize>>,
     /// Unique format specs seen for each argument.
@@ -231,6 +234,11 @@ fn parse_args<'a>(
 }
 
 impl<'a, 'b> Context<'a, 'b> {
+    /// The number of arguments that were explicitly given.
+    fn num_args(&self) -> usize {
+        self.args.len() - self.num_captured_args
+    }
+
     fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
         // NOTE: the `unwrap_or` branch is needed in case of invalid format
         // arguments, e.g., `format_args!("{foo}")`.
@@ -239,13 +247,13 @@ fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) {
         match *p {
             parse::String(_) => {}
             parse::NextArgument(ref mut arg) => {
-                if let parse::ArgumentNamed(s) = arg.position {
+                if let parse::ArgumentNamed(s, _) = arg.position {
                     arg.position = parse::ArgumentIs(lookup(s));
                 }
-                if let parse::CountIsName(s) = arg.format.width {
+                if let parse::CountIsName(s, _) = arg.format.width {
                     arg.format.width = parse::CountIsParam(lookup(s));
                 }
-                if let parse::CountIsName(s) = arg.format.precision {
+                if let parse::CountIsName(s, _) = arg.format.precision {
                     arg.format.precision = parse::CountIsParam(lookup(s));
                 }
             }
@@ -268,7 +276,7 @@ fn verify_piece(&mut self, p: &parse::Piece<'_>) {
                 // it's written second, so it should come after width/precision.
                 let pos = match arg.position {
                     parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i),
-                    parse::ArgumentNamed(s) => Named(s),
+                    parse::ArgumentNamed(s, span) => Named(s, span),
                 };
 
                 let ty = Placeholder(match arg.format.ty {
@@ -338,14 +346,14 @@ fn verify_count(&mut self, c: parse::Count) {
             parse::CountIsParam(i) => {
                 self.verify_arg_type(Exact(i), Count);
             }
-            parse::CountIsName(s) => {
-                self.verify_arg_type(Named(s), Count);
+            parse::CountIsName(s, span) => {
+                self.verify_arg_type(Named(s, span), Count);
             }
         }
     }
 
     fn describe_num_args(&self) -> Cow<'_, str> {
-        match self.args.len() {
+        match self.num_args() {
             0 => "no arguments were given".into(),
             1 => "there is 1 argument".into(),
             x => format!("there are {} arguments", x).into(),
@@ -371,7 +379,7 @@ fn report_invalid_references(&self, numbered_position_args: bool) {
 
         let count = self.pieces.len()
             + self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count();
-        if self.names.is_empty() && !numbered_position_args && count != self.args.len() {
+        if self.names.is_empty() && !numbered_position_args && count != self.num_args() {
             e = self.ecx.struct_span_err(
                 sp,
                 &format!(
@@ -419,7 +427,7 @@ fn report_invalid_references(&self, numbered_position_args: bool) {
             if let Some(span) = fmt.precision_span {
                 let span = self.fmtsp.from_inner(span);
                 match fmt.precision {
-                    parse::CountIsParam(pos) if pos > self.args.len() => {
+                    parse::CountIsParam(pos) if pos > self.num_args() => {
                         e.span_label(
                             span,
                             &format!(
@@ -462,7 +470,7 @@ fn report_invalid_references(&self, numbered_position_args: bool) {
             if let Some(span) = fmt.width_span {
                 let span = self.fmtsp.from_inner(span);
                 match fmt.width {
-                    parse::CountIsParam(pos) if pos > self.args.len() => {
+                    parse::CountIsParam(pos) if pos > self.num_args() => {
                         e.span_label(
                             span,
                             &format!(
@@ -494,12 +502,15 @@ fn report_invalid_references(&self, numbered_position_args: bool) {
     /// Actually verifies and tracks a given format placeholder
     /// (a.k.a. argument).
     fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
+        if let Exact(arg) = arg {
+            if arg >= self.num_args() {
+                self.invalid_refs.push((arg, self.curpiece));
+                return;
+            }
+        }
+
         match arg {
-            Exact(arg) => {
-                if self.args.len() <= arg {
-                    self.invalid_refs.push((arg, self.curpiece));
-                    return;
-                }
+            Exact(arg) | Capture(arg) => {
                 match ty {
                     Placeholder(_) => {
                         // record every (position, type) combination only once
@@ -522,11 +533,11 @@ fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
                 }
             }
 
-            Named(name) => {
+            Named(name, span) => {
                 match self.names.get(&name) {
                     Some(&idx) => {
                         // Treat as positional arg.
-                        self.verify_arg_type(Exact(idx), ty)
+                        self.verify_arg_type(Capture(idx), ty)
                     }
                     None => {
                         // For the moment capturing variables from format strings expanded from macros is
@@ -537,17 +548,18 @@ fn verify_arg_type(&mut self, arg: Position, ty: ArgumentType) {
                             self.arg_types.push(Vec::new());
                             self.arg_unique_types.push(Vec::new());
                             let span = if self.is_literal {
-                                *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp)
+                                self.fmtsp.from_inner(span)
                             } else {
                                 self.fmtsp
                             };
+                            self.num_captured_args += 1;
                             self.args.push(self.ecx.expr_ident(span, Ident::new(name, span)));
                             self.names.insert(name, idx);
-                            self.verify_arg_type(Exact(idx), ty)
+                            self.verify_arg_type(Capture(idx), ty)
                         } else {
                             let msg = format!("there is no argument named `{}`", name);
                             let sp = if self.is_literal {
-                                *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp)
+                                self.fmtsp.from_inner(span)
                             } else {
                                 self.fmtsp
                             };
@@ -617,7 +629,7 @@ fn build_count(&self, c: parse::Count) -> P<ast::Expr> {
             }
             parse::CountImplied => count(sym::Implied, None),
             // should never be the case, names are already resolved
-            parse::CountIsName(_) => panic!("should never happen"),
+            parse::CountIsName(..) => panic!("should never happen"),
         }
     }
 
@@ -664,7 +676,7 @@ fn build_piece(
 
                         // should never be the case, because names are already
                         // resolved.
-                        parse::ArgumentNamed(_) => panic!("should never happen"),
+                        parse::ArgumentNamed(..) => panic!("should never happen"),
                     }
                 };
 
@@ -1051,6 +1063,7 @@ pub fn expand_preparsed_format_args(
     let mut cx = Context {
         ecx,
         args,
+        num_captured_args: 0,
         arg_types,
         arg_unique_types,
         names,
index a433876147f8d903edbc8568485649f5eef0cf92..36cfbba45daccb2d521a5419b5c370e6e97293aa 100644 (file)
@@ -26,14 +26,14 @@ pub fn expand(
 
     // Allow using `#[global_allocator]` on an item statement
     // FIXME - if we get deref patterns, use them to reduce duplication here
-    let (item, is_stmt) = match &item {
+    let (item, is_stmt, ty_span) = match &item {
         Annotatable::Item(item) => match item.kind {
-            ItemKind::Static(..) => (item, false),
+            ItemKind::Static(ref ty, ..) => (item, false, ecx.with_def_site_ctxt(ty.span)),
             _ => return not_static(),
         },
         Annotatable::Stmt(stmt) => match &stmt.kind {
             StmtKind::Item(item_) => match item_.kind {
-                ItemKind::Static(..) => (item_, true),
+                ItemKind::Static(ref ty, ..) => (item_, true, ecx.with_def_site_ctxt(ty.span)),
                 _ => return not_static(),
             },
             _ => return not_static(),
@@ -43,13 +43,14 @@ pub fn expand(
 
     // Generate a bunch of new items using the AllocFnFactory
     let span = ecx.with_def_site_ctxt(item.span);
-    let f = AllocFnFactory { span, kind: AllocatorKind::Global, global: item.ident, cx: ecx };
+    let f =
+        AllocFnFactory { span, ty_span, kind: AllocatorKind::Global, global: item.ident, cx: ecx };
 
     // Generate item statements for the allocator methods.
     let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect();
 
     // Generate anonymous constant serving as container for the allocator methods.
-    let const_ty = ecx.ty(span, TyKind::Tup(Vec::new()));
+    let const_ty = ecx.ty(ty_span, TyKind::Tup(Vec::new()));
     let const_body = ecx.expr_block(ecx.block(span, stmts));
     let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
     let const_item = if is_stmt {
@@ -64,6 +65,7 @@ pub fn expand(
 
 struct AllocFnFactory<'a, 'b> {
     span: Span,
+    ty_span: Span,
     kind: AllocatorKind,
     global: Ident,
     cx: &'b ExtCtxt<'a>,
@@ -97,18 +99,18 @@ fn allocator_fn(&self, method: &AllocatorMethod) -> Stmt {
             self.attrs(),
             kind,
         );
-        self.cx.stmt_item(self.span, item)
+        self.cx.stmt_item(self.ty_span, item)
     }
 
     fn call_allocator(&self, method: Symbol, mut args: Vec<P<Expr>>) -> P<Expr> {
         let method = self.cx.std_path(&[sym::alloc, sym::GlobalAlloc, method]);
-        let method = self.cx.expr_path(self.cx.path(self.span, method));
-        let allocator = self.cx.path_ident(self.span, self.global);
+        let method = self.cx.expr_path(self.cx.path(self.ty_span, method));
+        let allocator = self.cx.path_ident(self.ty_span, self.global);
         let allocator = self.cx.expr_path(allocator);
-        let allocator = self.cx.expr_addr_of(self.span, allocator);
+        let allocator = self.cx.expr_addr_of(self.ty_span, allocator);
         args.insert(0, allocator);
 
-        self.cx.expr_call(self.span, method, args)
+        self.cx.expr_call(self.ty_span, method, args)
     }
 
     fn attrs(&self) -> Vec<Attribute> {
index eda9be58d9427147aab3f2cd4fe4774504d11957..38877399943ef77574acfd04697ab2e3d7ddc8ec 100644 (file)
@@ -9,6 +9,7 @@
 #![feature(decl_macro)]
 #![feature(is_sorted)]
 #![feature(nll)]
+#![feature(let_else)]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_quote)]
 #![recursion_limit = "256"]
 mod concat_idents;
 mod derive;
 mod deriving;
+mod edition_panic;
 mod env;
 mod format;
 mod format_foreign;
 mod global_allocator;
 mod log_syntax;
-mod panic;
 mod source_util;
 mod test;
 mod trace_macros;
@@ -83,8 +84,9 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         log_syntax: log_syntax::expand_log_syntax,
         module_path: source_util::expand_mod,
         option_env: env::expand_option_env,
-        core_panic: panic::expand_panic,
-        std_panic: panic::expand_panic,
+        core_panic: edition_panic::expand_panic,
+        std_panic: edition_panic::expand_panic,
+        unreachable: edition_panic::expand_unreachable,
         stringify: source_util::expand_stringify,
         trace_macros: trace_macros::expand_trace_macros,
     }
diff --git a/compiler/rustc_builtin_macros/src/panic.rs b/compiler/rustc_builtin_macros/src/panic.rs
deleted file mode 100644 (file)
index 54ab596..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-use rustc_ast::ptr::P;
-use rustc_ast::tokenstream::{DelimSpan, TokenStream};
-use rustc_ast::*;
-use rustc_expand::base::*;
-use rustc_span::edition::Edition;
-use rustc_span::symbol::sym;
-use rustc_span::Span;
-
-// This expands to either
-// - `$crate::panic::panic_2015!(...)` or
-// - `$crate::panic::panic_2021!(...)`
-// depending on the edition.
-//
-// This is used for both std::panic!() and core::panic!().
-//
-// `$crate` will refer to either the `std` or `core` crate depending on which
-// one we're expanding from.
-pub fn expand_panic<'cx>(
-    cx: &'cx mut ExtCtxt<'_>,
-    sp: Span,
-    tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
-    let panic = if use_panic_2021(sp) { sym::panic_2021 } else { sym::panic_2015 };
-
-    let sp = cx.with_call_site_ctxt(sp);
-
-    MacEager::expr(
-        cx.expr(
-            sp,
-            ExprKind::MacCall(MacCall {
-                path: Path {
-                    span: sp,
-                    segments: cx
-                        .std_path(&[sym::panic, panic])
-                        .into_iter()
-                        .map(|ident| PathSegment::from_ident(ident))
-                        .collect(),
-                    tokens: None,
-                },
-                args: P(MacArgs::Delimited(
-                    DelimSpan::from_single(sp),
-                    MacDelimiter::Parenthesis,
-                    tts,
-                )),
-                prior_type_ascription: None,
-            }),
-        ),
-    )
-}
-
-pub fn use_panic_2021(mut span: Span) -> bool {
-    // To determine the editon, we check the first span up the expansion
-    // stack that does not have #[allow_internal_unstable(edition_panic)].
-    // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.)
-    loop {
-        let expn = span.ctxt().outer_expn_data();
-        if let Some(features) = expn.allow_internal_unstable {
-            if features.iter().any(|&f| f == sym::edition_panic) {
-                span = expn.call_site;
-                continue;
-            }
-        }
-        break expn.edition >= Edition::Edition2021;
-    }
-}
index 6f61e4cba0776acccf84358c781fa4bd2a4516fa..c9dd114047b76eda6c0fb10bc249d2cdd82306b9 100644 (file)
@@ -56,7 +56,6 @@ pub fn inject(
     is_proc_macro_crate: bool,
     has_proc_macro_decls: bool,
     is_test_crate: bool,
-    num_crate_types: usize,
     handler: &rustc_errors::Handler,
 ) -> ast::Crate {
     let ecfg = ExpansionConfig::default("proc_macro".to_string());
@@ -81,10 +80,6 @@ pub fn inject(
         return krate;
     }
 
-    if num_crate_types > 1 {
-        handler.err("cannot mix `proc-macro` crate type with others");
-    }
-
     if is_test_crate {
         return krate;
     }
index e106f6014a31d597a0a84f18db3473a43d79b9b1..3571517d2b258a8162ab6fc69bb0e5e658015e7e 100644 (file)
@@ -11,7 +11,6 @@ pub fn inject(
     mut krate: ast::Crate,
     resolver: &mut dyn ResolverExpand,
     sess: &Session,
-    alt_std_name: Option<Symbol>,
 ) -> ast::Crate {
     let edition = sess.parse_sess.edition;
 
@@ -53,7 +52,7 @@ pub fn inject(
                 span,
                 ident,
                 vec![cx.attribute(cx.meta_word(span, sym::macro_use))],
-                ast::ItemKind::ExternCrate(alt_std_name),
+                ast::ItemKind::ExternCrate(None),
             ),
         );
     }
index c08b141b557cae1db99280d915156929ab35d964..690879624058b4ac3a0667baec6a403889bbe683 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_ast::attr;
 use rustc_ast::ptr::P;
 use rustc_ast_pretty::pprust;
+use rustc_errors::Applicability;
 use rustc_expand::base::*;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -102,11 +103,20 @@ pub fn expand_test_or_bench(
         }
     };
 
-    if let ast::ItemKind::MacCall(_) = item.kind {
-        cx.sess.parse_sess.span_diagnostic.span_warn(
-            item.span,
-            "`#[test]` attribute should not be used on macros. Use `#[cfg(test)]` instead.",
-        );
+    // Note: non-associated fn items are already handled by `expand_test_or_bench`
+    if !matches!(item.kind, ast::ItemKind::Fn(_)) {
+        cx.sess
+            .parse_sess
+            .span_diagnostic
+            .struct_span_err(
+                attr_sp,
+                "the `#[test]` attribute may only be used on a non-associated function",
+            )
+            .note("the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions")
+            .span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
+            .span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", String::from("#[cfg(test)]"), Applicability::MaybeIncorrect)
+            .emit();
+
         return vec![Annotatable::Item(item)];
     }
 
@@ -252,11 +262,6 @@ pub fn expand_test_or_bench(
                                         "ignore",
                                         cx.expr_bool(sp, should_ignore(&cx.sess, &item)),
                                     ),
-                                    // allow_fail: true | false
-                                    field(
-                                        "allow_fail",
-                                        cx.expr_bool(sp, should_fail(&cx.sess, &item)),
-                                    ),
                                     // compile_fail: true | false
                                     field("compile_fail", cx.expr_bool(sp, false)),
                                     // no_run: true | false
@@ -359,10 +364,6 @@ fn should_ignore(sess: &Session, i: &ast::Item) -> bool {
     sess.contains_name(&i.attrs, sym::ignore)
 }
 
-fn should_fail(sess: &Session, i: &ast::Item) -> bool {
-    sess.contains_name(&i.attrs, sym::allow_fail)
-}
-
 fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
     match cx.sess.find_by_name(&i.attrs, sym::should_panic) {
         Some(attr) => {
@@ -475,7 +476,7 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
             (false, _) => true,
         }
     } else {
-        sd.span_err(i.span, "only functions may be used as tests");
+        // should be unreachable because `is_test_fn_item` should catch all non-fn items
         false
     }
 }
index 72ebc84c1a3443d56f5a8c0a5d27658ac2bc6411..a0550860fa54531be5476ad9298b7333f4edfa72 100644 (file)
@@ -544,7 +544,7 @@ pub(crate) fn codegen_drop<'tcx>(
                 let arg_value = drop_place.place_ref(
                     fx,
                     fx.layout_of(fx.tcx.mk_ref(
-                        &ty::RegionKind::ReErased,
+                        fx.tcx.lifetimes.re_erased,
                         TypeAndMut { ty, mutbl: crate::rustc_hir::Mutability::Mut },
                     )),
                 );
index b0eb3864d80c82e5c44e4c749746447bcd678447..a099e8b3a6af3a07806d1c5e3b33996941adc1f1 100644 (file)
@@ -105,8 +105,6 @@ fn add_archive<F>(&mut self, archive_path: &Path, mut skip: F) -> std::io::Resul
         Ok(())
     }
 
-    fn update_symbols(&mut self) {}
-
     fn build(mut self) {
         enum BuilderKind {
             Bsd(ar::Builder<File>),
index 5a889734f215b4007efc699b49e876c289ab0647..917afa4eae06cbb91fe44f4fca3f7958c765abde 100644 (file)
@@ -79,7 +79,7 @@ pub(crate) fn codegen_fn<'tcx>(
     let arg_uninhabited = fx
         .mir
         .args_iter()
-        .any(|arg| fx.layout_of(fx.monomorphize(&fx.mir.local_decls[arg].ty)).abi.is_uninhabited());
+        .any(|arg| fx.layout_of(fx.monomorphize(fx.mir.local_decls[arg].ty)).abi.is_uninhabited());
 
     if !crate::constant::check_constants(&mut fx) {
         fx.bcx.append_block_params_for_function_params(fx.block_map[START_BLOCK]);
@@ -668,7 +668,7 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
                     let times = fx
                         .monomorphize(times)
                         .eval(fx.tcx, ParamEnv::reveal_all())
-                        .val
+                        .val()
                         .try_to_bits(fx.tcx.data_layout.pointer_size)
                         .unwrap();
                     if operand.layout().size.bytes() == 0 {
@@ -818,16 +818,16 @@ pub(crate) fn codegen_place<'tcx>(
                 match cplace.layout().ty.kind() {
                     ty::Array(elem_ty, _len) => {
                         assert!(!from_end, "array subslices are never `from_end`");
-                        let elem_layout = fx.layout_of(elem_ty);
+                        let elem_layout = fx.layout_of(*elem_ty);
                         let ptr = cplace.to_ptr();
                         cplace = CPlace::for_ptr(
                             ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)),
-                            fx.layout_of(fx.tcx.mk_array(elem_ty, to - from)),
+                            fx.layout_of(fx.tcx.mk_array(*elem_ty, to - from)),
                         );
                     }
                     ty::Slice(elem_ty) => {
                         assert!(from_end, "slice subslices should be `from_end`");
-                        let elem_layout = fx.layout_of(elem_ty);
+                        let elem_layout = fx.layout_of(*elem_ty);
                         let (ptr, len) = cplace.to_ptr_maybe_unsized();
                         let len = len.unwrap();
                         cplace = CPlace::for_ptr_with_extra(
index 3b6025c73d10bd7a0113e2b31662dd7a20d9753a..50f98965ab5d22ac31f735a56e18385e87bd2f69 100644 (file)
@@ -61,7 +61,7 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<types::Typ
         },
         ty::FnPtr(_) => pointer_ty(tcx),
         ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => {
-            if has_ptr_meta(tcx, pointee_ty) {
+            if has_ptr_meta(tcx, *pointee_ty) {
                 return None;
             } else {
                 pointer_ty(tcx)
@@ -100,7 +100,7 @@ fn clif_pair_type_from_ty<'tcx>(
             (a, b)
         }
         ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => {
-            if has_ptr_meta(tcx, pointee_ty) {
+            if has_ptr_meta(tcx, *pointee_ty) {
                 (pointer_ty(tcx), pointer_ty(tcx))
             } else {
                 return None;
index 74571817969d32576a599e56620521f88b0dd952..274fb211b7bbb5cd2ee8dff0b37267aec5fae605 100644 (file)
@@ -46,7 +46,7 @@ pub(crate) fn check_constants(fx: &mut FunctionCx<'_, '_, '_>) -> bool {
             ConstantKind::Ty(ct) => ct,
             ConstantKind::Val(..) => continue,
         };
-        match const_.val {
+        match const_.val() {
             ConstKind::Value(_) => {}
             ConstKind::Unevaluated(unevaluated) => {
                 if let Err(err) =
@@ -127,7 +127,7 @@ pub(crate) fn codegen_constant<'tcx>(
         ConstantKind::Ty(ct) => ct,
         ConstantKind::Val(val, ty) => return codegen_const_value(fx, val, ty),
     };
-    let const_val = match const_.val {
+    let const_val = match const_.val() {
         ConstKind::Value(const_val) => const_val,
         ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
             if fx.tcx.is_static(def.did) =>
@@ -135,7 +135,7 @@ pub(crate) fn codegen_constant<'tcx>(
             assert!(substs.is_empty());
             assert!(promoted.is_none());
 
-            return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty)).to_cvalue(fx);
+            return codegen_static_ref(fx, def.did, fx.layout_of(const_.ty())).to_cvalue(fx);
         }
         ConstKind::Unevaluated(unevaluated) => {
             match fx.tcx.const_eval_resolve(ParamEnv::reveal_all(), unevaluated, None) {
@@ -152,7 +152,7 @@ pub(crate) fn codegen_constant<'tcx>(
         | ConstKind::Error(_) => unreachable!("{:?}", const_),
     };
 
-    codegen_const_value(fx, const_val, const_.ty)
+    codegen_const_value(fx, const_val, const_.ty())
 }
 
 pub(crate) fn codegen_const_value<'tcx>(
@@ -465,7 +465,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
     match operand {
         Operand::Constant(const_) => match const_.literal {
             ConstantKind::Ty(const_) => {
-                fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value()
+                fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val().try_to_value()
             }
             ConstantKind::Val(val, _) => Some(val),
         },
@@ -490,7 +490,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                                         return None;
                                     }
                                     let const_val = mir_operand_get_const_val(fx, operand)?;
-                                    if fx.layout_of(ty).size
+                                    if fx.layout_of(*ty).size
                                         != const_val.try_to_scalar_int()?.size()
                                     {
                                         return None;
index 8e203b8cfa0637eb761c1af0b8cc1915caf79529..693092ba543ea947c5b448520fac7984935e697c 100644 (file)
@@ -114,7 +114,7 @@ pub(crate) fn new(tcx: TyCtxt<'tcx>, isa: &dyn TargetIsa) -> Self {
     }
 
     fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId {
-        if let Some(type_id) = self.types.get(ty) {
+        if let Some(type_id) = self.types.get(&ty) {
             return *type_id;
         }
 
@@ -143,7 +143,7 @@ fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId {
                 // Ensure that type is inserted before recursing to avoid duplicates
                 self.types.insert(ty, type_id);
 
-                let pointee = self.dwarf_ty(pointee_ty);
+                let pointee = self.dwarf_ty(*pointee_ty);
 
                 let type_entry = self.dwarf.unit.get_mut(type_id);
 
index fd96858010ea96c228f0ca76471743014e1580a1..8cae506e0cb62362eb56b626d02814f3d69395b2 100644 (file)
@@ -66,7 +66,7 @@ fn unsize_ptr<'tcx>(
         (&ty::Ref(_, a, _), &ty::Ref(_, b, _))
         | (&ty::Ref(_, a, _), &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
         | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
-            (src, unsized_info(fx, a, b, old_info))
+            (src, unsized_info(fx, *a, *b, old_info))
         }
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
             let (a, b) = (src_layout.ty.boxed_ty(), dst_layout.ty.boxed_ty());
index f29d13ccabddd25b4bd4a208ac2fa32df2fb937e..b016af5174e018630eddbb3b1ef5ae9bac8398ab 100644 (file)
@@ -514,7 +514,7 @@ fn transmute_value<'tcx>(
                     // Can only happen for vector types
                     let len =
                         u16::try_from(len.eval_usize(fx.tcx, ParamEnv::reveal_all())).unwrap();
-                    let vector_ty = fx.clif_type(element).unwrap().by(len).unwrap();
+                    let vector_ty = fx.clif_type(*element).unwrap().by(len).unwrap();
 
                     let data = match from.0 {
                         CValueInner::ByRef(ptr, None) => {
@@ -721,8 +721,8 @@ pub(crate) fn place_index(
         index: Value,
     ) -> CPlace<'tcx> {
         let (elem_layout, ptr) = match self.layout().ty.kind() {
-            ty::Array(elem_ty, _) => (fx.layout_of(elem_ty), self.to_ptr()),
-            ty::Slice(elem_ty) => (fx.layout_of(elem_ty), self.to_ptr_maybe_unsized().0),
+            ty::Array(elem_ty, _) => (fx.layout_of(*elem_ty), self.to_ptr()),
+            ty::Slice(elem_ty) => (fx.layout_of(*elem_ty), self.to_ptr_maybe_unsized().0),
             _ => bug!("place_index({:?})", self.layout().ty),
         };
 
@@ -781,11 +781,11 @@ pub(crate) fn assert_assignable<'tcx>(
             ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }),
             ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }),
         ) => {
-            assert_assignable(fx, a, b);
+            assert_assignable(fx, *a, *b);
         }
         (ty::Ref(_, a, _), ty::RawPtr(TypeAndMut { ty: b, mutbl: _ }))
         | (ty::RawPtr(TypeAndMut { ty: a, mutbl: _ }), ty::Ref(_, b, _)) => {
-            assert_assignable(fx, a, b);
+            assert_assignable(fx, *a, *b);
         }
         (ty::FnPtr(_), ty::FnPtr(_)) => {
             let from_sig = fx.tcx.normalize_erasing_late_bound_regions(
index 11dd6d49aa768d5d207cf4a1e4fe57e2008534a1..fac532f3e9c83a1f2dad6c48a27faecd64a25d2c 100644 (file)
@@ -113,9 +113,6 @@ fn add_archive<F>(&mut self, archive_path: &Path, mut skip: F) -> std::io::Resul
         Ok(())
     }
 
-    fn update_symbols(&mut self) {
-    }
-
     fn build(mut self) {
         use std::process::Command;
 
index ba4589bd810255be742e27f90a908bd54d4135f8..ddc2b88191bd0e8e032d05e1220579ec09071fe7 100644 (file)
@@ -144,7 +144,7 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
             // TODO(antoyo): set link section.
         }
 
-        if attrs.flags.contains(CodegenFnAttrFlags::USED) {
+        if attrs.flags.contains(CodegenFnAttrFlags::USED) || attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
             self.add_used_global(global.to_rvalue());
         }
     }
index e9b66b54c58b3b6e6cf4291fd49fe7fbff342a13..8a11e3e71bc81253404a427dd4d1b1c814b32339 100644 (file)
@@ -37,7 +37,7 @@ fn for_each_kind<F>(&self, mut f: F)
     where
         F: FnMut(llvm::Attribute),
     {
-        for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg)
+        for_each_kind!(self, f, NoAlias, NoCapture, NonNull, ReadOnly, InReg, NoUndef)
     }
 }
 
index 30d91b41a8e8b2b8a02b750a2b38c149cff4b3c3..7680d4fd233be498e81688d21e0a92c7151466c0 100644 (file)
@@ -64,7 +64,7 @@ pub(crate) unsafe fn codegen(
             llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
         }
         if tcx.sess.must_emit_unwind_tables() {
-            attributes::emit_uwtable(llfn, true);
+            attributes::emit_uwtable(llfn);
         }
 
         let callee = kind.fn_name(method.name);
@@ -111,7 +111,7 @@ pub(crate) unsafe fn codegen(
         llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
     }
     if tcx.sess.must_emit_unwind_tables() {
-        attributes::emit_uwtable(llfn, true);
+        attributes::emit_uwtable(llfn);
     }
 
     let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
index 7f82ce307d5263ba1f829fd9850fbccb021fcf64..30a52d6bd67fc5f49b51a223f4ac4b4f9302aa47 100644 (file)
@@ -59,8 +59,11 @@ pub fn sanitize<'ll>(cx: &CodegenCx<'ll, '_>, no_sanitize: SanitizerSet, llfn: &
 
 /// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function.
 #[inline]
-pub fn emit_uwtable(val: &Value, emit: bool) {
-    Attribute::UWTable.toggle_llfn(Function, val, emit);
+pub fn emit_uwtable(val: &Value) {
+    // NOTE: We should determine if we even need async unwind tables, as they
+    // take have more overhead and if we can use sync unwind tables we
+    // probably should.
+    llvm::EmitUWTableAttr(val, true);
 }
 
 /// Tell LLVM if this function should be 'naked', i.e., skip the epilogue and prologue.
@@ -275,7 +278,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     // You can also find more info on why Windows always requires uwtables here:
     //      https://bugzilla.mozilla.org/show_bug.cgi?id=1302078
     if cx.sess().must_emit_unwind_tables() {
-        attributes::emit_uwtable(llfn, true);
+        attributes::emit_uwtable(llfn);
     }
 
     if cx.sess().opts.debugging_opts.profile_sample_use.is_some() {
@@ -322,12 +325,33 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     // The target doesn't care; the subtarget reads our attribute.
     apply_tune_cpu_attr(cx, llfn);
 
-    let mut function_features = codegen_fn_attrs
-        .target_features
+    let function_features =
+        codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::<Vec<&str>>();
+
+    if let Some(f) = llvm_util::check_tied_features(
+        cx.tcx.sess,
+        &function_features.iter().map(|f| (*f, true)).collect(),
+    ) {
+        let span = cx
+            .tcx
+            .get_attrs(instance.def_id())
+            .iter()
+            .find(|a| a.has_name(rustc_span::sym::target_feature))
+            .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
+        let msg = format!(
+            "the target features {} must all be either enabled or disabled together",
+            f.join(", ")
+        );
+        let mut err = cx.tcx.sess.struct_span_err(span, &msg);
+        err.help("add the missing features in a `target_feature` attribute");
+        err.emit();
+        return;
+    }
+
+    let mut function_features = function_features
         .iter()
-        .flat_map(|f| {
-            let feature = f.as_str();
-            llvm_util::to_llvm_feature(cx.tcx.sess, feature)
+        .flat_map(|feat| {
+            llvm_util::to_llvm_feature(cx.tcx.sess, feat)
                 .into_iter()
                 .map(|f| format!("+{}", f))
                 .collect::<Vec<String>>()
index 5703a72c686e5bb3dc09e9d80aba617dbd7cd36f..21bd1dae7ac47161ccfbfe42c981b396a3b3933d 100644 (file)
@@ -27,7 +27,6 @@ pub struct LlvmArchiveBuilder<'a> {
     config: ArchiveConfig<'a>,
     removals: Vec<String>,
     additions: Vec<Addition>,
-    should_update_symbols: bool,
     src_archive: Option<Option<ArchiveRO>>,
 }
 
@@ -75,7 +74,6 @@ fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> LlvmArchiveBui
             config,
             removals: Vec::new(),
             additions: Vec::new(),
-            should_update_symbols: false,
             src_archive: None,
         }
     }
@@ -129,12 +127,6 @@ fn add_file(&mut self, file: &Path) {
             .push(Addition::File { path: file.to_path_buf(), name_in_archive: name.to_owned() });
     }
 
-    /// Indicate that the next call to `build` should update all symbols in
-    /// the archive (equivalent to running 'ar s' over it).
-    fn update_symbols(&mut self) {
-        self.should_update_symbols = true;
-    }
-
     /// Combine the provided files, rlibs, and native libraries into a single
     /// `Archive`.
     fn build(mut self) {
@@ -219,7 +211,7 @@ fn inject_dll_import_lib(
 
             match result {
                 Err(e) => {
-                    self.config.sess.fatal(&format!("Error calling dlltool: {}", e.to_string()));
+                    self.config.sess.fatal(&format!("Error calling dlltool: {}", e));
                 }
                 Ok(output) if !output.status.success() => self.config.sess.fatal(&format!(
                     "Dlltool could not create import library: {}\n{}",
@@ -313,7 +305,6 @@ fn build_with_llvm(&mut self, kind: ArchiveKind) -> io::Result<()> {
         let mut members = Vec::new();
 
         let dst = CString::new(self.config.dst.to_str().unwrap())?;
-        let should_update_symbols = self.should_update_symbols;
 
         unsafe {
             if let Some(archive) = self.src_archive() {
@@ -385,7 +376,7 @@ fn build_with_llvm(&mut self, kind: ArchiveKind) -> io::Result<()> {
                 dst.as_ptr(),
                 members.len() as libc::size_t,
                 members.as_ptr() as *const &_,
-                should_update_symbols,
+                true,
                 kind,
             );
             let ret = if r.into_result().is_err() {
index d43c7c606517927c6d84acee195540b0e2fdfdc1..6707de933522b4a569d77659125965981bb9cb9a 100644 (file)
@@ -522,6 +522,9 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
             }
 
             if attrs.flags.contains(CodegenFnAttrFlags::USED) {
+                // `USED` and `USED_LINKER` can't be used together.
+                assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER));
+
                 // The semantics of #[used] in Rust only require the symbol to make it into the
                 // object file. It is explicitly allowed for the linker to strip the symbol if it
                 // is dead. As such, use llvm.compiler.used instead of llvm.used.
@@ -530,6 +533,12 @@ fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
                 // in some versions of the gold linker.
                 self.add_compiler_used_global(g);
             }
+            if attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER) {
+                // `USED` and `USED_LINKER` can't be used together.
+                assert!(!attrs.flags.contains(CodegenFnAttrFlags::USED));
+
+                self.add_used_global(g);
+            }
         }
     }
 
index 8672459b5da3aae9191938309ca7e29808314256..ec68f6eb0f85dcd4d29b595231d3a7d94dcc6c13 100644 (file)
@@ -21,7 +21,8 @@
 };
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
-use rustc_session::config::{BranchProtection, CFGuard, CrateType, DebugInfo, PAuthKey, PacRet};
+use rustc_session::config::{BranchProtection, CFGuard, CFProtection};
+use rustc_session::config::{CrateType, DebugInfo, PAuthKey, PacRet};
 use rustc_session::Session;
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
@@ -134,7 +135,8 @@ pub unsafe fn create_module<'ll>(
     let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx);
 
     let mut target_data_layout = sess.target.data_layout.clone();
-    if llvm_util::get_version() < (13, 0, 0) {
+    let llvm_version = llvm_util::get_version();
+    if llvm_version < (13, 0, 0) {
         if sess.target.arch == "powerpc64" {
             target_data_layout = target_data_layout.replace("-S128", "");
         }
@@ -145,6 +147,18 @@ pub unsafe fn create_module<'ll>(
             target_data_layout = "e-m:e-p:64:64-i64:64-n32:64-S128".to_string();
         }
     }
+    if llvm_version < (14, 0, 0) {
+        if sess.target.llvm_target == "i686-pc-windows-msvc"
+            || sess.target.llvm_target == "i586-pc-windows-msvc"
+        {
+            target_data_layout =
+                "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:32-n8:16:32-a:0:32-S32"
+                    .to_string();
+        }
+        if sess.target.arch == "wasm32" {
+            target_data_layout = target_data_layout.replace("-p10:8:8-p20:8:8", "");
+        }
+    }
 
     // Ensure the data-layout values hardcoded remain the defaults.
     if sess.target.is_builtin {
@@ -287,6 +301,24 @@ pub unsafe fn create_module<'ll>(
         );
     }
 
+    // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang).
+    if let CFProtection::Branch | CFProtection::Full = sess.opts.debugging_opts.cf_protection {
+        llvm::LLVMRustAddModuleFlag(
+            llmod,
+            llvm::LLVMModFlagBehavior::Override,
+            "cf-protection-branch\0".as_ptr().cast(),
+            1,
+        )
+    }
+    if let CFProtection::Return | CFProtection::Full = sess.opts.debugging_opts.cf_protection {
+        llvm::LLVMRustAddModuleFlag(
+            llmod,
+            llvm::LLVMModFlagBehavior::Override,
+            "cf-protection-return\0".as_ptr().cast(),
+            1,
+        )
+    }
+
     llmod
 }
 
index 3014d2f1930eef5210cf4d4f9e0ccf1c4ea270cb..58f391692c49c109bb59b7011109403a09625943 100644 (file)
@@ -39,7 +39,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
     // LLVM 12.
     let version = coverageinfo::mapping_version();
     if version < 4 {
-        tcx.sess.fatal("rustc option `-Z instrument-coverage` requires LLVM 12 or higher.");
+        tcx.sess.fatal("rustc option `-C instrument-coverage` requires LLVM 12 or higher.");
     }
 
     debug!("Generating coverage map for CodegenUnit: `{}`", cx.codegen_unit.name());
@@ -274,7 +274,7 @@ fn save_function_record(
 /// (functions referenced by other "used" or public items). Any other functions considered unused,
 /// or "Unreachable", were still parsed and processed through the MIR stage, but were not
 /// codegenned. (Note that `-Clink-dead-code` can force some unused code to be codegenned, but
-/// that flag is known to cause other errors, when combined with `-Z instrument-coverage`; and
+/// that flag is known to cause other errors, when combined with `-C instrument-coverage`; and
 /// `-Clink-dead-code` will not generate code for unused generic functions.)
 ///
 /// We can find the unused functions (including generic functions) by the set difference of all MIR
index 1266b540aaeb15377ed3c177c38b40404ce648b6..1abc3fb523d1bce25955f2790d6df5a1961f2a6d 100644 (file)
@@ -21,6 +21,7 @@
 
 use cstr::cstr;
 use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo;
+use rustc_codegen_ssa::debuginfo::type_names::VTableNameKind;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
@@ -184,9 +185,9 @@ fn register_type_with_metadata(&mut self, type_: Ty<'tcx>, metadata: &'ll DIType
     ///
     /// This function is used to remove the temporary metadata
     /// mapping after we've computed the actual metadata.
-    fn remove_type(&mut self, type_: Ty<'tcx>) {
-        if self.type_to_metadata.remove(type_).is_none() {
-            bug!("type metadata `Ty` '{}' is not in the `TypeMap`!", type_);
+    fn remove_type(&mut self, ty: Ty<'tcx>) {
+        if self.type_to_metadata.remove(&ty).is_none() {
+            bug!("type metadata `Ty` '{}' is not in the `TypeMap`!", ty);
         }
     }
 
@@ -276,6 +277,12 @@ fn get_unique_type_id_str_of_enum_variant_part(
     ) -> String {
         format!("{}_variant_part", self.get_unique_type_id_as_string(enum_type_id))
     }
+
+    /// Gets the `UniqueTypeId` for the type of a vtable.
+    fn get_unique_type_id_of_vtable_type(&mut self, vtable_type_name: &str) -> UniqueTypeId {
+        let interner_key = self.unique_id_interner.intern(vtable_type_name);
+        interner_key
+    }
 }
 
 /// A description of some recursive type. It can either be already finished (as
@@ -351,14 +358,15 @@ fn finalize(&self, cx: &CodegenCx<'ll, 'tcx>) -> MetadataCreationResult<'ll> {
 
                 // ... then create the member descriptions ...
                 let member_descriptions = member_description_factory.create_member_descriptions(cx);
+                let type_params = compute_type_parameters(cx, unfinished_type);
 
                 // ... and attach them to the stub to complete it.
                 set_members_of_composite_type(
                     cx,
-                    unfinished_type,
                     member_holding_stub,
                     member_descriptions,
                     None,
+                    type_params,
                 );
                 MetadataCreationResult::new(metadata_stub, true)
             }
@@ -389,7 +397,7 @@ fn fixed_size_array_metadata<'ll, 'tcx>(
         bug!("fixed_size_array_metadata() called with non-ty::Array type `{:?}`", array_type)
     };
 
-    let element_type_metadata = type_metadata(cx, element_type);
+    let element_type_metadata = type_metadata(cx, *element_type);
 
     return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
@@ -538,7 +546,7 @@ fn subroutine_type_metadata<'ll, 'tcx>(
     )
     .chain(
         // regular arguments
-        signature.inputs().iter().map(|argument_type| Some(type_metadata(cx, argument_type))),
+        signature.inputs().iter().map(|&argument_type| Some(type_metadata(cx, argument_type))),
     )
     .collect();
 
@@ -593,7 +601,7 @@ fn slice_type_metadata<'ll, 'tcx>(
     unique_type_id: UniqueTypeId,
 ) -> MetadataCreationResult<'ll> {
     let element_type = match slice_type.kind() {
-        ty::Slice(element_type) => element_type,
+        ty::Slice(element_type) => *element_type,
         ty::Str => cx.tcx.types.u8,
         _ => {
             bug!(
@@ -983,7 +991,17 @@ fn foreign_type_metadata<'ll, 'tcx>(
     debug!("foreign_type_metadata: {:?}", t);
 
     let name = compute_debuginfo_type_name(cx.tcx, t, false);
-    create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero)
+    let (size, align) = cx.size_and_align_of(t);
+    create_struct_stub(
+        cx,
+        size,
+        align,
+        &name,
+        unique_type_id,
+        NO_SCOPE_METADATA,
+        DIFlags::FlagZero,
+        None,
+    )
 }
 
 fn param_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
@@ -1299,14 +1317,17 @@ fn prepare_struct_metadata<'ll, 'tcx>(
     };
 
     let containing_scope = get_namespace_for_item(cx, struct_def_id);
+    let (size, align) = cx.size_and_align_of(struct_type);
 
     let struct_metadata_stub = create_struct_stub(
         cx,
-        struct_type,
+        size,
+        align,
         &struct_name,
         unique_type_id,
         Some(containing_scope),
         DIFlags::FlagZero,
+        None,
     );
 
     create_and_register_recursive_type_forward_declaration(
@@ -1398,15 +1419,18 @@ fn prepare_tuple_metadata<'ll, 'tcx>(
     unique_type_id: UniqueTypeId,
     containing_scope: Option<&'ll DIScope>,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
+    let (size, align) = cx.size_and_align_of(tuple_type);
     let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false);
 
     let struct_stub = create_struct_stub(
         cx,
-        tuple_type,
+        size,
+        align,
         &tuple_name[..],
         unique_type_id,
         containing_scope,
         DIFlags::FlagZero,
+        None,
     );
 
     create_and_register_recursive_type_forward_declaration(
@@ -1581,13 +1605,14 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                     describe_enum_variant(cx, self.layout, variant_info, self_metadata);
 
                 let member_descriptions = member_description_factory.create_member_descriptions(cx);
+                let type_params = compute_type_parameters(cx, self.enum_type);
 
                 set_members_of_composite_type(
                     cx,
-                    self.enum_type,
                     variant_type_metadata,
                     member_descriptions,
                     Some(&self.common_members),
+                    type_params,
                 );
                 vec![MemberDescription {
                     name: variant_info.variant_name(),
@@ -1648,13 +1673,14 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
 
                         let member_descriptions =
                             member_desc_factory.create_member_descriptions(cx);
+                        let type_params = compute_type_parameters(cx, self.enum_type);
 
                         set_members_of_composite_type(
                             cx,
-                            self.enum_type,
                             variant_type_metadata,
                             member_descriptions,
                             Some(&self.common_members),
+                            type_params,
                         );
 
                         MemberDescription {
@@ -1777,13 +1803,14 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                     );
 
                     let member_descriptions = member_desc_factory.create_member_descriptions(cx);
+                    let type_params = compute_type_parameters(cx, self.enum_type);
 
                     set_members_of_composite_type(
                         cx,
-                        self.enum_type,
                         variant_type_metadata,
                         member_descriptions,
                         Some(&self.common_members),
+                        type_params,
                     );
 
                     let (size, align) =
@@ -1823,13 +1850,14 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
 
                             let member_descriptions =
                                 member_desc_factory.create_member_descriptions(cx);
+                            let type_params = compute_type_parameters(cx, self.enum_type);
 
                             set_members_of_composite_type(
                                 cx,
-                                self.enum_type,
                                 variant_type_metadata,
                                 member_descriptions,
                                 Some(&self.common_members),
+                                type_params,
                             );
 
                             let niche_value = calculate_niche_value(i);
@@ -1965,13 +1993,18 @@ fn describe_enum_variant<'ll, 'tcx>(
             .type_map
             .borrow_mut()
             .get_unique_type_id_of_enum_variant(cx, layout.ty, variant_name);
+
+        let (size, align) = cx.size_and_align_of(layout.ty);
+
         create_struct_stub(
             cx,
-            layout.ty,
+            size,
+            align,
             variant_name,
             unique_type_id,
             Some(containing_scope),
             DIFlags::FlagZero,
+            None,
         )
     });
 
@@ -2308,22 +2341,27 @@ fn composite_type_metadata<'ll, 'tcx>(
     member_descriptions: Vec<MemberDescription<'ll>>,
     containing_scope: Option<&'ll DIScope>,
 ) -> &'ll DICompositeType {
+    let (size, align) = cx.size_and_align_of(composite_type);
+
     // Create the (empty) struct metadata node ...
     let composite_type_metadata = create_struct_stub(
         cx,
-        composite_type,
+        size,
+        align,
         composite_type_name,
         composite_type_unique_id,
         containing_scope,
         DIFlags::FlagZero,
+        None,
     );
+
     // ... and immediately create and add the member descriptions.
     set_members_of_composite_type(
         cx,
-        composite_type,
         composite_type_metadata,
         member_descriptions,
         None,
+        compute_type_parameters(cx, composite_type),
     );
 
     composite_type_metadata
@@ -2331,10 +2369,10 @@ fn composite_type_metadata<'ll, 'tcx>(
 
 fn set_members_of_composite_type<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
-    composite_type: Ty<'tcx>,
     composite_type_metadata: &'ll DICompositeType,
     member_descriptions: Vec<MemberDescription<'ll>>,
     common_members: Option<&Vec<Option<&'ll DIType>>>,
+    type_params: &'ll DIArray,
 ) {
     // In some rare cases LLVM metadata uniquing would lead to an existing type
     // description being used instead of a new one created in
@@ -2361,13 +2399,12 @@ fn set_members_of_composite_type<'ll, 'tcx>(
         member_metadata.extend(other_members.iter());
     }
 
-    let type_params = compute_type_parameters(cx, composite_type);
     unsafe {
-        let type_array = create_DIArray(DIB(cx), &member_metadata);
+        let field_array = create_DIArray(DIB(cx), &member_metadata);
         llvm::LLVMRustDICompositeTypeReplaceArrays(
             DIB(cx),
             composite_type_metadata,
-            Some(type_array),
+            Some(field_array),
             Some(type_params),
         );
     }
@@ -2420,14 +2457,14 @@ fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<S
 /// with `set_members_of_composite_type()`.
 fn create_struct_stub<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
-    struct_type: Ty<'tcx>,
-    struct_type_name: &str,
+    size: Size,
+    align: Align,
+    type_name: &str,
     unique_type_id: UniqueTypeId,
     containing_scope: Option<&'ll DIScope>,
     flags: DIFlags,
+    vtable_holder: Option<&'ll DIType>,
 ) -> &'ll DICompositeType {
-    let (struct_size, struct_align) = cx.size_and_align_of(struct_type);
-
     let type_map = debug_context(cx).type_map.borrow();
     let unique_type_id = type_map.get_unique_type_id_as_string(unique_type_id);
 
@@ -2440,17 +2477,17 @@ fn create_struct_stub<'ll, 'tcx>(
         llvm::LLVMRustDIBuilderCreateStructType(
             DIB(cx),
             containing_scope,
-            struct_type_name.as_ptr().cast(),
-            struct_type_name.len(),
+            type_name.as_ptr().cast(),
+            type_name.len(),
             unknown_file_metadata(cx),
             UNKNOWN_LINE_NUMBER,
-            struct_size.bits(),
-            struct_align.bits() as u32,
+            size.bits(),
+            align.bits() as u32,
             flags,
             None,
             empty_array,
             0,
-            None,
+            vtable_holder,
             unique_type_id.as_ptr().cast(),
             unique_type_id.len(),
         )
@@ -2556,6 +2593,14 @@ pub fn create_global_var_metadata<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, g
 }
 
 /// Generates LLVM debuginfo for a vtable.
+///
+/// The vtable type looks like a struct with a field for each function pointer and super-trait
+/// pointer it contains (plus the `size` and `align` fields).
+///
+/// Except for `size`, `align`, and `drop_in_place`, the field names don't try to mirror
+/// the name of the method they implement. This can be implemented in the future once there
+/// is a proper disambiguation scheme for dealing with methods from different traits that have
+/// the same name.
 fn vtable_type_metadata<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     ty: Ty<'tcx>,
@@ -2572,16 +2617,81 @@ fn vtable_type_metadata<'ll, 'tcx>(
         COMMON_VTABLE_ENTRIES
     };
 
-    // FIXME: We describe the vtable as an array of *const () pointers. The length of the array is
-    //        correct - but we could create a more accurate description, e.g. by describing it
-    //        as a struct where each field has a name that corresponds to the name of the method
-    //        it points to.
-    //        However, this is not entirely straightforward because there might be multiple
-    //        methods with the same name if the vtable is for multiple traits. So for now we keep
-    //        things simple instead of adding some ad-hoc disambiguation scheme.
-    let vtable_type = tcx.mk_array(tcx.mk_imm_ptr(tcx.types.unit), vtable_entries.len() as u64);
+    // All function pointers are described as opaque pointers. This could be improved in the future
+    // by describing them as actual function pointers.
+    let void_pointer_ty = tcx.mk_imm_ptr(tcx.types.unit);
+    let void_pointer_type_debuginfo = type_metadata(cx, void_pointer_ty);
+    let usize_debuginfo = type_metadata(cx, tcx.types.usize);
+    let (pointer_size, pointer_align) = cx.size_and_align_of(void_pointer_ty);
+    // If `usize` is not pointer-sized and -aligned then the size and alignment computations
+    // for the vtable as a whole would be wrong. Let's make sure this holds even on weird
+    // platforms.
+    assert_eq!(cx.size_and_align_of(tcx.types.usize), (pointer_size, pointer_align));
+
+    let vtable_type_name =
+        compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::Type);
+    let unique_type_id = debug_context(cx)
+        .type_map
+        .borrow_mut()
+        .get_unique_type_id_of_vtable_type(&vtable_type_name);
+    let size = pointer_size * vtable_entries.len() as u64;
+
+    // This gets mapped to a DW_AT_containing_type attribute which allows GDB to correlate
+    // the vtable to the type it is for.
+    let vtable_holder = type_metadata(cx, ty);
+
+    let vtable_type_metadata = create_struct_stub(
+        cx,
+        size,
+        pointer_align,
+        &vtable_type_name,
+        unique_type_id,
+        NO_SCOPE_METADATA,
+        DIFlags::FlagArtificial,
+        Some(vtable_holder),
+    );
+
+    // Create a field for each entry in the vtable.
+    let fields: Vec<_> = vtable_entries
+        .iter()
+        .enumerate()
+        .filter_map(|(index, vtable_entry)| {
+            let (field_name, field_type) = match vtable_entry {
+                ty::VtblEntry::MetadataDropInPlace => {
+                    ("drop_in_place".to_string(), void_pointer_type_debuginfo)
+                }
+                ty::VtblEntry::Method(_) => {
+                    // Note: This code does not try to give a proper name to each method
+                    //       because there might be multiple methods with the same name
+                    //       (coming from different traits).
+                    (format!("__method{}", index), void_pointer_type_debuginfo)
+                }
+                ty::VtblEntry::TraitVPtr(_) => {
+                    // Note: In the future we could try to set the type of this pointer
+                    //       to the type that we generate for the corresponding vtable.
+                    (format!("__super_trait_ptr{}", index), void_pointer_type_debuginfo)
+                }
+                ty::VtblEntry::MetadataAlign => ("align".to_string(), usize_debuginfo),
+                ty::VtblEntry::MetadataSize => ("size".to_string(), usize_debuginfo),
+                ty::VtblEntry::Vacant => return None,
+            };
+
+            Some(MemberDescription {
+                name: field_name,
+                type_metadata: field_type,
+                offset: pointer_size * index as u64,
+                size: pointer_size,
+                align: pointer_align,
+                flags: DIFlags::FlagZero,
+                discriminant: None,
+                source_info: None,
+            })
+        })
+        .collect();
 
-    type_metadata(cx, vtable_type)
+    let type_params = create_DIArray(DIB(cx), &[]);
+    set_members_of_composite_type(cx, vtable_type_metadata, fields, None, type_params);
+    vtable_type_metadata
 }
 
 /// Creates debug information for the given vtable, which is for the
@@ -2603,11 +2713,12 @@ pub fn create_vtable_metadata<'ll, 'tcx>(
         return;
     }
 
-    let vtable_name = compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref);
+    let vtable_name =
+        compute_debuginfo_vtable_name(cx.tcx, ty, poly_trait_ref, VTableNameKind::GlobalVariable);
     let vtable_type = vtable_type_metadata(cx, ty, poly_trait_ref);
+    let linkage_name = "";
 
     unsafe {
-        let linkage_name = "";
         llvm::LLVMRustDIBuilderCreateStaticVariable(
             DIB(cx),
             NO_SCOPE_METADATA,
index 6bc7d8518dc96d0204f4e5e66c2b1a2a2c90b95b..247cb9ee6e8c9f2e475a4c70238b9f4bdd02437a 100644 (file)
@@ -430,9 +430,9 @@ fn get_function_signature<'ll, 'tcx>(
                     let t = arg.layout.ty;
                     let t = match t.kind() {
                         ty::Array(ct, _)
-                            if (*ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() =>
+                            if (*ct == cx.tcx.types.u8) || cx.layout_of(*ct).is_zst() =>
                         {
-                            cx.tcx.mk_imm_ptr(ct)
+                            cx.tcx.mk_imm_ptr(*ct)
                         }
                         _ => t,
                     };
index f51d014bfb39a97f2af4c07efccff68fe5771af8..cfd23f5c24e05a817234a0463d4073bdf1b041af 100644 (file)
@@ -1132,8 +1132,8 @@ macro_rules! require_simd {
 
     fn simd_simple_float_intrinsic<'ll, 'tcx>(
         name: Symbol,
-        in_elem: &::rustc_middle::ty::TyS<'_>,
-        in_ty: &::rustc_middle::ty::TyS<'_>,
+        in_elem: Ty<'_>,
+        in_ty: Ty<'_>,
         in_len: u64,
         bx: &mut Builder<'_, 'll, 'tcx>,
         span: Span,
index 2b102188790389dc86445e6be4393ca049f62350..90d4367a280a48fc34642a1e63dc36fec21b2f23 100644 (file)
@@ -189,6 +189,7 @@ pub enum Attribute {
     StackProtectReq = 30,
     StackProtectStrong = 31,
     StackProtect = 32,
+    NoUndef = 33,
 }
 
 /// LLVMIntPredicate
@@ -987,6 +988,7 @@ pub fn from_generic(kind: rustc_session::config::DebugInfo) -> Self {
 
 extern "C" {
     pub fn LLVMRustInstallFatalErrorHandler();
+    pub fn LLVMRustDisableSystemDialogsOnCrash();
 
     // Create and destroy contexts.
     pub fn LLVMRustContextCreate(shouldDiscardNames: bool) -> &'static mut Context;
@@ -1180,6 +1182,7 @@ pub fn LLVMRustGetOrInsertFunction<'a>(
     pub fn LLVMRustAddByValAttr(Fn: &Value, index: c_uint, ty: &Type);
     pub fn LLVMRustAddStructRetAttr(Fn: &Value, index: c_uint, ty: &Type);
     pub fn LLVMRustAddFunctionAttribute(Fn: &Value, index: c_uint, attr: Attribute);
+    pub fn LLVMRustEmitUWTableAttr(Fn: &Value, async_: bool);
     pub fn LLVMRustAddFunctionAttrStringValue(
         Fn: &Value,
         index: c_uint,
index a1117a11fc7cea9d69d82b89ef9b9b410488b909..8586b0466c8d0208d51b17d0a4517ba20c388893 100644 (file)
@@ -31,6 +31,10 @@ pub fn into_result(self) -> Result<(), ()> {
     }
 }
 
+pub fn EmitUWTableAttr(llfn: &Value, async_: bool) {
+    unsafe { LLVMRustEmitUWTableAttr(llfn, async_) }
+}
+
 pub fn AddFunctionAttrStringValue(llfn: &Value, idx: AttributePlace, attr: &CStr, value: &CStr) {
     unsafe {
         LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), value.as_ptr())
index d49df29f4534ec173fe60c0295bc20fae74c13fb..b1c14c7e44bd0031a6d75e6ca0723bbac6af7e97 100644 (file)
@@ -2,8 +2,8 @@
 use crate::{llvm, llvm_util};
 use libc::c_int;
 use libloading::Library;
-use rustc_codegen_ssa::target_features::supported_target_features;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_codegen_ssa::target_features::{supported_target_features, tied_target_features};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_fs_util::path_to_c_string;
 use rustc_middle::bug;
 use rustc_session::config::PrintRequest;
@@ -46,6 +46,12 @@ unsafe fn configure_llvm(sess: &Session) {
     let mut llvm_args = Vec::with_capacity(n_args + 1);
 
     llvm::LLVMRustInstallFatalErrorHandler();
+    // On Windows, an LLVM assertion will open an Abort/Retry/Ignore dialog
+    // box for the purpose of launching a debugger. However, on CI this will
+    // cause it to hang until it times out, which can take several hours.
+    if std::env::var_os("CI").is_some() {
+        llvm::LLVMRustDisableSystemDialogsOnCrash();
+    }
 
     fn llvm_arg_to_arg_name(full_arg: &str) -> &str {
         full_arg.trim().split(|c: char| c == '=' || c.is_whitespace()).next().unwrap_or("")
@@ -185,30 +191,58 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> Vec<&'a str> {
         ("aarch64", "frintts") => vec!["fptoint"],
         ("aarch64", "fcma") => vec!["complxnum"],
         ("aarch64", "pmuv3") => vec!["perfmon"],
+        ("aarch64", "paca") => vec!["pauth"],
+        ("aarch64", "pacg") => vec!["pauth"],
         (_, s) => vec![s],
     }
 }
 
+// Given a map from target_features to whether they are enabled or disabled,
+// ensure only valid combinations are allowed.
+pub fn check_tied_features(
+    sess: &Session,
+    features: &FxHashMap<&str, bool>,
+) -> Option<&'static [&'static str]> {
+    for tied in tied_target_features(sess) {
+        // Tied features must be set to the same value, or not set at all
+        let mut tied_iter = tied.iter();
+        let enabled = features.get(tied_iter.next().unwrap());
+
+        if tied_iter.any(|f| enabled != features.get(f)) {
+            return Some(tied);
+        }
+    }
+    None
+}
+
 pub fn target_features(sess: &Session) -> Vec<Symbol> {
     let target_machine = create_informational_target_machine(sess);
-    supported_target_features(sess)
-        .iter()
-        .filter_map(
-            |&(feature, gate)| {
+    let mut features: Vec<Symbol> =
+        supported_target_features(sess)
+            .iter()
+            .filter_map(|&(feature, gate)| {
                 if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
-            },
-        )
-        .filter(|feature| {
-            for llvm_feature in to_llvm_feature(sess, feature) {
-                let cstr = CString::new(llvm_feature).unwrap();
-                if unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } {
-                    return true;
+            })
+            .filter(|feature| {
+                for llvm_feature in to_llvm_feature(sess, feature) {
+                    let cstr = CString::new(llvm_feature).unwrap();
+                    if unsafe { llvm::LLVMRustHasFeature(target_machine, cstr.as_ptr()) } {
+                        return true;
+                    }
                 }
-            }
-            false
-        })
-        .map(|feature| Symbol::intern(feature))
-        .collect()
+                false
+            })
+            .map(|feature| Symbol::intern(feature))
+            .collect();
+
+    // LLVM 14 changed the ABI for i128 arguments to __float/__fix builtins on Win64
+    // (see https://reviews.llvm.org/D110413). This unstable target feature is intended for use
+    // by compiler-builtins, to export the builtins with the expected, LLVM-version-dependent ABI.
+    // The target feature can be dropped once we no longer support older LLVM versions.
+    if sess.is_nightly_build() && get_version() >= (14, 0, 0) {
+        features.push(Symbol::intern("llvm14-builtins-abi"));
+    }
+    features
 }
 
 pub fn print_version() {
@@ -389,15 +423,19 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> {
         Some(_) | None => {}
     };
 
+    fn strip(s: &str) -> &str {
+        s.strip_prefix(&['+', '-']).unwrap_or(s)
+    }
+
     let filter = |s: &str| {
         if s.is_empty() {
             return vec![];
         }
-        let feature = if s.starts_with('+') || s.starts_with('-') {
-            &s[1..]
-        } else {
+        let feature = strip(s);
+        if feature == s {
             return vec![s.to_string()];
-        };
+        }
+
         // Rustc-specific feature requests like `+crt-static` or `-crt-static`
         // are not passed down to LLVM.
         if RUSTC_SPECIFIC_FEATURES.contains(&feature) {
@@ -414,8 +452,17 @@ pub fn llvm_global_features(sess: &Session) -> Vec<String> {
     features.extend(sess.target.features.split(',').flat_map(&filter));
 
     // -Ctarget-features
-    features.extend(sess.opts.cg.target_feature.split(',').flat_map(&filter));
-
+    let feats: Vec<&str> = sess.opts.cg.target_feature.split(',').collect();
+    // LLVM enables based on the last occurence of a feature
+    if let Some(f) =
+        check_tied_features(sess, &feats.iter().map(|f| (strip(f), !f.starts_with("-"))).collect())
+    {
+        sess.err(&format!(
+            "Target features {} must all be enabled or disabled together",
+            f.join(", ")
+        ));
+    }
+    features.extend(feats.iter().flat_map(|&f| filter(f)));
     features
 }
 
index 81d0603bc5200f16c10637bcf205d50d8286d29a..fafb9a6dbdeccf88c6f80bbd6416352de8f46301 100644 (file)
@@ -330,7 +330,9 @@ fn scalar_pair_element_llvm_type<'a>(
             ty::Ref(..) | ty::RawPtr(_) => {
                 return self.field(cx, index).llvm_type(cx);
             }
-            ty::Adt(def, _) if def.is_box() => {
+            // only wide pointer boxes are handled as pointers
+            // thin pointer boxes with scalar allocators are handled by the general logic below
+            ty::Adt(def, substs) if def.is_box() && cx.layout_of(substs.type_at(1)).is_zst() => {
                 let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
                 return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
             }
index 3db948a16fc738c74b66a6ee3712876ffc4fc180..a2f74b9421468105e76a59d75c645a5034b9a6be 100644 (file)
@@ -51,7 +51,6 @@ pub trait ArchiveBuilder<'a> {
     fn add_archive<F>(&mut self, archive: &Path, skip: F) -> io::Result<()>
     where
         F: FnMut(&str) -> bool + 'static;
-    fn update_symbols(&mut self);
 
     fn build(self);
 
index 7a13e424f9aca31be604fbbc44f522c2f4b302db..58e0667d678986abd01f903d46d2242da324f1c4 100644 (file)
@@ -216,17 +216,18 @@ pub fn each_linked_rlib(
         }
         let name = &info.crate_name[&cnum];
         let used_crate_source = &info.used_crate_source[&cnum];
-        let path = if let Some((path, _)) = &used_crate_source.rlib {
-            path
-        } else if used_crate_source.rmeta.is_some() {
-            return Err(format!(
-                "could not find rlib for: `{}`, found rmeta (metadata) file",
-                name
-            ));
+        if let Some((path, _)) = &used_crate_source.rlib {
+            f(cnum, &path);
         } else {
-            return Err(format!("could not find rlib for: `{}`", name));
-        };
-        f(cnum, &path);
+            if used_crate_source.rmeta.is_some() {
+                return Err(format!(
+                    "could not find rlib for: `{}`, found rmeta (metadata) file",
+                    name
+                ));
+            } else {
+                return Err(format!("could not find rlib for: `{}`", name));
+            }
+        }
     }
     Ok(())
 }
@@ -333,10 +334,6 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
         ab.inject_dll_import_lib(&raw_dylib_name, &raw_dylib_imports, tmpdir);
     }
 
-    // After adding all files to the archive, we need to update the
-    // symbol table of the archive.
-    ab.update_symbols();
-
     // Note that it is important that we add all of our non-object "magical
     // files" *after* all of the object files in the archive. The reason for
     // this is as follows:
@@ -365,13 +362,6 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
             // normal linkers for the platform.
             let metadata = create_rmeta_file(sess, codegen_results.metadata.raw_data());
             ab.add_file(&emit_metadata(sess, &metadata, tmpdir));
-
-            // After adding all files to the archive, we need to update the
-            // symbol table of the archive. This currently dies on macOS (see
-            // #11162), and isn't necessary there anyway
-            if !sess.target.is_like_osx {
-                ab.update_symbols();
-            }
         }
 
         RlibFlavor::StaticlibBase => {
@@ -381,6 +371,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
             }
         }
     }
+
     return Ok(ab);
 }
 
@@ -509,7 +500,6 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(
         sess.fatal(&e);
     }
 
-    ab.update_symbols();
     ab.build();
 
     if !all_native_libs.is_empty() {
@@ -2310,7 +2300,6 @@ fn add_static_crate<'a, B: ArchiveBuilder<'a>>(
 
         sess.prof.generic_activity_with_arg("link_altering_rlib", name).run(|| {
             let mut archive = <B as ArchiveBuilder>::new(sess, &dst, Some(cratepath));
-            archive.update_symbols();
 
             let mut any_objects = false;
             for f in archive.src_files() {
index 6849533abc049e7098e8ee154b08bb23d1ed3f9d..9ebbcac76a28a45f0ac3f6d8f12ad02cee25d3dd 100644 (file)
@@ -200,9 +200,7 @@ fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
 //   `SHF_EXCLUDE` flag we can set on sections in an object file to get
 //   automatically removed from the final output.
 pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
-    let mut file = if let Some(file) = create_object_file(sess) {
-        file
-    } else {
+    let Some(mut file) = create_object_file(sess) else {
         // This is used to handle all "other" targets. This includes targets
         // in two categories:
         //
@@ -262,9 +260,7 @@ pub fn create_compressed_metadata_file(
 ) -> Vec<u8> {
     let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
     FrameEncoder::new(&mut compressed).write_all(metadata.raw_data()).unwrap();
-    let mut file = if let Some(file) = create_object_file(sess) {
-        file
-    } else {
+    let Some(mut file) = create_object_file(sess) else {
         return compressed.to_vec();
     };
     let section = file.add_section(
index 540979ce02d8fde47e148478b5cfb5d34c7ff466..f6fddbb509dc8a90404fee0d2c3208c4293fcd5a 100644 (file)
@@ -477,7 +477,7 @@ pub fn start_async_codegen<B: ExtraBackendMethods>(
         codegen_worker_receive,
         shared_emitter_main,
         future: coordinator_thread,
-        output_filenames: tcx.output_filenames(()),
+        output_filenames: tcx.output_filenames(()).clone(),
     }
 }
 
@@ -1050,7 +1050,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(),
         coordinator_send,
         diag_emitter: shared_emitter.clone(),
-        output_filenames: tcx.output_filenames(()),
+        output_filenames: tcx.output_filenames(()).clone(),
         regular_module_config: regular_config,
         metadata_module_config: metadata_config,
         allocator_module_config: allocator_config,
index 49b785afa69e9ab5435924fc85df171455aa61fb..4a5eabc87554cb67ba05ac51d393bf8794291836 100644 (file)
@@ -843,7 +843,7 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
             used_crate_source: Default::default(),
             lang_item_to_crate: Default::default(),
             missing_lang_items: Default::default(),
-            dependency_formats: tcx.dependency_formats(()),
+            dependency_formats: tcx.dependency_formats(()).clone(),
             windows_subsystem,
         };
         let lang_items = tcx.lang_items();
@@ -860,7 +860,7 @@ pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo {
             info.native_libraries
                 .insert(cnum, tcx.native_libraries(cnum).iter().map(Into::into).collect());
             info.crate_name.insert(cnum, tcx.crate_name(cnum).to_string());
-            info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum));
+            info.used_crate_source.insert(cnum, tcx.used_crate_source(cnum).clone());
             if tcx.is_compiler_builtins(cnum) {
                 info.compiler_builtins = Some(cnum);
             }
index 831c34d8f1f604fdd232d18c4605294088697146..b63851c195de6df091bed7ed0d4627ee3bb736ac 100644 (file)
@@ -146,7 +146,7 @@ fn push_debuginfo_type_name<'tcx>(
             if cpp_like_debuginfo {
                 output.push_str("array$<");
                 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
-                match len.val {
+                match len.val() {
                     ty::ConstKind::Param(param) => write!(output, ",{}>", param.name).unwrap(),
                     _ => write!(output, ",{}>", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
                         .unwrap(),
@@ -154,7 +154,7 @@ fn push_debuginfo_type_name<'tcx>(
             } else {
                 output.push('[');
                 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
-                match len.val {
+                match len.val() {
                     ty::ConstKind::Param(param) => write!(output, "; {}]", param.name).unwrap(),
                     _ => write!(output, "; {}]", len.eval_usize(tcx, ty::ParamEnv::reveal_all()))
                         .unwrap(),
@@ -343,7 +343,7 @@ fn push_debuginfo_type_name<'tcx>(
             // We only care about avoiding recursing
             // directly back to the type we're currently
             // processing
-            visited.remove(t);
+            visited.remove(&t);
         }
         ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => {
             // Name will be "{closure_env#0}<T1, T2, ...>", "{generator_env#0}<T1, T2, ...>", or
@@ -469,7 +469,14 @@ fn pop_auto_trait_separator(output: &mut String) {
     }
 }
 
-/// Computes a name for the global variable storing a vtable.
+pub enum VTableNameKind {
+    // Is the name for the const/static holding the vtable?
+    GlobalVariable,
+    // Is the name for the type of the vtable?
+    Type,
+}
+
+/// Computes a name for the global variable storing a vtable (or the type of that global variable).
 ///
 /// The name is of the form:
 ///
@@ -478,10 +485,15 @@ fn pop_auto_trait_separator(output: &mut String) {
 /// or, when generating C++-like names:
 ///
 /// `impl$<path::to::SomeType, path::to::SomeTrait>::vtable$`
+///
+/// If `kind` is `VTableNameKind::Type` then the last component is `{vtable_ty}` instead of just
+/// `{vtable}`, so that the type and the corresponding global variable get assigned different
+/// names.
 pub fn compute_debuginfo_vtable_name<'tcx>(
     tcx: TyCtxt<'tcx>,
     t: Ty<'tcx>,
     trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
+    kind: VTableNameKind,
 ) -> String {
     let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
 
@@ -514,7 +526,12 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
 
     push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name);
 
-    let suffix = if cpp_like_debuginfo { "::vtable$" } else { "::{vtable}" };
+    let suffix = match (cpp_like_debuginfo, kind) {
+        (true, VTableNameKind::GlobalVariable) => "::vtable$",
+        (false, VTableNameKind::GlobalVariable) => "::{vtable}",
+        (true, VTableNameKind::Type) => "::vtable_type$",
+        (false, VTableNameKind::Type) => "::{vtable_type}",
+    };
 
     vtable_name.reserve_exact(suffix.len());
     vtable_name.push_str(suffix);
@@ -628,19 +645,19 @@ fn push_generic_params_internal<'tcx>(
     true
 }
 
-fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output: &mut String) {
-    match ct.val {
+fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut String) {
+    match ct.val() {
         ty::ConstKind::Param(param) => {
             write!(output, "{}", param.name)
         }
-        _ => match ct.ty.kind() {
+        _ => match ct.ty().kind() {
             ty::Int(ity) => {
-                let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty);
+                let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
                 let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
                 write!(output, "{}", val)
             }
             ty::Uint(_) => {
-                let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty);
+                let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
                 write!(output, "{}", val)
             }
             ty::Bool => {
@@ -655,7 +672,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output:
                 let mut hasher = StableHasher::new();
                 hcx.while_hashing_spans(false, |hcx| {
                     hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
-                        ct.val.hash_stable(hcx, &mut hasher);
+                        ct.val().hash_stable(hcx, &mut hasher);
                     });
                 });
                 // Let's only emit 64 bits of the hash value. That should be plenty for
index 93b39dc8e9ee102c8015ca4b21ebfd9f5c5d5fd1..5cdf131b0b633d5d211807479befb4e09c1ab505 100644 (file)
@@ -29,7 +29,7 @@ pub fn eval_mir_constant(
             mir::ConstantKind::Ty(ct) => ct,
             mir::ConstantKind::Val(val, _) => return Ok(val),
         };
-        match ct.val {
+        match ct.val() {
             ty::ConstKind::Unevaluated(ct) => self
                 .cx
                 .tcx()
@@ -61,11 +61,11 @@ pub fn simd_shuffle_indices(
                 let c = ty::Const::from_value(bx.tcx(), val, ty);
                 let values: Vec<_> = bx
                     .tcx()
-                    .destructure_const(ty::ParamEnv::reveal_all().and(&c))
+                    .destructure_const(ty::ParamEnv::reveal_all().and(c))
                     .fields
                     .iter()
                     .map(|field| {
-                        if let Some(prim) = field.val.try_to_scalar() {
+                        if let Some(prim) = field.val().try_to_scalar() {
                             let layout = bx.layout_of(field_ty);
                             let scalar = match layout.abi {
                                 Abi::Scalar(x) => x,
@@ -78,7 +78,7 @@ pub fn simd_shuffle_indices(
                     })
                     .collect();
                 let llval = bx.const_struct(&values, false);
-                (llval, c.ty)
+                (llval, c.ty())
             })
             .unwrap_or_else(|_| {
                 bx.tcx().sess.span_err(span, "could not evaluate shuffle_indices at compile time");
index 63cc6faf9ec5ea01de532406e44fcc2b98ff9f84..f31b0ee592e9cb9b98acededf52e8b6543239cee 100644 (file)
     ("ssbs", Some(sym::aarch64_target_feature)),
     // FEAT_SB
     ("sb", Some(sym::aarch64_target_feature)),
-    // FEAT_PAUTH
-    ("pauth", Some(sym::aarch64_target_feature)),
+    // FEAT_PAUTH (address authentication)
+    ("paca", Some(sym::aarch64_target_feature)),
+    // FEAT_PAUTH (generic authentication)
+    ("pacg", Some(sym::aarch64_target_feature)),
     // FEAT_DPB
     ("dpb", Some(sym::aarch64_target_feature)),
     // FEAT_DPB2
     ("v8.7a", Some(sym::aarch64_target_feature)),
 ];
 
+const AARCH64_TIED_FEATURES: &[&[&str]] = &[&["paca", "pacg"]];
+
 const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("adx", Some(sym::adx_target_feature)),
     ("aes", None),
@@ -256,6 +260,13 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt
     }
 }
 
+pub fn tied_target_features(sess: &Session) -> &'static [&'static [&'static str]] {
+    match &*sess.target.arch {
+        "aarch64" => AARCH64_TIED_FEATURES,
+        _ => &[],
+    }
+}
+
 pub(crate) fn provide(providers: &mut Providers) {
     providers.supported_target_features = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
index cbf570dba4c3ead260821e083c6881a431e7b0fc..e77201cf0c800a144b0853b2010184f5533b48c9 100644 (file)
@@ -22,7 +22,7 @@ pub trait CoverageInfoMethods<'tcx>: BackendTypes {
 
 pub trait CoverageInfoBuilderMethods<'tcx>: BackendTypes {
     /// Returns true if the function source hash was added to the coverage map (even if it had
-    /// already been added, for this instance). Returns false *only* if `-Z instrument-coverage` is
+    /// already been added, for this instance). Returns false *only* if `-C instrument-coverage` is
     /// not enabled (a coverage map is not being generated).
     fn set_function_source_hash(
         &mut self,
@@ -30,7 +30,7 @@ fn set_function_source_hash(
         function_source_hash: u64,
     ) -> bool;
 
-    /// Returns true if the counter was added to the coverage map; false if `-Z instrument-coverage`
+    /// Returns true if the counter was added to the coverage map; false if `-C instrument-coverage`
     /// is not enabled (a coverage map is not being generated).
     fn add_coverage_counter(
         &mut self,
@@ -40,7 +40,7 @@ fn add_coverage_counter(
     ) -> bool;
 
     /// Returns true if the expression was added to the coverage map; false if
-    /// `-Z instrument-coverage` is not enabled (a coverage map is not being generated).
+    /// `-C instrument-coverage` is not enabled (a coverage map is not being generated).
     fn add_coverage_counter_expression(
         &mut self,
         instance: Instance<'tcx>,
@@ -51,7 +51,7 @@ fn add_coverage_counter_expression(
         region: Option<CodeRegion>,
     ) -> bool;
 
-    /// Returns true if the region was added to the coverage map; false if `-Z instrument-coverage`
+    /// Returns true if the region was added to the coverage map; false if `-C instrument-coverage`
     /// is not enabled (a coverage map is not being generated).
     fn add_coverage_unreachable(&mut self, instance: Instance<'tcx>, region: CodeRegion) -> bool;
 }
index 87298023980ed8c2ff2ccde238122e1a7556fb53..89a0f8245e5fb7e36b23433e5320f6d11b39ee25 100644 (file)
@@ -156,9 +156,37 @@ fn struct_generic(
             }
             // Add spans for the stacktrace. Don't print a single-line backtrace though.
             if self.stacktrace.len() > 1 {
+                // Helper closure to print duplicated lines.
+                let mut flush_last_line = |last_frame, times| {
+                    if let Some((line, span)) = last_frame {
+                        err.span_label(span, &line);
+                        // Don't print [... additional calls ...] if the number of lines is small
+                        if times < 3 {
+                            for _ in 0..times {
+                                err.span_label(span, &line);
+                            }
+                        } else {
+                            err.span_label(
+                                span,
+                                format!("[... {} additional calls {} ...]", times, &line),
+                            );
+                        }
+                    }
+                };
+
+                let mut last_frame = None;
+                let mut times = 0;
                 for frame_info in &self.stacktrace {
-                    err.span_label(frame_info.span, frame_info.to_string());
+                    let frame = (frame_info.to_string(), frame_info.span);
+                    if last_frame.as_ref() == Some(&frame) {
+                        times += 1;
+                    } else {
+                        flush_last_line(last_frame, times);
+                        last_frame = Some(frame);
+                        times = 0;
+                    }
                 }
+                flush_last_line(last_frame, times);
             }
             // Let the caller finish the job.
             emit(err)
index 9dc34260de76697047c831da46ec30ec24d6ca40..bfb9c40be57df0e6d09c34b2caee8b8d63bfdad7 100644 (file)
@@ -6,7 +6,6 @@
     ScalarMaybeUninit, StackPopCleanup,
 };
 
-use rustc_errors::ErrorReported;
 use rustc_hir::def::DefKind;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
@@ -281,25 +280,6 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
 
     let cid = key.value;
     let def = cid.instance.def.with_opt_param();
-
-    if let Some(def) = def.as_local() {
-        if tcx.has_typeck_results(def.did) {
-            if let Some(error_reported) = tcx.typeck_opt_const_arg(def).tainted_by_errors {
-                return Err(ErrorHandled::Reported(error_reported));
-            }
-        }
-        if !tcx.is_mir_available(def.did) {
-            tcx.sess.delay_span_bug(
-                tcx.def_span(def.did),
-                &format!("no MIR body is available for {:?}", def.did),
-            );
-            return Err(ErrorHandled::Reported(ErrorReported {}));
-        }
-        if let Some(error_reported) = tcx.mir_const_qualif_opt_const_arg(def).error_occured {
-            return Err(ErrorHandled::Reported(error_reported));
-        }
-    }
-
     let is_static = tcx.is_static(def.did);
 
     let mut ecx = InterpCx::new(
index 89717b75f12815abea8069f2d36d695b7ff3b205..e157b584052128790b90db8300725e56b7fcf7ad 100644 (file)
@@ -1,3 +1,5 @@
+use rustc_errors::ErrorReported;
+use rustc_hir::def::DefKind;
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Ty};
 use std::borrow::Borrow;
@@ -243,6 +245,12 @@ fn load_mir(
             ty::InstanceDef::Item(def) => {
                 if ecx.tcx.is_ctfe_mir_available(def.did) {
                     Ok(ecx.tcx.mir_for_ctfe_opt_const_arg(def))
+                } else if ecx.tcx.def_kind(def.did) == DefKind::AssocConst {
+                    ecx.tcx.sess.delay_span_bug(
+                        rustc_span::DUMMY_SP,
+                        "This is likely a const item that is missing from its impl",
+                    );
+                    throw_inval!(AlreadyReported(ErrorReported {}));
                 } else {
                     let path = ecx.tcx.def_path_str(def.did);
                     Err(ConstEvalErrKind::NeedsRfc(format!("calling extern function `{}`", path))
index 91b17d1ac1ef88be5adecd336dec1415b7adbb1a..ba1d5f45bbb10be632ea2f3888b10235110f5604 100644 (file)
@@ -11,7 +11,8 @@
 use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
 
 use crate::interpret::{
-    intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MPlaceTy, MemPlaceMeta, Scalar,
+    intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy,
+    MemPlaceMeta, Scalar,
 };
 
 mod error;
@@ -132,49 +133,46 @@ fn const_to_valtree_inner<'tcx>(
     }
 }
 
-/// This function uses `unwrap` copiously, because an already validated constant
-/// must have valid fields and can thus never fail outside of compiler bugs. However, it is
-/// invoked from the pretty printer, where it can receive enums with no variants and e.g.
-/// `read_discriminant` needs to be able to handle that.
-pub(crate) fn destructure_const<'tcx>(
+/// This function should never fail for validated constants. However, it is also invoked from the
+/// pretty printer which might attempt to format invalid constants and in that case it might fail.
+pub(crate) fn try_destructure_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    val: &'tcx ty::Const<'tcx>,
-) -> mir::DestructuredConst<'tcx> {
+    val: ty::Const<'tcx>,
+) -> InterpResult<'tcx, mir::DestructuredConst<'tcx>> {
     trace!("destructure_const: {:?}", val);
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
-    let op = ecx.const_to_op(val, None).unwrap();
+    let op = ecx.const_to_op(val, None)?;
 
     // We go to `usize` as we cannot allocate anything bigger anyway.
-    let (field_count, variant, down) = match val.ty.kind() {
+    let (field_count, variant, down) = match val.ty().kind() {
         ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
-        ty::Adt(def, _) if def.variants.is_empty() => {
-            return mir::DestructuredConst { variant: None, fields: &[] };
-        }
         ty::Adt(def, _) => {
-            let variant = ecx.read_discriminant(&op).unwrap().1;
-            let down = ecx.operand_downcast(&op, variant).unwrap();
+            let variant = ecx.read_discriminant(&op)?.1;
+            let down = ecx.operand_downcast(&op, variant)?;
             (def.variants[variant].fields.len(), Some(variant), down)
         }
         ty::Tuple(substs) => (substs.len(), None, op),
         _ => bug!("cannot destructure constant {:?}", val),
     };
 
-    let fields_iter = (0..field_count).map(|i| {
-        let field_op = ecx.operand_field(&down, i).unwrap();
-        let val = op_to_const(&ecx, &field_op);
-        ty::Const::from_value(tcx, val, field_op.layout.ty)
-    });
-    let fields = tcx.arena.alloc_from_iter(fields_iter);
+    let fields = (0..field_count)
+        .map(|i| {
+            let field_op = ecx.operand_field(&down, i)?;
+            let val = op_to_const(&ecx, &field_op);
+            Ok(ty::Const::from_value(tcx, val, field_op.layout.ty))
+        })
+        .collect::<InterpResult<'tcx, Vec<_>>>()?;
+    let fields = tcx.arena.alloc_from_iter(fields);
 
-    mir::DestructuredConst { variant, fields }
+    Ok(mir::DestructuredConst { variant, fields })
 }
 
 pub(crate) fn deref_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    val: &'tcx ty::Const<'tcx>,
-) -> &'tcx ty::Const<'tcx> {
+    val: ty::Const<'tcx>,
+) -> ty::Const<'tcx> {
     trace!("deref_const: {:?}", val);
     let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
     let op = ecx.const_to_op(val, None).unwrap();
@@ -194,7 +192,7 @@ pub(crate) fn deref_const<'tcx>(
         // In case of unsized types, figure out the real type behind.
         MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() {
             ty::Str => bug!("there's no sized equivalent of a `str`"),
-            ty::Slice(elem_ty) => tcx.mk_array(elem_ty, scalar.to_machine_usize(&tcx).unwrap()),
+            ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_machine_usize(&tcx).unwrap()),
             _ => bug!(
                 "type {} should not have metadata, but had {:?}",
                 mplace.layout.ty,
@@ -203,5 +201,5 @@ pub(crate) fn deref_const<'tcx>(
         },
     };
 
-    tcx.mk_const(ty::Const { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
+    tcx.mk_const(ty::ConstS { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
 }
index 4c4b0bd2d1f271c215d8e6b9591e9f3ee077e851..e2c4eb1dadc83facbfe202c929681901e4ad2ced 100644 (file)
@@ -315,7 +315,7 @@ fn unsize_into(
         match (&src.layout.ty.kind(), &cast_ty.ty.kind()) {
             (&ty::Ref(_, s, _), &ty::Ref(_, c, _) | &ty::RawPtr(TypeAndMut { ty: c, .. }))
             | (&ty::RawPtr(TypeAndMut { ty: s, .. }), &ty::RawPtr(TypeAndMut { ty: c, .. })) => {
-                self.unsize_into_ptr(src, dest, s, c)
+                self.unsize_into_ptr(src, dest, *s, *c)
             }
             (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
                 assert_eq!(def_a, def_b);
index 0a8112da2aba8fbe4ccd596e05a14da16e970773..1b86bcfa8c9ad6ed9cef72d69ff896226e79043e 100644 (file)
@@ -509,20 +509,18 @@ pub fn load_mir(
         instance: ty::InstanceDef<'tcx>,
         promoted: Option<mir::Promoted>,
     ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
-        // do not continue if typeck errors occurred (can only occur in local crate)
         let def = instance.with_opt_param();
-        if let Some(def) = def.as_local() {
-            if self.tcx.has_typeck_results(def.did) {
-                if let Some(error_reported) = self.tcx.typeck_opt_const_arg(def).tainted_by_errors {
-                    throw_inval!(AlreadyReported(error_reported))
-                }
-            }
-        }
         trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
-        if let Some(promoted) = promoted {
-            return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]);
+        let body = if let Some(promoted) = promoted {
+            &self.tcx.promoted_mir_opt_const_arg(def)[promoted]
+        } else {
+            M::load_mir(self, instance)?
+        };
+        // do not continue if typeck errors occurred (can only occur in local crate)
+        if let Some(err) = body.tainted_by_errors {
+            throw_inval!(AlreadyReported(err));
         }
-        M::load_mir(self, instance)
+        Ok(body)
     }
 
     /// Call this on things you got out of the MIR (so it is as generic as the current
index ca000f93eb6b5c521bb4614f186f046aa2344cce..e6f243e28dbc5c7a45a524b3ae66b141a559ada0 100644 (file)
@@ -68,7 +68,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
         }
     }
 
-    fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+    fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
         self.pretty_print_const(ct, false)
     }
 
index e9c94c0cc434ccf73a8270d7cba68aaf1f1e0d9b..ec5eafcd6331821b2312d00eab57cde8bd4ee065 100644 (file)
@@ -561,10 +561,10 @@ pub(super) fn eval_operands(
     /// "universe" (param_env).
     pub fn const_to_op(
         &self,
-        val: &ty::Const<'tcx>,
+        val: ty::Const<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
-        match val.val {
+        match val.val() {
             ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
             ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)),
             ty::ConstKind::Unevaluated(uv) => {
@@ -574,7 +574,7 @@ pub fn const_to_op(
             ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
                 span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val)
             }
-            ty::ConstKind::Value(val_val) => self.const_val_to_op(val_val, val.ty, layout),
+            ty::ConstKind::Value(val_val) => self.const_val_to_op(val_val, val.ty(), layout),
         }
     }
 
@@ -584,8 +584,8 @@ pub fn mir_const_to_op(
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
         match val {
-            mir::ConstantKind::Ty(ct) => self.const_to_op(ct, layout),
-            mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, ty, layout),
+            mir::ConstantKind::Ty(ct) => self.const_to_op(*ct, layout),
+            mir::ConstantKind::Val(val, ty) => self.const_val_to_op(*val, *ty, layout),
         }
     }
 
index 818b95b7fc4f3108923d1e74aa2f0dbe2cad132c..7b06ffaf15d02f86f7917d36750cf663878805ef 100644 (file)
@@ -462,7 +462,7 @@ fn mplace_subslice(
         let (meta, ty) = match base.layout.ty.kind() {
             // It is not nice to match on the type, but that seems to be the only way to
             // implement this.
-            ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(inner, inner_len)),
+            ty::Array(inner, _) => (MemPlaceMeta::None, self.tcx.mk_array(*inner, inner_len)),
             ty::Slice(..) => {
                 let len = Scalar::from_machine_usize(inner_len, self);
                 (MemPlaceMeta::Meta(len), base.layout.ty)
index 6a3378a3896e3a0b58fdb74afed1dd6b486f5e53..e17bd9a8c08993112f43ed8bd45c90d6a1106f09 100644 (file)
@@ -55,7 +55,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                                     assert!(matches!(ty.kind(), ty::Param(_)))
                                 }
                                 ty::subst::GenericArgKind::Const(ct) => {
-                                    assert!(matches!(ct.val, ty::ConstKind::Param(_)))
+                                    assert!(matches!(ct.val(), ty::ConstKind::Param(_)))
                                 }
                                 ty::subst::GenericArgKind::Lifetime(..) => (),
                             },
@@ -68,8 +68,8 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
         }
 
-        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-            match c.val {
+        fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+            match c.val() {
                 ty::ConstKind::Param(..) => ControlFlow::Break(FoundParam),
                 _ => c.super_visit_with(self),
             }
index 9dc7930fc51fb48cc6bb774097cb3afd663e1928..4060bee7e056c1c61554069927610d644a52521e 100644 (file)
@@ -553,7 +553,7 @@ fn try_visit_primitive(
                 {
                     // A mutable reference inside a const? That does not seem right (except if it is
                     // a ZST).
-                    let layout = self.ecx.layout_of(ty)?;
+                    let layout = self.ecx.layout_of(*ty)?;
                     if !layout.is_zst() {
                         throw_validation_failure!(self.path, { "mutable reference in a `const`" });
                     }
@@ -837,7 +837,7 @@ fn visit_aggregate(
                 // This is the length of the array/slice.
                 let len = mplace.len(self.ecx)?;
                 // This is the element type size.
-                let layout = self.ecx.layout_of(tys)?;
+                let layout = self.ecx.layout_of(*tys)?;
                 // This is the size in bytes of the whole array. (This checks for overflow.)
                 let size = layout.size * len;
 
@@ -896,7 +896,7 @@ fn visit_aggregate(
             // Fast path for arrays and slices of ZSTs. We only need to check a single ZST element
             // of an array and not all of them, because there's only a single value of a specific
             // ZST type, so either validation fails for all elements or none.
-            ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(tys)?.is_zst() => {
+            ty::Array(tys, ..) | ty::Slice(tys) if self.ecx.layout_of(*tys)?.is_zst() => {
                 // Validate just the first element (if any).
                 self.walk_aggregate(op, fields.take(1))?
             }
index 838484876c72a3d92e20e2640cbc81ded0fb5626..77d312f585138f6c4c9eda1031cb4f4c1a27955a 100644 (file)
@@ -41,9 +41,9 @@ pub fn provide(providers: &mut Providers) {
     providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
     providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
     providers.const_caller_location = const_eval::const_caller_location;
-    providers.destructure_const = |tcx, param_env_and_value| {
+    providers.try_destructure_const = |tcx, param_env_and_value| {
         let (param_env, value) = param_env_and_value.into_parts();
-        const_eval::destructure_const(tcx, param_env, value)
+        const_eval::try_destructure_const(tcx, param_env, value).ok()
     };
     providers.const_to_valtree = |tcx, param_env_and_value| {
         let (param_env, raw) = param_env_and_value.into_parts();
index 6799514a4490db098206e2958dff72304158fb10..095c8f84f41adb28eb8e1c3e97f7651fb1d19f1f 100644 (file)
@@ -14,6 +14,7 @@
 use rustc_middle::ty::{Binder, TraitPredicate, TraitRef};
 use rustc_mir_dataflow::{self, Analysis};
 use rustc_span::{sym, Span, Symbol};
+use rustc_trait_selection::traits::error_reporting::InferCtxtExt;
 use rustc_trait_selection::traits::SelectionContext;
 
 use std::mem;
@@ -120,7 +121,7 @@ pub fn has_mut_interior(
     fn in_return_place(
         &mut self,
         ccx: &'mir ConstCx<'mir, 'tcx>,
-        error_occured: Option<ErrorReported>,
+        tainted_by_errors: Option<ErrorReported>,
     ) -> ConstQualifs {
         // Find the `Return` terminator if one exists.
         //
@@ -134,7 +135,9 @@ fn in_return_place(
             .map(|(bb, _)| bb);
 
         let return_block = match return_block {
-            None => return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), error_occured),
+            None => {
+                return qualifs::in_any_value_of_ty(ccx, ccx.body.return_ty(), tainted_by_errors);
+            }
             Some(bb) => bb,
         };
 
@@ -166,7 +169,7 @@ fn in_return_place(
             needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc),
             has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
             custom_eq,
-            error_occured,
+            tainted_by_errors,
         }
     }
 }
@@ -291,13 +294,13 @@ pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
     }
 
     /// Emits an error if an expression cannot be evaluated in the current context.
-    pub fn check_op(&mut self, op: impl NonConstOp) {
+    pub fn check_op(&mut self, op: impl NonConstOp<'tcx>) {
         self.check_op_spanned(op, self.span);
     }
 
     /// Emits an error at the given `span` if an expression cannot be evaluated in the current
     /// context.
-    pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
+    pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
         let gate = match op.status_in_item(self.ccx) {
             Status::Allowed => return,
 
@@ -771,7 +774,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
         self.super_terminator(terminator, location);
 
         match &terminator.kind {
-            TerminatorKind::Call { func, args, .. } => {
+            TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => {
                 let ConstCx { tcx, body, param_env, .. } = *self.ccx;
                 let caller = self.def_id().to_def_id();
 
@@ -795,20 +798,24 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 if let Some(trait_id) = tcx.trait_of_item(callee) {
                     trace!("attempting to call a trait method");
                     if !self.tcx.features().const_trait_impl {
-                        self.check_op(ops::FnCallNonConst(Some((callee, substs))));
+                        self.check_op(ops::FnCallNonConst {
+                            caller,
+                            callee,
+                            substs,
+                            span: *fn_span,
+                            from_hir_call: *from_hir_call,
+                        });
                         return;
                     }
 
                     let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
-                    let obligation = Obligation::new(
-                        ObligationCause::dummy(),
-                        param_env,
-                        Binder::dummy(TraitPredicate {
-                            trait_ref,
-                            constness: ty::BoundConstness::NotConst,
-                            polarity: ty::ImplPolarity::Positive,
-                        }),
-                    );
+                    let poly_trait_pred = Binder::dummy(TraitPredicate {
+                        trait_ref,
+                        constness: ty::BoundConstness::ConstIfConst,
+                        polarity: ty::ImplPolarity::Positive,
+                    });
+                    let obligation =
+                        Obligation::new(ObligationCause::dummy(), param_env, poly_trait_pred);
 
                     let implsrc = tcx.infer_ctxt().enter(|infcx| {
                         let mut selcx = SelectionContext::new(&infcx);
@@ -824,10 +831,6 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                             return;
                         }
                         Ok(Some(ImplSource::UserDefined(data))) => {
-                            if let hir::Constness::NotConst = tcx.impl_constness(data.impl_def_id) {
-                                self.check_op(ops::FnCallNonConst(None));
-                                return;
-                            }
                             let callee_name = tcx.item_name(callee);
                             if let Some(&did) = tcx
                                 .associated_item_def_ids(data.impl_def_id)
@@ -839,22 +842,61 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                                 substs = InternalSubsts::identity_for_item(tcx, did);
                                 callee = did;
                             }
+
+                            if let hir::Constness::NotConst = tcx.impl_constness(data.impl_def_id) {
+                                self.check_op(ops::FnCallNonConst {
+                                    caller,
+                                    callee,
+                                    substs,
+                                    span: *fn_span,
+                                    from_hir_call: *from_hir_call,
+                                });
+                                return;
+                            }
                         }
                         _ if !tcx.is_const_fn_raw(callee) => {
                             // At this point, it is only legal when the caller is marked with
                             // #[default_method_body_is_const], and the callee is in the same
                             // trait.
                             let callee_trait = tcx.trait_of_item(callee);
-                            if callee_trait.is_some() {
-                                if tcx.has_attr(caller, sym::default_method_body_is_const) {
-                                    if tcx.trait_of_item(caller) == callee_trait {
-                                        nonconst_call_permission = true;
-                                    }
-                                }
+                            if callee_trait.is_some()
+                                && tcx.has_attr(caller, sym::default_method_body_is_const)
+                                && callee_trait == tcx.trait_of_item(caller)
+                                // Can only call methods when it's `<Self as TheTrait>::f`.
+                                && tcx.types.self_param == substs.type_at(0)
+                            {
+                                nonconst_call_permission = true;
                             }
 
                             if !nonconst_call_permission {
-                                self.check_op(ops::FnCallNonConst(None));
+                                let obligation = Obligation::new(
+                                    ObligationCause::dummy_with_span(*fn_span),
+                                    param_env,
+                                    tcx.mk_predicate(
+                                        poly_trait_pred.map_bound(ty::PredicateKind::Trait),
+                                    ),
+                                );
+
+                                // improve diagnostics by showing what failed. Our requirements are stricter this time
+                                // as we are going to error again anyways.
+                                tcx.infer_ctxt().enter(|infcx| {
+                                    if let Err(e) = implsrc {
+                                        infcx.report_selection_error(
+                                            obligation.clone(),
+                                            &obligation,
+                                            &e,
+                                            false,
+                                        );
+                                    }
+                                });
+
+                                self.check_op(ops::FnCallNonConst {
+                                    caller,
+                                    callee,
+                                    substs,
+                                    span: *fn_span,
+                                    from_hir_call: *from_hir_call,
+                                });
                                 return;
                             }
                         }
@@ -923,7 +965,13 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     }
 
                     if !nonconst_call_permission {
-                        self.check_op(ops::FnCallNonConst(None));
+                        self.check_op(ops::FnCallNonConst {
+                            caller,
+                            callee,
+                            substs,
+                            span: *fn_span,
+                            from_hir_call: *from_hir_call,
+                        });
                         return;
                     }
                 }
index 24c4a4915e5e831f7313a41e18f897d0df1ebd96..8c3f8e8816464d156eddd3235cd4f119fb365f36 100644 (file)
@@ -3,14 +3,22 @@
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
+use rustc_middle::mir;
+use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
-use rustc_middle::{mir, ty::AssocKind};
+use rustc_middle::ty::{
+    suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, TraitPredicate, Ty,
+};
+use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::sym;
-use rustc_span::{symbol::Ident, Span, Symbol};
-use rustc_span::{BytePos, Pos};
+use rustc_span::{BytePos, Pos, Span, Symbol};
+use rustc_trait_selection::traits::SelectionContext;
 
 use super::ConstCx;
+use crate::util::{call_kind, CallDesugaringKind, CallKind};
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
 pub enum Status {
@@ -29,9 +37,9 @@ pub enum DiagnosticImportance {
 }
 
 /// An operation that is not *always* allowed in a const context.
-pub trait NonConstOp: std::fmt::Debug {
+pub trait NonConstOp<'tcx>: std::fmt::Debug {
     /// Returns an enum indicating whether this operation is allowed within the given item.
-    fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
         Status::Forbidden
     }
 
@@ -39,13 +47,13 @@ fn importance(&self) -> DiagnosticImportance {
         DiagnosticImportance::Primary
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
 }
 
 #[derive(Debug)]
 pub struct FloatingPointOp;
-impl NonConstOp for FloatingPointOp {
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
+    fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
         if ccx.const_kind() == hir::ConstContext::ConstFn {
             Status::Unstable(sym::const_fn_floating_point_arithmetic)
         } else {
@@ -53,7 +61,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
         }
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_fn_floating_point_arithmetic,
@@ -66,77 +74,229 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 /// A function call where the callee is a pointer.
 #[derive(Debug)]
 pub struct FnCallIndirect;
-impl NonConstOp for FnCallIndirect {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn")
     }
 }
 
 /// A function call where the callee is not marked as `const`.
-#[derive(Debug)]
-pub struct FnCallNonConst<'tcx>(pub Option<(DefId, SubstsRef<'tcx>)>);
-impl<'a> NonConstOp for FnCallNonConst<'a> {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        let mut err = struct_span_err!(
-            ccx.tcx.sess,
-            span,
-            E0015,
-            "calls in {}s are limited to constant functions, \
-             tuple structs and tuple variants",
-            ccx.const_kind(),
-        );
+#[derive(Debug, Clone, Copy)]
+pub struct FnCallNonConst<'tcx> {
+    pub caller: DefId,
+    pub callee: DefId,
+    pub substs: SubstsRef<'tcx>,
+    pub span: Span,
+    pub from_hir_call: bool,
+}
 
-        if let FnCallNonConst(Some((callee, substs))) = *self {
-            if let Some(trait_def_id) = ccx.tcx.lang_items().eq_trait() {
-                if let Some(eq_item) = ccx.tcx.associated_items(trait_def_id).find_by_name_and_kind(
-                    ccx.tcx,
-                    Ident::with_dummy_span(sym::eq),
-                    AssocKind::Fn,
-                    trait_def_id,
-                ) {
-                    if callee == eq_item.def_id && substs.len() == 2 {
-                        match (substs[0].unpack(), substs[1].unpack()) {
-                            (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
-                                if self_ty == rhs_ty
-                                    && self_ty.is_ref()
-                                    && self_ty.peel_refs().is_primitive() =>
-                            {
-                                let mut num_refs = 0;
-                                let mut tmp_ty = self_ty;
-                                while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
-                                    num_refs += 1;
-                                    tmp_ty = inner_ty;
-                                }
-                                let deref = "*".repeat(num_refs);
-
-                                if let Ok(call_str) =
-                                    ccx.tcx.sess.source_map().span_to_snippet(span)
-                                {
-                                    if let Some(eq_idx) = call_str.find("==") {
-                                        if let Some(rhs_idx) = call_str[(eq_idx + 2)..]
-                                            .find(|c: char| !c.is_whitespace())
-                                        {
-                                            let rhs_pos = span.lo()
-                                                + BytePos::from_usize(eq_idx + 2 + rhs_idx);
-                                            let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
-                                            err.multipart_suggestion(
-                                                "consider dereferencing here",
-                                                vec![
-                                                    (span.shrink_to_lo(), deref.clone()),
-                                                    (rhs_span, deref),
-                                                ],
-                                                Applicability::MachineApplicable,
-                                            );
-                                        }
+impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> DiagnosticBuilder<'tcx> {
+        let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self;
+        let ConstCx { tcx, param_env, .. } = *ccx;
+
+        let diag_trait = |mut err, self_ty: Ty<'_>, trait_id| {
+            let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
+
+            match self_ty.kind() {
+                Param(param_ty) => {
+                    debug!(?param_ty);
+                    if let Some(generics) = caller
+                        .as_local()
+                        .map(|id| tcx.hir().local_def_id_to_hir_id(id))
+                        .map(|id| tcx.hir().get(id))
+                        .as_ref()
+                        .and_then(|node| node.generics())
+                    {
+                        let constraint = with_no_trimmed_paths(|| {
+                            format!("~const {}", trait_ref.print_only_trait_path())
+                        });
+                        suggest_constraining_type_param(
+                            tcx,
+                            generics,
+                            &mut err,
+                            &param_ty.name.as_str(),
+                            &constraint,
+                            None,
+                        );
+                    }
+                }
+                Adt(..) => {
+                    let obligation = Obligation::new(
+                        ObligationCause::dummy(),
+                        param_env,
+                        Binder::dummy(TraitPredicate {
+                            trait_ref,
+                            constness: BoundConstness::NotConst,
+                            polarity: ImplPolarity::Positive,
+                        }),
+                    );
+
+                    let implsrc = tcx.infer_ctxt().enter(|infcx| {
+                        let mut selcx = SelectionContext::new(&infcx);
+                        selcx.select(&obligation)
+                    });
+
+                    if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
+                        let span =
+                            tcx.sess.source_map().guess_head_span(tcx.def_span(data.impl_def_id));
+                        err.span_note(span, "impl defined here, but it is not `const`");
+                    }
+                }
+                _ => {}
+            }
+
+            err
+        };
+
+        let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None);
+
+        debug!(?call_kind);
+
+        let mut err = match call_kind {
+            CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
+                macro_rules! error {
+                    ($fmt:literal) => {
+                        struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind())
+                    };
+                }
+
+                let err = match kind {
+                    CallDesugaringKind::ForLoopIntoIter => {
+                        error!("cannot convert `{}` into an iterator in {}s")
+                    }
+                    CallDesugaringKind::QuestionBranch => {
+                        error!("`?` cannot determine the branch of `{}` in {}s")
+                    }
+                    CallDesugaringKind::QuestionFromResidual => {
+                        error!("`?` cannot convert from residual of `{}` in {}s")
+                    }
+                    CallDesugaringKind::TryBlockFromOutput => {
+                        error!("`try` block cannot convert `{}` to the result in {}s")
+                    }
+                };
+
+                diag_trait(err, self_ty, kind.trait_def_id(tcx))
+            }
+            CallKind::FnCall { fn_trait_id, self_ty } => {
+                let mut err = struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0015,
+                    "cannot call non-const closure in {}s",
+                    ccx.const_kind(),
+                );
+
+                match self_ty.kind() {
+                    FnDef(def_id, ..) => {
+                        let span = tcx.sess.source_map().guess_head_span(tcx.def_span(*def_id));
+                        if ccx.tcx.is_const_fn_raw(*def_id) {
+                            span_bug!(span, "calling const FnDef errored when it shouldn't");
+                        }
+
+                        err.span_note(span, "function defined here, but it is not `const`");
+                    }
+                    FnPtr(..) => {
+                        err.note(&format!(
+                            "function pointers need an RFC before allowed to be called in {}s",
+                            ccx.const_kind()
+                        ));
+                    }
+                    Closure(..) => {
+                        err.note(&format!(
+                            "closures need an RFC before allowed to be called in {}s",
+                            ccx.const_kind()
+                        ));
+                    }
+                    _ => {}
+                }
+
+                diag_trait(err, self_ty, fn_trait_id)
+            }
+            CallKind::Operator { trait_id, self_ty, .. } => {
+                let mut err = struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0015,
+                    "cannot call non-const operator in {}s",
+                    ccx.const_kind()
+                );
+
+                if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
+                    match (substs[0].unpack(), substs[1].unpack()) {
+                        (GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
+                            if self_ty == rhs_ty
+                                && self_ty.is_ref()
+                                && self_ty.peel_refs().is_primitive() =>
+                        {
+                            let mut num_refs = 0;
+                            let mut tmp_ty = self_ty;
+                            while let rustc_middle::ty::Ref(_, inner_ty, _) = tmp_ty.kind() {
+                                num_refs += 1;
+                                tmp_ty = *inner_ty;
+                            }
+                            let deref = "*".repeat(num_refs);
+
+                            if let Ok(call_str) = ccx.tcx.sess.source_map().span_to_snippet(span) {
+                                if let Some(eq_idx) = call_str.find("==") {
+                                    if let Some(rhs_idx) =
+                                        call_str[(eq_idx + 2)..].find(|c: char| !c.is_whitespace())
+                                    {
+                                        let rhs_pos =
+                                            span.lo() + BytePos::from_usize(eq_idx + 2 + rhs_idx);
+                                        let rhs_span = span.with_lo(rhs_pos).with_hi(rhs_pos);
+                                        err.multipart_suggestion(
+                                            "consider dereferencing here",
+                                            vec![
+                                                (span.shrink_to_lo(), deref.clone()),
+                                                (rhs_span, deref),
+                                            ],
+                                            Applicability::MachineApplicable,
+                                        );
                                     }
                                 }
                             }
-                            _ => {}
                         }
+                        _ => {}
                     }
                 }
+
+                diag_trait(err, self_ty, trait_id)
             }
-        }
+            CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
+                let mut err = struct_span_err!(
+                    tcx.sess,
+                    span,
+                    E0015,
+                    "cannot perform deref coercion on `{}` in {}s",
+                    self_ty,
+                    ccx.const_kind()
+                );
+
+                err.note(&format!("attempting to deref into `{}`", deref_target_ty));
+
+                // Check first whether the source is accessible (issue #87060)
+                if tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
+                    err.span_note(deref_target, "deref defined here");
+                }
+
+                diag_trait(err, self_ty, tcx.lang_items().deref_trait().unwrap())
+            }
+            _ => struct_span_err!(
+                ccx.tcx.sess,
+                span,
+                E0015,
+                "cannot call non-const fn `{}` in {}s",
+                ccx.tcx.def_path_str_with_substs(callee, substs),
+                ccx.const_kind(),
+            ),
+        };
+
+        err.note(&format!(
+            "calls in {}s are limited to constant functions, \
+             tuple structs and tuple variants",
+            ccx.const_kind(),
+        ));
 
         err
     }
@@ -148,8 +308,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 #[derive(Debug)]
 pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
 
-impl NonConstOp for FnCallUnstable {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let FnCallUnstable(def_id, feature) = *self;
 
         let mut err = ccx.tcx.sess.struct_span_err(
@@ -174,8 +334,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 
 #[derive(Debug)]
 pub struct FnPtrCast;
-impl NonConstOp for FnPtrCast {
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for FnPtrCast {
+    fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
         if ccx.const_kind() != hir::ConstContext::ConstFn {
             Status::Allowed
         } else {
@@ -183,7 +343,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
         }
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_fn_fn_ptr_basics,
@@ -195,8 +355,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 
 #[derive(Debug)]
 pub struct Generator(pub hir::GeneratorKind);
-impl NonConstOp for Generator {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for Generator {
+    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
         if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
             Status::Unstable(sym::const_async_blocks)
         } else {
@@ -204,7 +364,7 @@ fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
         }
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind());
         if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
             feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg)
@@ -216,8 +376,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 
 #[derive(Debug)]
 pub struct HeapAllocation;
-impl NonConstOp for HeapAllocation {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -240,8 +400,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 
 #[derive(Debug)]
 pub struct InlineAsm;
-impl NonConstOp for InlineAsm {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for InlineAsm {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -256,8 +416,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 pub struct LiveDrop {
     pub dropped_at: Option<Span>,
 }
-impl NonConstOp for LiveDrop {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for LiveDrop {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -276,8 +436,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 /// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
 /// the final value of the constant.
 pub struct TransientCellBorrow;
-impl NonConstOp for TransientCellBorrow {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
+    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable(sym::const_refs_to_cell)
     }
     fn importance(&self) -> DiagnosticImportance {
@@ -285,7 +445,7 @@ fn importance(&self) -> DiagnosticImportance {
         // not additionally emit a feature gate error if activating the feature gate won't work.
         DiagnosticImportance::Secondary
     }
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_refs_to_cell,
@@ -300,8 +460,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 /// the final value of the constant, and thus we cannot allow this (for now). We may allow
 /// it in the future for static items.
 pub struct CellBorrow;
-impl NonConstOp for CellBorrow {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for CellBorrow {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -337,8 +497,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 /// static or const items.
 pub struct MutBorrow(pub hir::BorrowKind);
 
-impl NonConstOp for MutBorrow {
-    fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for MutBorrow {
+    fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
         Status::Forbidden
     }
 
@@ -348,7 +508,7 @@ fn importance(&self) -> DiagnosticImportance {
         DiagnosticImportance::Secondary
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let raw = match self.0 {
             hir::BorrowKind::Raw => "raw ",
             hir::BorrowKind::Ref => "",
@@ -382,12 +542,12 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 #[derive(Debug)]
 pub struct TransientMutBorrow(pub hir::BorrowKind);
 
-impl NonConstOp for TransientMutBorrow {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
+    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable(sym::const_mut_refs)
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let raw = match self.0 {
             hir::BorrowKind::Raw => "raw ",
             hir::BorrowKind::Ref => "",
@@ -404,8 +564,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 
 #[derive(Debug)]
 pub struct MutDeref;
-impl NonConstOp for MutDeref {
-    fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for MutDeref {
+    fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable(sym::const_mut_refs)
     }
 
@@ -414,7 +574,7 @@ fn importance(&self) -> DiagnosticImportance {
         DiagnosticImportance::Secondary
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_mut_refs,
@@ -427,8 +587,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 /// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
 #[derive(Debug)]
 pub struct PanicNonStr;
-impl NonConstOp for PanicNonStr {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         ccx.tcx.sess.struct_span_err(
             span,
             "argument to `panic!()` in a const context must have type `&str`",
@@ -441,8 +601,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 /// allocation base addresses that are not known at compile-time.
 #[derive(Debug)]
 pub struct RawPtrComparison;
-impl NonConstOp for RawPtrComparison {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = ccx
             .tcx
             .sess
@@ -457,12 +617,12 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 
 #[derive(Debug)]
 pub struct RawMutPtrDeref;
-impl NonConstOp for RawMutPtrDeref {
+impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
     fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
         Status::Unstable(sym::const_mut_refs)
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         feature_err(
             &ccx.tcx.sess.parse_sess,
             sym::const_mut_refs,
@@ -477,8 +637,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 /// allocation base addresses that are not known at compile-time.
 #[derive(Debug)]
 pub struct RawPtrToIntCast;
-impl NonConstOp for RawPtrToIntCast {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = ccx
             .tcx
             .sess
@@ -494,8 +654,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 /// An access to a (non-thread-local) `static`.
 #[derive(Debug)]
 pub struct StaticAccess;
-impl NonConstOp for StaticAccess {
-    fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+impl<'tcx> NonConstOp<'tcx> for StaticAccess {
+    fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
         if let hir::ConstContext::Static(_) = ccx.const_kind() {
             Status::Allowed
         } else {
@@ -503,7 +663,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
         }
     }
 
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -528,8 +688,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
 /// An access to a thread-local `static`.
 #[derive(Debug)]
 pub struct ThreadLocalAccess;
-impl NonConstOp for ThreadLocalAccess {
-    fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
+impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
+    fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         struct_span_err!(
             ccx.tcx.sess,
             span,
@@ -546,8 +706,8 @@ pub mod ty {
 
     #[derive(Debug)]
     pub struct MutRef(pub mir::LocalKind);
-    impl NonConstOp for MutRef {
-        fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
+    impl<'tcx> NonConstOp<'tcx> for MutRef {
+        fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
             Status::Unstable(sym::const_mut_refs)
         }
 
@@ -560,11 +720,7 @@ fn importance(&self) -> DiagnosticImportance {
             }
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_mut_refs,
@@ -576,7 +732,7 @@ fn build_error<'tcx>(
 
     #[derive(Debug)]
     pub struct FnPtr(pub mir::LocalKind);
-    impl NonConstOp for FnPtr {
+    impl<'tcx> NonConstOp<'tcx> for FnPtr {
         fn importance(&self) -> DiagnosticImportance {
             match self.0 {
                 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@@ -586,7 +742,7 @@ fn importance(&self) -> DiagnosticImportance {
             }
         }
 
-        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
             if ccx.const_kind() != hir::ConstContext::ConstFn {
                 Status::Allowed
             } else {
@@ -594,11 +750,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
             }
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_fn_fn_ptr_basics,
@@ -610,16 +762,12 @@ fn build_error<'tcx>(
 
     #[derive(Debug)]
     pub struct ImplTrait;
-    impl NonConstOp for ImplTrait {
+    impl<'tcx> NonConstOp<'tcx> for ImplTrait {
         fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
             Status::Unstable(sym::const_impl_trait)
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_impl_trait,
@@ -631,7 +779,7 @@ fn build_error<'tcx>(
 
     #[derive(Debug)]
     pub struct TraitBound(pub mir::LocalKind);
-    impl NonConstOp for TraitBound {
+    impl<'tcx> NonConstOp<'tcx> for TraitBound {
         fn importance(&self) -> DiagnosticImportance {
             match self.0 {
                 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@@ -641,7 +789,7 @@ fn importance(&self) -> DiagnosticImportance {
             }
         }
 
-        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
             if ccx.const_kind() != hir::ConstContext::ConstFn {
                 Status::Allowed
             } else {
@@ -649,11 +797,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
             }
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             let mut err = feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_fn_trait_bound,
@@ -674,7 +818,7 @@ fn build_error<'tcx>(
 
     #[derive(Debug)]
     pub struct DynTrait(pub mir::LocalKind);
-    impl NonConstOp for DynTrait {
+    impl<'tcx> NonConstOp<'tcx> for DynTrait {
         fn importance(&self) -> DiagnosticImportance {
             match self.0 {
                 mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@@ -684,7 +828,7 @@ fn importance(&self) -> DiagnosticImportance {
             }
         }
 
-        fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
+        fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
             if ccx.const_kind() != hir::ConstContext::ConstFn {
                 Status::Allowed
             } else {
@@ -692,11 +836,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
             }
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             let mut err = feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_fn_trait_bound,
@@ -718,16 +858,12 @@ fn build_error<'tcx>(
     /// A trait bound with the `?const Trait` opt-out
     #[derive(Debug)]
     pub struct TraitBoundNotConst;
-    impl NonConstOp for TraitBoundNotConst {
-        fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
+    impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst {
+        fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
             Status::Unstable(sym::const_trait_bound_opt_out)
         }
 
-        fn build_error<'tcx>(
-            &self,
-            ccx: &ConstCx<'_, 'tcx>,
-            span: Span,
-        ) -> DiagnosticBuilder<'tcx> {
+        fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
             feature_err(
                 &ccx.tcx.sess.parse_sess,
                 sym::const_trait_bound_opt_out,
index 91610b15eb9998d022dea2fd34fb886a564c7a21..639b798be5431abad80e703acf5702b10d402d52 100644 (file)
 pub fn in_any_value_of_ty<'tcx>(
     cx: &ConstCx<'_, 'tcx>,
     ty: Ty<'tcx>,
-    error_occured: Option<ErrorReported>,
+    tainted_by_errors: Option<ErrorReported>,
 ) -> ConstQualifs {
     ConstQualifs {
         has_mut_interior: HasMutInterior::in_any_value_of_ty(cx, ty),
         needs_drop: NeedsDrop::in_any_value_of_ty(cx, ty),
         needs_non_const_drop: NeedsNonConstDrop::in_any_value_of_ty(cx, ty),
         custom_eq: CustomEq::in_any_value_of_ty(cx, ty),
-        error_occured,
+        tainted_by_errors,
     }
 }
 
@@ -355,7 +355,7 @@ pub fn in_operand<'tcx, Q, F>(
 
     // Check the qualifs of the value of `const` items.
     if let Some(ct) = constant.literal.const_for_ty() {
-        if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.val {
+        if let ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) = ct.val() {
             // Use qualifs of the type for the promoted. Promoteds in MIR body should be possible
             // only for `NeedsNonConstDrop` with precise drop checking. This is the only const
             // check performed after the promotion. Verify that with an assertion.
index ac282a5ecc82c281454dcc0c83a31a4662bd7f3d..cacc0018fe93772bacd6e28caf08ece6bfb74a22 100644 (file)
@@ -496,7 +496,7 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
                 if matches!(kind, CastKind::Misc) {
                     let operand_ty = operand.ty(self.body, self.tcx);
                     let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
-                    let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
+                    let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast");
                     if let (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) = (cast_in, cast_out) {
                         // ptr-to-int casts are not possible in consts and thus not promotable
                         return Err(Unpromotable);
@@ -839,7 +839,7 @@ fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) ->
                     span,
                     user_ty: None,
                     literal: tcx
-                        .mk_const(ty::Const {
+                        .mk_const(ty::ConstS {
                             ty,
                             val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                                 def,
@@ -974,6 +974,7 @@ pub fn promote_candidates<'tcx>(
             vec![],
             body.span,
             body.generator_kind(),
+            body.tainted_by_errors,
         );
 
         let promoter = Promoter {
diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs
new file mode 100644 (file)
index 0000000..11bb950
--- /dev/null
@@ -0,0 +1,143 @@
+//! Common logic for borrowck use-after-move errors when moved into a `fn(self)`,
+//! as well as errors when attempting to call a non-const function in a const
+//! context.
+
+use rustc_hir::def_id::DefId;
+use rustc_hir::lang_items::LangItemGroup;
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt};
+use rustc_span::symbol::Ident;
+use rustc_span::{sym, DesugaringKind, Span};
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum CallDesugaringKind {
+    /// for _ in x {} calls x.into_iter()
+    ForLoopIntoIter,
+    /// x? calls x.branch()
+    QuestionBranch,
+    /// x? calls type_of(x)::from_residual()
+    QuestionFromResidual,
+    /// try { ..; x } calls type_of(x)::from_output(x)
+    TryBlockFromOutput,
+}
+
+impl CallDesugaringKind {
+    pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId {
+        match self {
+            Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(),
+            Self::QuestionBranch | Self::TryBlockFromOutput => {
+                tcx.lang_items().try_trait().unwrap()
+            }
+            Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(),
+        }
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum CallKind<'tcx> {
+    /// A normal method call of the form `receiver.foo(a, b, c)`
+    Normal {
+        self_arg: Option<Ident>,
+        desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>,
+        /// Whether the self type of the method call has an `.as_ref()` method.
+        /// Used for better diagnostics.
+        is_option_or_result: bool,
+    },
+    /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)`
+    FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> },
+    /// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
+    Operator { self_arg: Option<Ident>, trait_id: DefId, self_ty: Ty<'tcx> },
+    DerefCoercion {
+        /// The `Span` of the `Target` associated type
+        /// in the `Deref` impl we are using.
+        deref_target: Span,
+        /// The type `T::Deref` we are dereferencing to
+        deref_target_ty: Ty<'tcx>,
+        self_ty: Ty<'tcx>,
+    },
+}
+
+pub fn call_kind<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ParamEnv<'tcx>,
+    method_did: DefId,
+    method_substs: SubstsRef<'tcx>,
+    fn_call_span: Span,
+    from_hir_call: bool,
+    self_arg: Option<Ident>,
+) -> CallKind<'tcx> {
+    let parent = tcx.opt_associated_item(method_did).and_then(|assoc| match assoc.container {
+        AssocItemContainer::ImplContainer(impl_did) => tcx.trait_id_of_impl(impl_did),
+        AssocItemContainer::TraitContainer(trait_did) => Some(trait_did),
+    });
+
+    let fn_call = parent
+        .and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p));
+
+    let operator = (!from_hir_call)
+        .then(|| parent)
+        .flatten()
+        .and_then(|p| tcx.lang_items().group(LangItemGroup::Op).iter().find(|did| **did == p));
+
+    let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
+
+    // Check for a 'special' use of 'self' -
+    // an FnOnce call, an operator (e.g. `<<`), or a
+    // deref coercion.
+    let kind = if let Some(&trait_id) = fn_call {
+        Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) })
+    } else if let Some(&trait_id) = operator {
+        Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) })
+    } else if is_deref {
+        let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
+            Instance::resolve(tcx, param_env, deref_target, method_substs).transpose()
+        });
+        if let Some(Ok(instance)) = deref_target {
+            let deref_target_ty = instance.ty(tcx, param_env);
+            Some(CallKind::DerefCoercion {
+                deref_target: tcx.def_span(instance.def_id()),
+                deref_target_ty,
+                self_ty: method_substs.type_at(0),
+            })
+        } else {
+            None
+        }
+    } else {
+        None
+    };
+
+    kind.unwrap_or_else(|| {
+        // This isn't a 'special' use of `self`
+        debug!(?method_did, ?fn_call_span);
+        let desugaring = if Some(method_did) == tcx.lang_items().into_iter_fn()
+            && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop)
+        {
+            Some((CallDesugaringKind::ForLoopIntoIter, method_substs.type_at(0)))
+        } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) {
+            if Some(method_did) == tcx.lang_items().branch_fn() {
+                Some((CallDesugaringKind::QuestionBranch, method_substs.type_at(0)))
+            } else if Some(method_did) == tcx.lang_items().from_residual_fn() {
+                Some((CallDesugaringKind::QuestionFromResidual, method_substs.type_at(0)))
+            } else {
+                None
+            }
+        } else if Some(method_did) == tcx.lang_items().from_output_fn()
+            && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock)
+        {
+            Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0)))
+        } else {
+            None
+        };
+        let parent_self_ty = tcx
+            .parent(method_did)
+            .filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
+            .and_then(|did| match tcx.type_of(did).kind() {
+                ty::Adt(def, ..) => Some(def.did),
+                _ => None,
+            });
+        let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
+            matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
+        });
+        CallKind::Normal { self_arg, desugaring, is_option_or_result }
+    })
+}
index 4a406f8bfd08834fc18e66ea987fe261ed636ef9..a1876bed83eca4a1bfac1eb0d781e1b707ea50de 100644 (file)
@@ -1,8 +1,10 @@
 pub mod aggregate;
 mod alignment;
+mod call_kind;
 pub mod collect_writes;
 mod find_self_call;
 
 pub use self::aggregate::expand_aggregate;
 pub use self::alignment::is_disaligned;
+pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
 pub use self::find_self_call::find_self_call;
diff --git a/compiler/rustc_data_structures/src/intern.rs b/compiler/rustc_data_structures/src/intern.rs
new file mode 100644 (file)
index 0000000..c79a5eb
--- /dev/null
@@ -0,0 +1,98 @@
+use std::cmp::Ordering;
+use std::hash::{Hash, Hasher};
+use std::ops::Deref;
+use std::ptr;
+
+mod private {
+    #[derive(Clone, Copy, Debug)]
+    pub struct PrivateZst;
+}
+
+/// A reference to a value that is interned, and is known to be unique.
+///
+/// Note that it is possible to have a `T` and a `Interned<T>` that are (or
+/// refer to) equal but different values. But if you have two different
+/// `Interned<T>`s, they both refer to the same value, at a single location in
+/// memory. This means that equality and hashing can be done on the value's
+/// address rather than the value's contents, which can improve performance.
+///
+/// The `PrivateZst` field means you can pattern match with `Interned(v, _)`
+/// but you can only construct a `Interned` with `new_unchecked`, and not
+/// directly.
+#[derive(Debug)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Interned<'a, T>(pub &'a T, pub private::PrivateZst);
+
+impl<'a, T> Interned<'a, T> {
+    /// Create a new `Interned` value. The value referred to *must* be interned
+    /// and thus be unique, and it *must* remain unique in the future. This
+    /// function has `_unchecked` in the name but is not `unsafe`, because if
+    /// the uniqueness condition is violated condition it will cause incorrect
+    /// behaviour but will not affect memory safety.
+    #[inline]
+    pub const fn new_unchecked(t: &'a T) -> Self {
+        Interned(t, private::PrivateZst)
+    }
+}
+
+impl<'a, T> Clone for Interned<'a, T> {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl<'a, T> Copy for Interned<'a, T> {}
+
+impl<'a, T> Deref for Interned<'a, T> {
+    type Target = T;
+
+    #[inline]
+    fn deref(&self) -> &T {
+        self.0
+    }
+}
+
+impl<'a, T> PartialEq for Interned<'a, T> {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        // Pointer equality implies equality, due to the uniqueness constraint.
+        ptr::eq(self.0, other.0)
+    }
+}
+
+impl<'a, T> Eq for Interned<'a, T> {}
+
+// In practice you can't intern any `T` that doesn't implement `Eq`, because
+// that's needed for hashing. Therefore, we won't be interning any `T` that
+// implements `PartialOrd` without also implementing `Ord`. So we can have the
+// bound `T: Ord` here and avoid duplication with the `Ord` impl below.
+impl<'a, T: Ord> PartialOrd for Interned<'a, T> {
+    fn partial_cmp(&self, other: &Interned<'a, T>) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl<'a, T: Ord> Ord for Interned<'a, T> {
+    fn cmp(&self, other: &Interned<'a, T>) -> Ordering {
+        // Pointer equality implies equality, due to the uniqueness constraint,
+        // but the contents must be compared otherwise.
+        if ptr::eq(self.0, other.0) {
+            Ordering::Equal
+        } else {
+            let res = self.0.cmp(&other.0);
+            debug_assert_ne!(res, Ordering::Equal);
+            res
+        }
+    }
+}
+
+impl<'a, T> Hash for Interned<'a, T> {
+    #[inline]
+    fn hash<H: Hasher>(&self, s: &mut H) {
+        // Pointer hashing is sufficient, due to the uniqueness constraint.
+        ptr::hash(self.0, s)
+    }
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_data_structures/src/intern/tests.rs b/compiler/rustc_data_structures/src/intern/tests.rs
new file mode 100644 (file)
index 0000000..09810a0
--- /dev/null
@@ -0,0 +1,59 @@
+use super::*;
+use std::cmp::Ordering;
+
+#[derive(Debug)]
+struct S(u32);
+
+impl PartialEq for S {
+    fn eq(&self, _other: &Self) -> bool {
+        panic!("shouldn't be called");
+    }
+}
+
+impl Eq for S {}
+
+impl PartialOrd for S {
+    fn partial_cmp(&self, other: &S) -> Option<Ordering> {
+        // The `==` case should be handled by `Interned`.
+        assert_ne!(self.0, other.0);
+        self.0.partial_cmp(&other.0)
+    }
+}
+
+impl Ord for S {
+    fn cmp(&self, other: &S) -> Ordering {
+        // The `==` case should be handled by `Interned`.
+        assert_ne!(self.0, other.0);
+        self.0.cmp(&other.0)
+    }
+}
+
+#[test]
+fn test_uniq() {
+    let s1 = S(1);
+    let s2 = S(2);
+    let s3 = S(3);
+    let s4 = S(1); // violates uniqueness
+
+    let v1 = Interned::new_unchecked(&s1);
+    let v2 = Interned::new_unchecked(&s2);
+    let v3a = Interned::new_unchecked(&s3);
+    let v3b = Interned::new_unchecked(&s3);
+    let v4 = Interned::new_unchecked(&s4); // violates uniqueness
+
+    assert_ne!(v1, v2);
+    assert_ne!(v2, v3a);
+    assert_eq!(v1, v1);
+    assert_eq!(v3a, v3b);
+    assert_ne!(v1, v4); // same content but different addresses: not equal
+
+    assert_eq!(v1.cmp(&v2), Ordering::Less);
+    assert_eq!(v3a.cmp(&v2), Ordering::Greater);
+    assert_eq!(v1.cmp(&v1), Ordering::Equal); // only uses Interned::eq, not S::cmp
+    assert_eq!(v3a.cmp(&v3b), Ordering::Equal); // only uses Interned::eq, not S::cmp
+
+    assert_eq!(v1.partial_cmp(&v2), Some(Ordering::Less));
+    assert_eq!(v3a.partial_cmp(&v2), Some(Ordering::Greater));
+    assert_eq!(v1.partial_cmp(&v1), Some(Ordering::Equal)); // only uses Interned::eq, not S::cmp
+    assert_eq!(v3a.partial_cmp(&v3b), Some(Ordering::Equal)); // only uses Interned::eq, not S::cmp
+}
index 205f1cd77c0183a846de7c37b194cf7bb74565d6..80f83140f4b41a557338b02662b6c71e6d92aee8 100644 (file)
@@ -21,6 +21,7 @@
 #![feature(type_alias_impl_trait)]
 #![feature(new_uninit)]
 #![feature(once_cell)]
+#![feature(rustc_attrs)]
 #![feature(test)]
 #![feature(thread_id_value)]
 #![feature(vec_into_raw_parts)]
@@ -68,12 +69,12 @@ macro_rules! unlikely {
 pub mod functor;
 pub mod fx;
 pub mod graph;
+pub mod intern;
 pub mod jobserver;
 pub mod macros;
 pub mod map_in_place;
 pub mod obligation_forest;
 pub mod owning_ref;
-pub mod ptr_key;
 pub mod sip128;
 pub mod small_c_str;
 pub mod snapshot_map;
diff --git a/compiler/rustc_data_structures/src/ptr_key.rs b/compiler/rustc_data_structures/src/ptr_key.rs
deleted file mode 100644 (file)
index 440ccb0..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-use std::ops::Deref;
-use std::{hash, ptr};
-
-/// A wrapper around reference that compares and hashes like a pointer.
-/// Can be used as a key in sets/maps indexed by pointers to avoid `unsafe`.
-#[derive(Debug)]
-pub struct PtrKey<'a, T>(pub &'a T);
-
-impl<'a, T> Clone for PtrKey<'a, T> {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
-
-impl<'a, T> Copy for PtrKey<'a, T> {}
-
-impl<'a, T> PartialEq for PtrKey<'a, T> {
-    fn eq(&self, rhs: &Self) -> bool {
-        ptr::eq(self.0, rhs.0)
-    }
-}
-
-impl<'a, T> Eq for PtrKey<'a, T> {}
-
-impl<'a, T> hash::Hash for PtrKey<'a, T> {
-    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
-        (self.0 as *const T).hash(hasher)
-    }
-}
-
-impl<'a, T> Deref for PtrKey<'a, T> {
-    type Target = T;
-
-    fn deref(&self) -> &Self::Target {
-        self.0
-    }
-}
index 53062b9c20da8b8e6e6118730a518ff98c3bbf3f..6e5c0617bf34cb089c3942c5ca4831d874e7129b 100644 (file)
@@ -202,28 +202,26 @@ pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 {
         hasher
     }
 
-    // A specialized write function for values with size <= 8.
     #[inline]
-    fn short_write<T>(&mut self, x: T) {
-        let size = mem::size_of::<T>();
+    pub fn short_write<const LEN: usize>(&mut self, bytes: [u8; LEN]) {
         let nbuf = self.nbuf;
-        debug_assert!(size <= 8);
+        debug_assert!(LEN <= 8);
         debug_assert!(nbuf < BUFFER_SIZE);
-        debug_assert!(nbuf + size < BUFFER_WITH_SPILL_SIZE);
+        debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE);
 
-        if nbuf + size < BUFFER_SIZE {
+        if nbuf + LEN < BUFFER_SIZE {
             unsafe {
                 // The memcpy call is optimized away because the size is known.
                 let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
-                ptr::copy_nonoverlapping(&x as *const _ as *const u8, dst, size);
+                ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN);
             }
 
-            self.nbuf = nbuf + size;
+            self.nbuf = nbuf + LEN;
 
             return;
         }
 
-        unsafe { self.short_write_process_buffer(x) }
+        unsafe { self.short_write_process_buffer(bytes) }
     }
 
     // A specialized write function for values with size <= 8 that should only
@@ -233,18 +231,17 @@ fn short_write<T>(&mut self, x: T) {
     // `self.nbuf` must cause `self.buf` to become fully initialized (and not
     // overflow) if it wasn't already.
     #[inline(never)]
-    unsafe fn short_write_process_buffer<T>(&mut self, x: T) {
-        let size = mem::size_of::<T>();
+    unsafe fn short_write_process_buffer<const LEN: usize>(&mut self, bytes: [u8; LEN]) {
         let nbuf = self.nbuf;
-        debug_assert!(size <= 8);
+        debug_assert!(LEN <= 8);
         debug_assert!(nbuf < BUFFER_SIZE);
-        debug_assert!(nbuf + size >= BUFFER_SIZE);
-        debug_assert!(nbuf + size < BUFFER_WITH_SPILL_SIZE);
+        debug_assert!(nbuf + LEN >= BUFFER_SIZE);
+        debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE);
 
         // Copy first part of input into end of buffer, possibly into spill
         // element. The memcpy call is optimized away because the size is known.
         let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
-        ptr::copy_nonoverlapping(&x as *const _ as *const u8, dst, size);
+        ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN);
 
         // Process buffer.
         for i in 0..BUFFER_CAPACITY {
@@ -254,17 +251,17 @@ unsafe fn short_write_process_buffer<T>(&mut self, x: T) {
             self.state.v0 ^= elem;
         }
 
-        // Copy remaining input into start of buffer by copying size - 1
-        // elements from spill (at most size - 1 bytes could have overflowed
+        // Copy remaining input into start of buffer by copying LEN - 1
+        // elements from spill (at most LEN - 1 bytes could have overflowed
         // into the spill). The memcpy call is optimized away because the size
-        // is known. And the whole copy is optimized away for size == 1.
+        // is known. And the whole copy is optimized away for LEN == 1.
         let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8;
-        ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, size - 1);
+        ptr::copy_nonoverlapping(src, self.buf.as_mut_ptr() as *mut u8, LEN - 1);
 
         // This function should only be called when the write fills the buffer.
-        // Therefore, when size == 1, the new `self.nbuf` must be zero. The size
-        // is statically known, so the branch is optimized away.
-        self.nbuf = if size == 1 { 0 } else { nbuf + size - BUFFER_SIZE };
+        // Therefore, when LEN == 1, the new `self.nbuf` must be zero.
+        // LEN is statically known, so the branch is optimized away.
+        self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE };
         self.processed += BUFFER_SIZE;
     }
 
@@ -412,52 +409,52 @@ pub fn finish128(mut self) -> (u64, u64) {
 impl Hasher for SipHasher128 {
     #[inline]
     fn write_u8(&mut self, i: u8) {
-        self.short_write(i);
+        self.short_write(i.to_ne_bytes());
     }
 
     #[inline]
     fn write_u16(&mut self, i: u16) {
-        self.short_write(i);
+        self.short_write(i.to_ne_bytes());
     }
 
     #[inline]
     fn write_u32(&mut self, i: u32) {
-        self.short_write(i);
+        self.short_write(i.to_ne_bytes());
     }
 
     #[inline]
     fn write_u64(&mut self, i: u64) {
-        self.short_write(i);
+        self.short_write(i.to_ne_bytes());
     }
 
     #[inline]
     fn write_usize(&mut self, i: usize) {
-        self.short_write(i);
+        self.short_write(i.to_ne_bytes());
     }
 
     #[inline]
     fn write_i8(&mut self, i: i8) {
-        self.short_write(i as u8);
+        self.short_write((i as u8).to_ne_bytes());
     }
 
     #[inline]
     fn write_i16(&mut self, i: i16) {
-        self.short_write(i as u16);
+        self.short_write((i as u16).to_ne_bytes());
     }
 
     #[inline]
     fn write_i32(&mut self, i: i32) {
-        self.short_write(i as u32);
+        self.short_write((i as u32).to_ne_bytes());
     }
 
     #[inline]
     fn write_i64(&mut self, i: i64) {
-        self.short_write(i as u64);
+        self.short_write((i as u64).to_ne_bytes());
     }
 
     #[inline]
     fn write_isize(&mut self, i: isize) {
-        self.short_write(i as usize);
+        self.short_write((i as usize).to_ne_bytes());
     }
 
     #[inline]
index b4cc85293f7c19b84d27b612d0b09f56a25f7cd6..8a50179cd3b642144113181bfe7d72ea8aad4cec 100644 (file)
@@ -13,6 +13,7 @@
 pub type SnapshotMapStorage<K, V> = SnapshotMap<K, V, FxHashMap<K, V>, ()>;
 pub type SnapshotMapRef<'a, K, V, L> = SnapshotMap<K, V, &'a mut FxHashMap<K, V>, &'a mut L>;
 
+#[derive(Clone)]
 pub struct SnapshotMap<K, V, M = FxHashMap<K, V>, L = VecLog<UndoLog<K, V>>> {
     map: M,
     undo_log: L,
@@ -30,6 +31,7 @@ fn default() -> Self {
     }
 }
 
+#[derive(Clone)]
 pub enum UndoLog<K, V> {
     Inserted(K),
     Overwrite(K, V),
index 1495521ddbb5433967bdba3c79f06511e09d86c2..31d6a42cf288405d8e624f2fc40247227135b6cc 100644 (file)
@@ -80,22 +80,22 @@ fn write_u8(&mut self, i: u8) {
 
     #[inline]
     fn write_u16(&mut self, i: u16) {
-        self.state.write_u16(i.to_le());
+        self.state.short_write(i.to_le_bytes());
     }
 
     #[inline]
     fn write_u32(&mut self, i: u32) {
-        self.state.write_u32(i.to_le());
+        self.state.short_write(i.to_le_bytes());
     }
 
     #[inline]
     fn write_u64(&mut self, i: u64) {
-        self.state.write_u64(i.to_le());
+        self.state.short_write(i.to_le_bytes());
     }
 
     #[inline]
     fn write_u128(&mut self, i: u128) {
-        self.state.write_u128(i.to_le());
+        self.state.write(&i.to_le_bytes());
     }
 
     #[inline]
@@ -103,7 +103,7 @@ fn write_usize(&mut self, i: usize) {
         // Always treat usize as u64 so we get the same results on 32 and 64 bit
         // platforms. This is important for symbol hashes when cross compiling,
         // for example.
-        self.state.write_u64((i as u64).to_le());
+        self.state.short_write((i as u64).to_le_bytes());
     }
 
     #[inline]
@@ -113,38 +113,38 @@ fn write_i8(&mut self, i: i8) {
 
     #[inline]
     fn write_i16(&mut self, i: i16) {
-        self.state.write_i16(i.to_le());
+        self.state.short_write((i as u16).to_le_bytes());
     }
 
     #[inline]
     fn write_i32(&mut self, i: i32) {
-        self.state.write_i32(i.to_le());
+        self.state.short_write((i as u32).to_le_bytes());
     }
 
     #[inline]
     fn write_i64(&mut self, i: i64) {
-        self.state.write_i64(i.to_le());
+        self.state.short_write((i as u64).to_le_bytes());
     }
 
     #[inline]
     fn write_i128(&mut self, i: i128) {
-        self.state.write_i128(i.to_le());
+        self.state.write(&(i as u128).to_le_bytes());
     }
 
     #[inline]
     fn write_isize(&mut self, i: isize) {
-        // Always treat isize as i64 so we get the same results on 32 and 64 bit
+        // Always treat isize as a 64-bit number so we get the same results on 32 and 64 bit
         // platforms. This is important for symbol hashes when cross compiling,
         // for example. Sign extending here is preferable as it means that the
         // same negative number hashes the same on both 32 and 64 bit platforms.
-        let value = (i as i64).to_le() as u64;
+        let value = i as u64;
 
         // Cold path
         #[cold]
         #[inline(never)]
         fn hash_value(state: &mut SipHasher128, value: u64) {
             state.write_u8(0xFF);
-            state.write_u64(value);
+            state.short_write(value.to_le_bytes());
         }
 
         // `isize` values often seem to have a small (positive) numeric value in practice.
index a84ee3da438c7635697657b83e8fbc573114fd8a..b0d66c32a07adc3f737623ebcb4f78b9aed5e567 100644 (file)
@@ -159,4 +159,5 @@ fn check_hash(a: u64, b: u64) {
     check_hash(0xAAAA, 0xAAAAAA);
     check_hash(0xAAAAAA, 0xAAAAAAAA);
     check_hash(0xFF, 0xFFFFFFFFFFFFFFFF);
+    check_hash(u64::MAX /* -1 */, 1);
 }
index 0f490c33102457af67d7f0eec004eedd32ba2961..3601169528b9d501fc8024c882b105ce4ccc5acd 100644 (file)
@@ -29,7 +29,7 @@
 use rustc_metadata::locator;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
-use rustc_serialize::json::{self, ToJson};
+use rustc_serialize::json::ToJson;
 use rustc_session::config::{nightly_options, CG_OPTIONS, DB_OPTIONS};
 use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
 use rustc_session::cstore::MetadataLoader;
@@ -66,7 +66,7 @@
 const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
     ?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
 
-const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["Z", "C", "crate-type"];
+const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"];
 
 const ICE_REPORT_COMPILER_FLAGS_EXCLUDE: &[&str] = &["metadata", "extra-filename"];
 
@@ -226,7 +226,6 @@ fn run_compiler(
         output_dir: odir,
         file_loader,
         diagnostic_output,
-        stderr: None,
         lint_caps: Default::default(),
         parse_sess_created: None,
         register_lints: None,
@@ -263,7 +262,7 @@ fn run_compiler(
                         describe_lints(compiler.session(), &lint_store, registered_lints);
                         return;
                     }
-                    let should_stop = RustcDefaultCalls::print_crate_info(
+                    let should_stop = print_crate_info(
                         &***compiler.codegen_backend(),
                         compiler.session(),
                         None,
@@ -292,7 +291,7 @@ fn run_compiler(
 
     interface::run_compiler(config, |compiler| {
         let sess = compiler.session();
-        let should_stop = RustcDefaultCalls::print_crate_info(
+        let should_stop = print_crate_info(
             &***compiler.codegen_backend(),
             sess,
             Some(compiler.input()),
@@ -301,13 +300,9 @@ fn run_compiler(
             compiler.temps_dir(),
         )
         .and_then(|| {
-            RustcDefaultCalls::list_metadata(
-                sess,
-                &*compiler.codegen_backend().metadata_loader(),
-                compiler.input(),
-            )
+            list_metadata(sess, &*compiler.codegen_backend().metadata_loader(), compiler.input())
         })
-        .and_then(|| RustcDefaultCalls::try_process_rlink(sess, compiler));
+        .and_then(|| try_process_rlink(sess, compiler));
 
         if should_stop == Compilation::Stop {
             return sess.compile_status();
@@ -512,10 +507,6 @@ pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
     }
 }
 
-/// CompilerCalls instance for a regular rustc build.
-#[derive(Copy, Clone)]
-pub struct RustcDefaultCalls;
-
 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') {
@@ -588,160 +579,157 @@ fn show_content_with_pager(content: &str) {
     }
 }
 
-impl RustcDefaultCalls {
-    pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
-        if sess.opts.debugging_opts.link_only {
-            if let Input::File(file) = compiler.input() {
-                // FIXME: #![crate_type] and #![crate_name] support not implemented yet
-                sess.init_crate_types(collect_crate_types(sess, &[]));
-                let outputs = compiler.build_output_filenames(sess, &[]);
-                let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| {
-                    sess.fatal(&format!("failed to read rlink file: {}", err));
-                });
-                let codegen_results: CodegenResults = json::decode(&rlink_data);
-                let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
-                abort_on_err(result, sess);
-            } else {
-                sess.fatal("rlink must be a file")
-            }
-            Compilation::Stop
+pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation {
+    if sess.opts.debugging_opts.link_only {
+        if let Input::File(file) = compiler.input() {
+            // FIXME: #![crate_type] and #![crate_name] support not implemented yet
+            sess.init_crate_types(collect_crate_types(sess, &[]));
+            let outputs = compiler.build_output_filenames(sess, &[]);
+            let rlink_data = fs::read(file).unwrap_or_else(|err| {
+                sess.fatal(&format!("failed to read rlink file: {}", err));
+            });
+            let mut decoder = rustc_serialize::opaque::Decoder::new(&rlink_data, 0);
+            let codegen_results: CodegenResults = rustc_serialize::Decodable::decode(&mut decoder);
+            let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
+            abort_on_err(result, sess);
         } else {
-            Compilation::Continue
+            sess.fatal("rlink must be a file")
         }
+        Compilation::Stop
+    } else {
+        Compilation::Continue
     }
+}
 
-    pub fn list_metadata(
-        sess: &Session,
-        metadata_loader: &dyn MetadataLoader,
-        input: &Input,
-    ) -> Compilation {
-        if sess.opts.debugging_opts.ls {
-            match *input {
-                Input::File(ref ifile) => {
-                    let path = &(*ifile);
-                    let mut v = Vec::new();
-                    locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v)
-                        .unwrap();
-                    println!("{}", String::from_utf8(v).unwrap());
-                }
-                Input::Str { .. } => {
-                    early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
-                }
+pub fn list_metadata(
+    sess: &Session,
+    metadata_loader: &dyn MetadataLoader,
+    input: &Input,
+) -> Compilation {
+    if sess.opts.debugging_opts.ls {
+        match *input {
+            Input::File(ref ifile) => {
+                let path = &(*ifile);
+                let mut v = Vec::new();
+                locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap();
+                println!("{}", String::from_utf8(v).unwrap());
+            }
+            Input::Str { .. } => {
+                early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
             }
-            return Compilation::Stop;
         }
-
-        Compilation::Continue
+        return Compilation::Stop;
     }
 
-    fn print_crate_info(
-        codegen_backend: &dyn CodegenBackend,
-        sess: &Session,
-        input: Option<&Input>,
-        odir: &Option<PathBuf>,
-        ofile: &Option<PathBuf>,
-        temps_dir: &Option<PathBuf>,
-    ) -> Compilation {
-        use rustc_session::config::PrintRequest::*;
-        // NativeStaticLibs and LinkArgs are special - printed during linking
-        // (empty iterator returns true)
-        if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) {
-            return Compilation::Continue;
-        }
+    Compilation::Continue
+}
 
-        let attrs = match input {
-            None => None,
-            Some(input) => {
-                let result = parse_crate_attrs(sess, input);
-                match result {
-                    Ok(attrs) => Some(attrs),
-                    Err(mut parse_error) => {
-                        parse_error.emit();
-                        return Compilation::Stop;
-                    }
+fn print_crate_info(
+    codegen_backend: &dyn CodegenBackend,
+    sess: &Session,
+    input: Option<&Input>,
+    odir: &Option<PathBuf>,
+    ofile: &Option<PathBuf>,
+    temps_dir: &Option<PathBuf>,
+) -> Compilation {
+    use rustc_session::config::PrintRequest::*;
+    // NativeStaticLibs and LinkArgs are special - printed during linking
+    // (empty iterator returns true)
+    if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) {
+        return Compilation::Continue;
+    }
+
+    let attrs = match input {
+        None => None,
+        Some(input) => {
+            let result = parse_crate_attrs(sess, input);
+            match result {
+                Ok(attrs) => Some(attrs),
+                Err(mut parse_error) => {
+                    parse_error.emit();
+                    return Compilation::Stop;
                 }
             }
-        };
-        for req in &sess.opts.prints {
-            match *req {
-                TargetList => {
-                    let mut targets =
-                        rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
-                    targets.sort_unstable();
-                    println!("{}", targets.join("\n"));
-                }
-                Sysroot => println!("{}", sess.sysroot.display()),
-                TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
-                TargetSpec => println!("{}", sess.target.to_json().pretty()),
-                FileNames | CrateName => {
-                    let input = input.unwrap_or_else(|| {
-                        early_error(ErrorOutputType::default(), "no input file provided")
-                    });
-                    let attrs = attrs.as_ref().unwrap();
-                    let t_outputs = rustc_interface::util::build_output_filenames(
-                        input, odir, ofile, temps_dir, attrs, sess,
-                    );
-                    let id = rustc_session::output::find_crate_name(sess, attrs, input);
-                    if *req == PrintRequest::CrateName {
-                        println!("{}", id);
-                        continue;
-                    }
-                    let crate_types = collect_crate_types(sess, attrs);
-                    for &style in &crate_types {
-                        let fname =
-                            rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
-                        println!("{}", fname.file_name().unwrap().to_string_lossy());
-                    }
+        }
+    };
+    for req in &sess.opts.prints {
+        match *req {
+            TargetList => {
+                let mut targets = rustc_target::spec::TARGETS.iter().copied().collect::<Vec<_>>();
+                targets.sort_unstable();
+                println!("{}", targets.join("\n"));
+            }
+            Sysroot => println!("{}", sess.sysroot.display()),
+            TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
+            TargetSpec => println!("{}", sess.target.to_json().pretty()),
+            FileNames | CrateName => {
+                let input = input.unwrap_or_else(|| {
+                    early_error(ErrorOutputType::default(), "no input file provided")
+                });
+                let attrs = attrs.as_ref().unwrap();
+                let t_outputs = rustc_interface::util::build_output_filenames(
+                    input, odir, ofile, temps_dir, attrs, sess,
+                );
+                let id = rustc_session::output::find_crate_name(sess, attrs, input);
+                if *req == PrintRequest::CrateName {
+                    println!("{}", id);
+                    continue;
                 }
-                Cfg => {
-                    let mut cfgs = sess
-                        .parse_sess
-                        .config
-                        .iter()
-                        .filter_map(|&(name, value)| {
-                            // Note that crt-static is a specially recognized cfg
-                            // directive that's printed out here as part of
-                            // rust-lang/rust#37406, but in general the
-                            // `target_feature` cfg is gated under
-                            // rust-lang/rust#29717. For now this is just
-                            // specifically allowing the crt-static cfg and that's
-                            // it, this is intended to get into Cargo and then go
-                            // through to build scripts.
-                            if (name != sym::target_feature || value != Some(sym::crt_dash_static))
-                                && !sess.is_nightly_build()
-                                && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
-                            {
-                                return None;
-                            }
-
-                            if let Some(value) = value {
-                                Some(format!("{}=\"{}\"", name, value))
-                            } else {
-                                Some(name.to_string())
-                            }
-                        })
-                        .collect::<Vec<String>>();
-
-                    cfgs.sort();
-                    for cfg in cfgs {
-                        println!("{}", cfg);
-                    }
+                let crate_types = collect_crate_types(sess, attrs);
+                for &style in &crate_types {
+                    let fname =
+                        rustc_session::output::filename_for_input(sess, style, &id, &t_outputs);
+                    println!("{}", fname.file_name().unwrap().to_string_lossy());
                 }
-                RelocationModels
-                | CodeModels
-                | TlsModels
-                | TargetCPUs
-                | StackProtectorStrategies
-                | TargetFeatures => {
-                    codegen_backend.print(*req, sess);
+            }
+            Cfg => {
+                let mut cfgs = sess
+                    .parse_sess
+                    .config
+                    .iter()
+                    .filter_map(|&(name, value)| {
+                        // Note that crt-static is a specially recognized cfg
+                        // directive that's printed out here as part of
+                        // rust-lang/rust#37406, but in general the
+                        // `target_feature` cfg is gated under
+                        // rust-lang/rust#29717. For now this is just
+                        // specifically allowing the crt-static cfg and that's
+                        // it, this is intended to get into Cargo and then go
+                        // through to build scripts.
+                        if (name != sym::target_feature || value != Some(sym::crt_dash_static))
+                            && !sess.is_nightly_build()
+                            && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
+                        {
+                            return None;
+                        }
+
+                        if let Some(value) = value {
+                            Some(format!("{}=\"{}\"", name, value))
+                        } else {
+                            Some(name.to_string())
+                        }
+                    })
+                    .collect::<Vec<String>>();
+
+                cfgs.sort();
+                for cfg in cfgs {
+                    println!("{}", cfg);
                 }
-                // Any output here interferes with Cargo's parsing of other printed output
-                NativeStaticLibs => {}
-                LinkArgs => {}
             }
+            RelocationModels
+            | CodeModels
+            | TlsModels
+            | TargetCPUs
+            | StackProtectorStrategies
+            | TargetFeatures => {
+                codegen_backend.print(*req, sess);
+            }
+            // Any output here interferes with Cargo's parsing of other printed output
+            NativeStaticLibs => {}
+            LinkArgs => {}
         }
-        Compilation::Stop
     }
+    Compilation::Stop
 }
 
 /// Prints version information
@@ -1100,31 +1088,31 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<as
 /// debugging, since some ICEs only happens with non-default compiler flags
 /// (and the users don't always report them).
 fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
-    let args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).collect::<Vec<_>>();
-
-    // Avoid printing help because of empty args. This can suggest the compiler
-    // itself is not the program root (consider RLS).
-    if args.len() < 2 {
-        return None;
-    }
+    let mut args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).peekable();
 
-    let matches = handle_options(&args)?;
     let mut result = Vec::new();
     let mut excluded_cargo_defaults = false;
-    for flag in ICE_REPORT_COMPILER_FLAGS {
-        let prefix = if flag.len() == 1 { "-" } else { "--" };
-
-        for content in &matches.opt_strs(flag) {
-            // Split always returns the first element
-            let name = if let Some(first) = content.split('=').next() { first } else { &content };
-
-            let content =
-                if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) { name } else { content };
-
-            if !ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&name) {
-                result.push(format!("{}{} {}", prefix, flag, content));
+    while let Some(arg) = args.next() {
+        if let Some(a) = ICE_REPORT_COMPILER_FLAGS.iter().find(|a| arg.starts_with(*a)) {
+            let content = if arg.len() == a.len() {
+                match args.next() {
+                    Some(arg) => arg.to_string(),
+                    None => continue,
+                }
+            } else if arg.get(a.len()..a.len() + 1) == Some("=") {
+                arg[a.len() + 1..].to_string()
             } else {
+                arg[a.len()..].to_string()
+            };
+            if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| content.starts_with(exc)) {
                 excluded_cargo_defaults = true;
+            } else {
+                result.push(a.to_string());
+                match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| content.starts_with(*s))
+                {
+                    Some(s) => result.push(s.to_string()),
+                    None => result.push(content),
+                }
             }
         }
     }
@@ -1240,6 +1228,15 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
 ///
 /// A custom rustc driver can skip calling this to set up a custom ICE hook.
 pub fn install_ice_hook() {
+    // If the user has not explicitly overriden "RUST_BACKTRACE", then produce
+    // full backtraces. When a compiler ICE happens, we want to gather
+    // as much information as possible to present in the issue opened
+    // by the user. Compiler developers and other rustc users can
+    // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
+    // (e.g. `RUST_BACKTRACE=1`)
+    if std::env::var("RUST_BACKTRACE").is_err() {
+        std::env::set_var("RUST_BACKTRACE", "full");
+    }
     SyncLazy::force(&DEFAULT_HOOK);
 }
 
index c401f65eddaedde02a099bc37ac22533871b9e0d..a72681dbf4e7ede9866d2b620ec9e071cdf3627a 100644 (file)
@@ -97,6 +97,7 @@
 E0185: include_str!("./error_codes/E0185.md"),
 E0186: include_str!("./error_codes/E0186.md"),
 E0191: include_str!("./error_codes/E0191.md"),
+E0192: include_str!("./error_codes/E0192.md"),
 E0193: include_str!("./error_codes/E0193.md"),
 E0195: include_str!("./error_codes/E0195.md"),
 E0197: include_str!("./error_codes/E0197.md"),
 //  E0188, // can not cast an immutable reference to a mutable pointer
 //  E0189, // deprecated: can only cast a boxed pointer to a boxed object
 //  E0190, // deprecated: can only cast a &-pointer to an &-object
-//  E0192, // negative impl only applicable to auto traits
 //  E0194, // merged into E0403
 //  E0196, // cannot determine a type for this closure
     E0208,
index 5fd951b2e86cb906c8f92ec8ec74b9b53b1ca157..deca042a91a5054b30c4a7e29cac91c5f8e31a11 100644 (file)
@@ -1,15 +1,17 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 A negative impl was added on a trait implementation.
 
 Erroneous code example:
 
-```compile_fail,E0192
+```compile_fail
 trait Trait {
     type Bar;
 }
 
 struct Foo;
 
-impl !Trait for Foo { } //~ ERROR E0192
+impl !Trait for Foo { } //~ ERROR
 
 fn main() {}
 ```
index adbf76509ed483cc6bcf893292bdf8b28603b12a..806f0001c60fda3ac92c55637efdcc4b6c79fdf2 100644 (file)
@@ -6,11 +6,16 @@ Erroneous code example:
 0u32 as char; // error: only `u8` can be cast as `char`, not `u32`
 ```
 
-As the error message indicates, only `u8` can be cast into `char`. Example:
+`char` is a Unicode Scalar Value, an integer value from 0 to 0xD7FF and
+0xE000 to 0x10FFFF. (The gap is for surrogate pairs.) Only `u8` always fits in
+those ranges so only `u8` may be cast to `char`.
+
+To allow larger values, use `char::from_u32`, which checks the value is valid.
 
 ```
-let c = 86u8 as char; // ok!
-assert_eq!(c, 'V');
+assert_eq!(86u8 as char, 'V'); // ok!
+assert_eq!(char::from_u32(0x3B1), Some('α')); // ok!
+assert_eq!(char::from_u32(0xD800), None); // not a USV.
 ```
 
 For more information about casts, take a look at the Type cast section in
index bfe2459dc8dc1cf259b2fd72243cbd5112adc7ca..9cb12778a561f8a1782a72a97f38e09f61a9c266 100644 (file)
@@ -161,6 +161,9 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, staged_api, "1.0.0", None, None),
     /// Added for testing E0705; perma-unstable.
     (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
+    /// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions.
+    /// Marked `incomplete` since perma-unstable and unsound.
+    (incomplete, unsafe_pin_internals, "1.60.0", None, None),
     /// Use for stable + negative coherence and strict coherence depending on trait's
     /// rustc_strict_coherence value.
     (active, with_negative_coherence, "1.60.0", None, None),
@@ -277,20 +280,18 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (incomplete, adt_const_params, "1.56.0", Some(44580), None),
     /// Allows defining an `#[alloc_error_handler]`.
     (active, alloc_error_handler, "1.29.0", Some(51540), None),
-    /// Allows a test to fail without failing the whole suite.
-    (active, allow_fail, "1.19.0", Some(46488), None),
     /// Allows explicit discriminants on non-unit enum variants.
     (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),
     /// Allows trait methods with arbitrary self types.
     (active, arbitrary_self_types, "1.23.0", Some(44874), None),
     /// Allows using `const` operands in inline assembly.
-    (active, asm_const, "1.58.0", Some(72016), None),
+    (active, asm_const, "1.58.0", Some(93332), None),
     /// Enables experimental inline assembly support for additional architectures.
-    (active, asm_experimental_arch, "1.58.0", Some(72016), None),
+    (active, asm_experimental_arch, "1.58.0", Some(93335), None),
     /// Allows using `sym` operands in inline assembly.
-    (active, asm_sym, "1.58.0", Some(72016), None),
+    (active, asm_sym, "1.58.0", Some(93333), None),
     /// Allows the `may_unwind` option in inline assembly.
-    (active, asm_unwind, "1.58.0", Some(72016), None),
+    (active, asm_unwind, "1.58.0", Some(93334), None),
     /// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
     (active, associated_const_equality, "1.58.0", Some(92827), None),
     /// Allows the user of associated type bounds.
@@ -311,8 +312,10 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, cfg_sanitize, "1.41.0", Some(39699), None),
     /// Allows `cfg(target_abi = "...")`.
     (active, cfg_target_abi, "1.55.0", Some(80970), None),
-    /// Allows `cfg(target_has_atomic = "...")`.
-    (active, cfg_target_has_atomic, "1.9.0", Some(32976), None),
+    /// Allows `cfg(target_has_atomic_load_store = "...")`.
+    (active, cfg_target_has_atomic, "1.60.0", Some(94039), None),
+    /// Allows `cfg(target_has_atomic_equal_alignment = "...")`.
+    (active, cfg_target_has_atomic_equal_alignment, "1.60.0", Some(93822), None),
     /// Allows `cfg(target_thread_local)`.
     (active, cfg_target_thread_local, "1.7.0", Some(29594), None),
     /// Allow conditional compilation depending on rust version
@@ -332,7 +335,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows using and casting function pointers in a `const fn`.
     (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None),
     /// Allows trait bounds in `const fn`.
-    (active, const_fn_trait_bound, "1.53.0", Some(57563), None),
+    (active, const_fn_trait_bound, "1.53.0", Some(93706), None),
     /// Allows `for _ in _` loops in const contexts.
     (active, const_for, "1.56.0", Some(87575), None),
     /// Allows argument and return position `impl Trait` in a `const fn`.
@@ -533,6 +536,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     ///
     /// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0.
     (active, untagged_unions, "1.13.0", Some(55149), None),
+    /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
+    (active, used_with_arg, "1.60.0", Some(93798), None),
     /// Allows `extern "wasm" fn`
     (active, wasm_abi, "1.53.0", Some(83788), None),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
index 3933746c319ecc89d5e630ec15cdf48c478fe7d5..d9a986aba7d08401122eb1ca053f60af07b9112c 100644 (file)
@@ -26,13 +26,12 @@ macro_rules! cfg_fn {
     // (name in cfg, feature, function to check if the feature is enabled)
     (sym::target_abi, sym::cfg_target_abi, cfg_fn!(cfg_target_abi)),
     (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)),
-    (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
-    (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
     (
         sym::target_has_atomic_equal_alignment,
-        sym::cfg_target_has_atomic,
-        cfg_fn!(cfg_target_has_atomic),
+        sym::cfg_target_has_atomic_equal_alignment,
+        cfg_fn!(cfg_target_has_atomic_equal_alignment),
     ),
+    (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)),
     (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)),
     (sym::version, sym::cfg_version, cfg_fn!(cfg_version)),
     (sym::panic, sym::cfg_panic, cfg_fn!(cfg_panic)),
@@ -324,7 +323,7 @@ pub struct BuiltinAttribute {
     ungated!(export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     ungated!(link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding),
     ungated!(no_mangle, Normal, template!(Word), WarnFollowing),
-    ungated!(used, Normal, template!(Word), WarnFollowing),
+    ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing),
 
     // Limits:
     ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing),
@@ -339,7 +338,6 @@ pub struct BuiltinAttribute {
     ),
 
     // Entry point:
-    ungated!(main, Normal, template!(Word), WarnFollowing),
     ungated!(start, Normal, template!(Word), WarnFollowing),
     ungated!(no_start, CrateLevel, template!(Word), WarnFollowing),
     ungated!(no_main, CrateLevel, template!(Word), WarnFollowing),
@@ -403,7 +401,6 @@ pub struct BuiltinAttribute {
     },
 
     // Testing:
-    gated!(allow_fail, Normal, template!(Word), WarnFollowing, experimental!(allow_fail)),
     gated!(
         test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, custom_test_frameworks,
         "custom test frameworks are an unstable feature",
index b9f3b5ad1b1fce8b5c6aebbf821dbcaa0306b5af..f5f944db5e90b23cbbd63a3a381beb997e566ff1 100644 (file)
@@ -48,6 +48,8 @@ macro_rules! declare_features {
     (removed, advanced_slice_patterns, "1.0.0", Some(62254), None,
      Some("merged into `#![feature(slice_patterns)]`")),
     (removed, allocator, "1.0.0", None, None, None),
+    /// Allows a test to fail without failing the whole suite.
+    (removed, allow_fail, "1.19.0", Some(46488), None, Some("removed due to no clear use cases")),
     (removed, await_macro, "1.38.0", Some(50547), None,
      Some("subsumed by `.await` syntax")),
     /// Allows comparing raw pointers during const eval.
index a43cb0203dd239c757c66cdf4efcc01c33f091c5..e99f61d034fb8b3a340f8fc616f924872296ba29 100644 (file)
@@ -266,59 +266,67 @@ pub enum Res<Id = hir::HirId> {
     ///
     /// **Belongs to the type namespace.**
     PrimTy(hir::PrimTy),
-    /// The `Self` type, optionally with the trait it is associated with
-    /// and optionally with the [`DefId`] of the impl it is associated with.
+    /// The `Self` type, optionally with the [`DefId`] of the trait it belongs to and
+    /// optionally with the [`DefId`] of the item introducing the `Self` type alias.
     ///
     /// **Belongs to the type namespace.**
     ///
-    /// For example, the `Self` in
-    ///
+    /// Examples:
     /// ```
+    /// struct Bar(Box<Self>);
+    /// // `Res::SelfTy { trait_: None, alias_of: Some(Bar) }`
+    ///
     /// trait Foo {
     ///     fn foo() -> Box<Self>;
+    ///     // `Res::SelfTy { trait_: Some(Foo), alias_of: None }`
     /// }
-    /// ```
-    ///
-    /// would have the [`DefId`] of `Foo` associated with it. The `Self` in
-    ///
-    /// ```
-    /// struct Bar;
     ///
     /// impl Bar {
-    ///     fn new() -> Self { Bar }
+    ///     fn blah() {
+    ///         let _: Self;
+    ///         // `Res::SelfTy { trait_: None, alias_of: Some(::{impl#0}) }`
+    ///     }
     /// }
-    /// ```
-    ///
-    /// would have the [`DefId`] of the impl associated with it. Finally, the `Self` in
     ///
-    /// ```
     /// impl Foo for Bar {
-    ///     fn foo() -> Box<Self> { Box::new(Bar) }
+    ///     fn foo() -> Box<Self> {
+    ///     // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
+    ///         let _: Self;
+    ///         // `Res::SelfTy { trait_: Some(Foo), alias_of: Some(::{impl#1}) }`
+    ///
+    ///         todo!()
+    ///     }
     /// }
     /// ```
     ///
-    /// would have both the [`DefId`] of `Foo` and the [`DefId`] of the impl
-    /// associated with it.
-    ///
     /// *See also [`Res::SelfCtor`].*
     ///
     /// -----
     ///
-    /// HACK(min_const_generics): impl self types also have an optional requirement to **not** mention
+    /// HACK(min_const_generics): self types also have an optional requirement to **not** mention
     /// any generic parameters to allow the following with `min_const_generics`:
     /// ```
     /// impl Foo { fn test() -> [u8; std::mem::size_of::<Self>()] { todo!() } }
+    ///
+    /// struct Bar([u8; baz::<Self>()]);
+    /// const fn baz<T>() -> usize { 10 }
     /// ```
     /// We do however allow `Self` in repeat expression even if it is generic to not break code
-    /// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint.
-    ///
-    /// FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
-    SelfTy(
-        /// Optionally, the trait associated with this `Self` type.
-        Option<DefId>,
-        /// Optionally, the impl associated with this `Self` type.
-        Option<(DefId, bool)>,
-    ),
+    /// which already works on stable while causing the `const_evaluatable_unchecked` future compat lint:
+    /// ```
+    /// fn foo<T>() {
+    ///     let _bar = [1_u8; std::mem::size_of::<*mut T>()];
+    /// }
+    /// ```
+    // FIXME(generic_const_exprs): Remove this bodge once that feature is stable.
+    SelfTy {
+        /// The trait this `Self` is a generic arg for.
+        trait_: Option<DefId>,
+        /// The item introducing the `Self` type alias. Can be used in the `type_of` query
+        /// to get the underlying type. Additionally whether the `Self` type is disallowed
+        /// from mentioning generics (i.e. when used in an anonymous constant).
+        alias_to: Option<(DefId, bool)>,
+    },
     /// A tool attribute module; e.g., the `rustfmt` in `#[rustfmt::skip]`.
     ///
     /// **Belongs to the type namespace.**
@@ -550,7 +558,7 @@ pub fn opt_def_id(&self) -> Option<DefId> {
 
             Res::Local(..)
             | Res::PrimTy(..)
-            | Res::SelfTy(..)
+            | Res::SelfTy { .. }
             | Res::SelfCtor(..)
             | Res::ToolMod
             | Res::NonMacroAttr(..)
@@ -573,7 +581,7 @@ pub fn descr(&self) -> &'static str {
             Res::SelfCtor(..) => "self constructor",
             Res::PrimTy(..) => "builtin type",
             Res::Local(..) => "local variable",
-            Res::SelfTy(..) => "self type",
+            Res::SelfTy { .. } => "self type",
             Res::ToolMod => "tool module",
             Res::NonMacroAttr(attr_kind) => attr_kind.descr(),
             Res::Err => "unresolved item",
@@ -596,7 +604,7 @@ pub fn map_id<R>(self, mut map: impl FnMut(Id) -> R) -> Res<R> {
             Res::SelfCtor(id) => Res::SelfCtor(id),
             Res::PrimTy(id) => Res::PrimTy(id),
             Res::Local(id) => Res::Local(map(id)),
-            Res::SelfTy(a, b) => Res::SelfTy(a, b),
+            Res::SelfTy { trait_, alias_to } => Res::SelfTy { trait_, alias_to },
             Res::ToolMod => Res::ToolMod,
             Res::NonMacroAttr(attr_kind) => Res::NonMacroAttr(attr_kind),
             Res::Err => Res::Err,
@@ -620,7 +628,7 @@ pub fn macro_kind(self) -> Option<MacroKind> {
     pub fn ns(&self) -> Option<Namespace> {
         match self {
             Res::Def(kind, ..) => kind.ns(),
-            Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => Some(Namespace::TypeNS),
+            Res::PrimTy(..) | Res::SelfTy { .. } | Res::ToolMod => Some(Namespace::TypeNS),
             Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS),
             Res::NonMacroAttr(..) => Some(Namespace::MacroNS),
             Res::Err => None,
index 43900ba88993e3eb2c3eb4f189fd1aab74b64c00..0961d0131d07cfca16b61f201f9498f26e518b24 100644 (file)
@@ -640,9 +640,8 @@ pub fn is_param_bound(&self, param_def_id: DefId) -> bool {
             _ => return false,
         };
         match path.res {
-            Res::Def(DefKind::TyParam, def_id) | Res::SelfTy(Some(def_id), None) => {
-                def_id == param_def_id
-            }
+            Res::Def(DefKind::TyParam, def_id)
+            | Res::SelfTy { trait_: Some(def_id), alias_to: None } => def_id == param_def_id,
             _ => false,
         }
     }
@@ -2112,7 +2111,6 @@ pub struct ImplItem<'hir> {
     pub ident: Ident,
     pub def_id: LocalDefId,
     pub vis: Visibility<'hir>,
-    pub defaultness: Defaultness,
     pub generics: Generics<'hir>,
     pub kind: ImplItemKind<'hir>,
     pub span: Span,
@@ -3310,6 +3308,6 @@ mod size_asserts {
 
     rustc_data_structures::static_assert_size!(super::Item<'static>, 184);
     rustc_data_structures::static_assert_size!(super::TraitItem<'static>, 128);
-    rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 152);
+    rustc_data_structures::static_assert_size!(super::ImplItem<'static>, 144);
     rustc_data_structures::static_assert_size!(super::ForeignItem<'static>, 136);
 }
index 1d10e79d3007b08eeee1b15f14a854ded24ee924..c55f2a7b03941461ed0e9ca824d69da656f99532 100644 (file)
@@ -141,22 +141,22 @@ pub trait Map<'hir> {
 // Used when no map is actually available, forcing manual implementation of nested visitors.
 impl<'hir> Map<'hir> for ! {
     fn find(&self, _: HirId) -> Option<Node<'hir>> {
-        unreachable!()
+        *self;
     }
     fn body(&self, _: BodyId) -> &'hir Body<'hir> {
-        unreachable!()
+        *self;
     }
     fn item(&self, _: ItemId) -> &'hir Item<'hir> {
-        unreachable!()
+        *self;
     }
     fn trait_item(&self, _: TraitItemId) -> &'hir TraitItem<'hir> {
-        unreachable!()
+        *self;
     }
     fn impl_item(&self, _: ImplItemId) -> &'hir ImplItem<'hir> {
-        unreachable!()
+        *self;
     }
     fn foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> {
-        unreachable!()
+        *self;
     }
 }
 
@@ -1020,12 +1020,10 @@ pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref:
 
 pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let ImplItem { def_id: _, ident, ref vis, ref defaultness, ref generics, ref kind, span: _ } =
-        *impl_item;
+    let ImplItem { def_id: _, ident, ref vis, ref generics, ref kind, span: _ } = *impl_item;
 
     visitor.visit_ident(ident);
     visitor.visit_vis(vis);
-    visitor.visit_defaultness(defaultness);
     visitor.visit_generics(generics);
     match *kind {
         ImplItemKind::Const(ref ty, body) => {
index 0db562f91a6a5499a50b8ed647fdb0326e840a1a..db70002c2d66ac97d99d57ebb2f6da49403e6350 100644 (file)
@@ -8,7 +8,7 @@
 ///
 /// 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
 ///    - Example: find all items with a `#[foo]` attribute on them.
-///    - How: Implement `ItemLikeVisitor` and call `tcx.hir().krate().visit_all_item_likes()`.
+///    - How: Implement `ItemLikeVisitor` and call `tcx.hir().visit_all_item_likes()`.
 ///    - Pro: Efficient; just walks the lists of item-like things, not the nodes themselves.
 ///    - Con: Don't get information about nesting
 ///    - Con: Don't have methods for specific bits of HIR, like "on
@@ -19,9 +19,9 @@
 ///    - Example: Examine each expression to look for its type and do some check or other.
 ///    - How: Implement `intravisit::Visitor` and override the `nested_visit_map()` method
 ///      to return `NestedVisitorMap::OnlyBodies` and use
-///      `tcx.hir().krate().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within
-///      your `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget
-///      to invoke `intravisit::walk_expr()` to keep walking the subparts).
+///      `tcx.hir().visit_all_item_likes(&mut visitor.as_deep_visitor())`. Within your
+///      `intravisit::Visitor` impl, implement methods like `visit_expr()` (don't forget to invoke
+///      `intravisit::walk_expr()` to keep walking the subparts).
 ///    - Pro: Visitor methods for any kind of HIR node, not just item-like things.
 ///    - Pro: Integrates well into dependency tracking.
 ///    - Con: Don't get information about nesting between items
index be4849d0b846e1064ac31b36617a4e74db93b1f4..b299e71c9c4c45f4d78fc95f6cba527b6fe07b75 100644 (file)
 
 pub enum LangItemGroup {
     Op,
+    Fn,
 }
 
-const NUM_GROUPS: usize = 1;
+const NUM_GROUPS: usize = 2;
 
 macro_rules! expand_group {
     () => {
@@ -98,11 +99,12 @@ impl LanguageItems {
             /// Construct an empty collection of lang items and no missing ones.
             pub fn new() -> Self {
                 fn init_none(_: LangItem) -> Option<DefId> { None }
+                const EMPTY: Vec<DefId> = Vec::new();
 
                 Self {
                     items: vec![$(init_none(LangItem::$variant)),*],
                     missing: Vec::new(),
-                    groups: [vec![]; NUM_GROUPS],
+                    groups: [EMPTY; NUM_GROUPS],
                 }
             }
 
@@ -251,9 +253,9 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     DerefTarget,             sym::deref_target,        deref_target,               Target::AssocTy,        GenericRequirement::None;
     Receiver,                sym::receiver,            receiver_trait,             Target::Trait,          GenericRequirement::None;
 
-    Fn,                      kw::Fn,                   fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
-    FnMut,                   sym::fn_mut,              fn_mut_trait,               Target::Trait,          GenericRequirement::Exact(1);
-    FnOnce,                  sym::fn_once,             fn_once_trait,              Target::Trait,          GenericRequirement::Exact(1);
+    Fn(Fn),                  kw::Fn,                   fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
+    FnMut(Fn),               sym::fn_mut,              fn_mut_trait,               Target::Trait,          GenericRequirement::Exact(1);
+    FnOnce(Fn),              sym::fn_once,             fn_once_trait,              Target::Trait,          GenericRequirement::Exact(1);
 
     FnOnceOutput,            sym::fn_once_output,      fn_once_output,             Target::AssocTy,        GenericRequirement::None;
 
@@ -264,8 +266,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     Unpin,                   sym::unpin,               unpin_trait,                Target::Trait,          GenericRequirement::None;
     Pin,                     sym::pin,                 pin_type,                   Target::Struct,         GenericRequirement::None;
 
-    PartialEq,               sym::eq,                  eq_trait,                   Target::Trait,          GenericRequirement::Exact(1);
-    PartialOrd,              sym::partial_ord,         partial_ord_trait,          Target::Trait,          GenericRequirement::Exact(1);
+    PartialEq(Op),           sym::eq,                  eq_trait,                   Target::Trait,          GenericRequirement::Exact(1);
+    PartialOrd(Op),          sym::partial_ord,         partial_ord_trait,          Target::Trait,          GenericRequirement::Exact(1);
 
     // A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
     // various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
@@ -277,7 +279,6 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     Panic,                   sym::panic,               panic_fn,                   Target::Fn,             GenericRequirement::Exact(0);
     PanicFmt,                sym::panic_fmt,           panic_fmt,                  Target::Fn,             GenericRequirement::None;
     PanicDisplay,            sym::panic_display,       panic_display,              Target::Fn,             GenericRequirement::None;
-    PanicStr,                sym::panic_str,           panic_str,                  Target::Fn,             GenericRequirement::None;
     ConstPanicFmt,           sym::const_panic_fmt,     const_panic_fmt,            Target::Fn,             GenericRequirement::None;
     PanicBoundsCheck,        sym::panic_bounds_check,  panic_bounds_check_fn,      Target::Fn,             GenericRequirement::Exact(0);
     PanicInfo,               sym::panic_info,          panic_info,                 Target::Struct,         GenericRequirement::None;
index b15054ae6d610420d8133002a6d68f776e5ca8f9..61f03442d61f204d1f0ba83a7c06fe00133b1b95 100644 (file)
@@ -164,13 +164,11 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
 
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for ImplItem<'_> {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        let ImplItem { def_id: _, ident, ref vis, defaultness, ref generics, ref kind, span } =
-            *self;
+        let ImplItem { def_id: _, ident, ref vis, ref generics, ref kind, span } = *self;
 
         hcx.hash_hir_item_like(|hcx| {
             ident.name.hash_stable(hcx, hasher);
             vis.hash_stable(hcx, hasher);
-            defaultness.hash_stable(hcx, hasher);
             generics.hash_stable(hcx, hasher);
             kind.hash_stable(hcx, hasher);
             span.hash_stable(hcx, hasher);
@@ -208,6 +206,9 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         // We ignore the `nodes` and `bodies` fields since these refer to information included in
         // `hash` which is hashed in the collector and used for the crate hash.
+        // `local_id_to_def_id` is also ignored because is dependent on the body, then just hashing
+        // the body satisfies the condition of two nodes being different have different
+        // `hash_stable` results.
         let OwnerNodes {
             hash_including_bodies,
             hash_without_bodies: _,
index a47ebaf1237a1ec611a12dc642a13faef5414fc6..8e45b636f47f706e2552e143325fcb500d8edf9a 100644 (file)
@@ -139,7 +139,7 @@ fn print_generic_args(&mut self, _: &ast::GenericArgs, _colons_before_params: bo
     }
 }
 
-pub const INDENT_UNIT: usize = 4;
+pub const INDENT_UNIT: isize = 4;
 
 /// Requires you to pass an input filename and reader so that
 /// it can scan the input text for comments to copy forward.
@@ -923,7 +923,6 @@ pub fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) {
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(ii.span.lo());
         self.print_outer_attributes(self.attrs(ii.hir_id()));
-        self.print_defaultness(ii.defaultness);
 
         match ii.kind {
             hir::ImplItemKind::Const(ref ty, expr) => {
index cf86c450a5bccff15950f986d196ee1e4f46b248..7f376c5fbe54b71a9937151c12e86b67ad9bddf1 100644 (file)
@@ -852,11 +852,7 @@ pub fn insert_range(&mut self, elems: impl RangeBounds<T>) {
             Bound::Excluded(end) => end.index(),
             Bound::Unbounded => self.domain_size() - 1,
         };
-        let len = if let Some(l) = end.checked_sub(start) {
-            l
-        } else {
-            return;
-        };
+        let Some(len) = end.checked_sub(start) else { return };
         match self {
             HybridBitSet::Sparse(sparse) if sparse.len() + len < SPARSE_MAX => {
                 // The set is sparse and has space for `elems`.
index 147061dafeb1ed555e543024173fe9ac92f79d8f..94991fdb2011091c75af7bf1284e0ec394bbc059 100644 (file)
@@ -51,6 +51,28 @@ pub fn at(
     ) -> At<'a, 'tcx> {
         At { infcx: self, cause, param_env }
     }
+
+    /// Forks the inference context, creating a new inference context with the same inference
+    /// variables in the same state. This can be used to "branch off" many tests from the same
+    /// common state. Used in coherence.
+    pub fn fork(&self) -> Self {
+        Self {
+            tcx: self.tcx.clone(),
+            defining_use_anchor: self.defining_use_anchor.clone(),
+            in_progress_typeck_results: self.in_progress_typeck_results.clone(),
+            inner: self.inner.clone(),
+            skip_leak_check: self.skip_leak_check.clone(),
+            lexical_region_resolutions: self.lexical_region_resolutions.clone(),
+            selection_cache: self.selection_cache.clone(),
+            evaluation_cache: self.evaluation_cache.clone(),
+            reported_trait_errors: self.reported_trait_errors.clone(),
+            reported_closure_mismatch: self.reported_closure_mismatch.clone(),
+            tainted_by_errors_flag: self.tainted_by_errors_flag.clone(),
+            err_count_on_creation: self.err_count_on_creation,
+            in_snapshot: self.in_snapshot.clone(),
+            universe: self.universe.clone(),
+        }
+    }
 }
 
 pub trait ToTrace<'tcx>: Relate<'tcx> + Copy {
@@ -258,7 +280,10 @@ fn to_trace(
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
-        TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
+        TypeTrace {
+            cause: cause.clone(),
+            values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+        }
     }
 }
 
@@ -274,7 +299,7 @@ fn to_trace(
     }
 }
 
-impl<'tcx> ToTrace<'tcx> for &'tcx Const<'tcx> {
+impl<'tcx> ToTrace<'tcx> for Const<'tcx> {
     fn to_trace(
         _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
@@ -282,27 +307,22 @@ fn to_trace(
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
-        TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) }
+        TypeTrace {
+            cause: cause.clone(),
+            values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+        }
     }
 }
 
 impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> {
     fn to_trace(
-        tcx: TyCtxt<'tcx>,
+        _: TyCtxt<'tcx>,
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
-        match (a, b) {
-            (ty::Term::Ty(a), ty::Term::Ty(b)) => {
-                ToTrace::to_trace(tcx, cause, a_is_expected, a, b)
-            }
-            (ty::Term::Const(a), ty::Term::Const(b)) => {
-                ToTrace::to_trace(tcx, cause, a_is_expected, a, b)
-            }
-            (_, _) => todo!(),
-        }
+        TypeTrace { cause: cause.clone(), values: Terms(ExpectedFound::new(a_is_expected, a, b)) }
     }
 }
 
@@ -348,7 +368,7 @@ fn to_trace(
         let b_ty = tcx.mk_projection(b.item_def_id, b.substs);
         TypeTrace {
             cause: cause.clone(),
-            values: Types(ExpectedFound::new(a_is_expected, a_ty, b_ty)),
+            values: Terms(ExpectedFound::new(a_is_expected, a_ty.into(), b_ty.into())),
         }
     }
 }
index 9d40b3cba2952eb48d96b3cb4552bd0f8cb27824..5e67c8cfa27c4a73cc0799ace0fed0efa64de974 100644 (file)
@@ -49,6 +49,31 @@ pub fn canonicalize_query<V>(
         Canonicalizer::canonicalize(value, self, self.tcx, &CanonicalizeAllFreeRegions, query_state)
     }
 
+    /// Like [Self::canonicalize_query], but preserves distinct universes. For
+    /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and
+    /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1`
+    /// in `U2`.
+    ///
+    /// This is used for Chalk integration.
+    pub fn canonicalize_query_preserving_universes<V>(
+        &self,
+        value: V,
+        query_state: &mut OriginalQueryValues<'tcx>,
+    ) -> Canonicalized<'tcx, V>
+    where
+        V: TypeFoldable<'tcx>,
+    {
+        self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed);
+
+        Canonicalizer::canonicalize(
+            value,
+            self,
+            self.tcx,
+            &CanonicalizeAllFreeRegionsPreservingUniverses,
+            query_state,
+        )
+    }
+
     /// Canonicalizes a query *response* `V`. When we canonicalize a
     /// query response, we only canonicalize unbound inference
     /// variables, and we leave other free regions alone. So,
@@ -133,7 +158,7 @@ pub fn canonicalize_query_keep_static<V>(
 /// maximally general query. But if we are canonicalizing a *query
 /// response*, then we don't typically replace free regions, as they
 /// must have been introduced from other parts of the system.
-trait CanonicalizeRegionMode {
+trait CanonicalizeMode {
     fn canonicalize_free_region<'tcx>(
         &self,
         canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -141,17 +166,20 @@ fn canonicalize_free_region<'tcx>(
     ) -> ty::Region<'tcx>;
 
     fn any(&self) -> bool;
+
+    // Do we preserve universe of variables.
+    fn preserve_universes(&self) -> bool;
 }
 
 struct CanonicalizeQueryResponse;
 
-impl CanonicalizeRegionMode for CanonicalizeQueryResponse {
+impl CanonicalizeMode for CanonicalizeQueryResponse {
     fn canonicalize_free_region<'tcx>(
         &self,
         canonicalizer: &mut Canonicalizer<'_, 'tcx>,
         r: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
-        match r {
+        match *r {
             ty::ReFree(_)
             | ty::ReErased
             | ty::ReStatic
@@ -159,12 +187,12 @@ fn canonicalize_free_region<'tcx>(
             | ty::ReEarlyBound(..) => r,
 
             ty::RePlaceholder(placeholder) => canonicalizer.canonical_var_for_region(
-                CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(*placeholder) },
+                CanonicalVarInfo { kind: CanonicalVarKind::PlaceholderRegion(placeholder) },
                 r,
             ),
 
             ty::ReVar(vid) => {
-                let universe = canonicalizer.region_var_universe(*vid);
+                let universe = canonicalizer.region_var_universe(vid);
                 canonicalizer.canonical_var_for_region(
                     CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
                     r,
@@ -198,17 +226,21 @@ fn canonicalize_free_region<'tcx>(
     fn any(&self) -> bool {
         false
     }
+
+    fn preserve_universes(&self) -> bool {
+        true
+    }
 }
 
 struct CanonicalizeUserTypeAnnotation;
 
-impl CanonicalizeRegionMode for CanonicalizeUserTypeAnnotation {
+impl CanonicalizeMode for CanonicalizeUserTypeAnnotation {
     fn canonicalize_free_region<'tcx>(
         &self,
         canonicalizer: &mut Canonicalizer<'_, 'tcx>,
         r: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
-        match r {
+        match *r {
             ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReErased | ty::ReStatic => r,
             ty::ReVar(_) => canonicalizer.canonical_var_for_region_in_root_universe(r),
             _ => {
@@ -221,11 +253,15 @@ fn canonicalize_free_region<'tcx>(
     fn any(&self) -> bool {
         false
     }
+
+    fn preserve_universes(&self) -> bool {
+        false
+    }
 }
 
 struct CanonicalizeAllFreeRegions;
 
-impl CanonicalizeRegionMode for CanonicalizeAllFreeRegions {
+impl CanonicalizeMode for CanonicalizeAllFreeRegions {
     fn canonicalize_free_region<'tcx>(
         &self,
         canonicalizer: &mut Canonicalizer<'_, 'tcx>,
@@ -237,26 +273,54 @@ fn canonicalize_free_region<'tcx>(
     fn any(&self) -> bool {
         true
     }
+
+    fn preserve_universes(&self) -> bool {
+        false
+    }
+}
+
+struct CanonicalizeAllFreeRegionsPreservingUniverses;
+
+impl CanonicalizeMode for CanonicalizeAllFreeRegionsPreservingUniverses {
+    fn canonicalize_free_region<'tcx>(
+        &self,
+        canonicalizer: &mut Canonicalizer<'_, 'tcx>,
+        r: ty::Region<'tcx>,
+    ) -> ty::Region<'tcx> {
+        let universe = canonicalizer.infcx.universe_of_region(r);
+        canonicalizer.canonical_var_for_region(
+            CanonicalVarInfo { kind: CanonicalVarKind::Region(universe) },
+            r,
+        )
+    }
+
+    fn any(&self) -> bool {
+        true
+    }
+
+    fn preserve_universes(&self) -> bool {
+        true
+    }
 }
 
 struct CanonicalizeFreeRegionsOtherThanStatic;
 
-impl CanonicalizeRegionMode for CanonicalizeFreeRegionsOtherThanStatic {
+impl CanonicalizeMode for CanonicalizeFreeRegionsOtherThanStatic {
     fn canonicalize_free_region<'tcx>(
         &self,
         canonicalizer: &mut Canonicalizer<'_, 'tcx>,
         r: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
-        if let ty::ReStatic = r {
-            r
-        } else {
-            canonicalizer.canonical_var_for_region_in_root_universe(r)
-        }
+        if r.is_static() { r } else { canonicalizer.canonical_var_for_region_in_root_universe(r) }
     }
 
     fn any(&self) -> bool {
         true
     }
+
+    fn preserve_universes(&self) -> bool {
+        false
+    }
 }
 
 struct Canonicalizer<'cx, 'tcx> {
@@ -267,7 +331,7 @@ struct Canonicalizer<'cx, 'tcx> {
     // Note that indices is only used once `var_values` is big enough to be
     // heap-allocated.
     indices: FxHashMap<GenericArg<'tcx>, BoundVar>,
-    canonicalize_region_mode: &'cx dyn CanonicalizeRegionMode,
+    canonicalize_mode: &'cx dyn CanonicalizeMode,
     needs_canonical_flags: TypeFlags,
 
     binder_index: ty::DebruijnIndex,
@@ -311,7 +375,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
                     vid, r
                 );
                 let r = self.tcx.reuse_or_mk_region(r, ty::ReVar(resolved_vid));
-                self.canonicalize_region_mode.canonicalize_free_region(self, r)
+                self.canonicalize_mode.canonicalize_free_region(self, r)
             }
 
             ty::ReStatic
@@ -319,7 +383,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
             | ty::ReFree(_)
             | ty::ReEmpty(_)
             | ty::RePlaceholder(..)
-            | ty::ReErased => self.canonicalize_region_mode.canonicalize_free_region(self, r),
+            | ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
         }
     }
 
@@ -337,8 +401,10 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
                     // `TyVar(vid)` is unresolved, track its universe index in the canonicalized
                     // result.
                     Err(mut ui) => {
-                        // FIXME: perf problem described in #55921.
-                        ui = ty::UniverseIndex::ROOT;
+                        if !self.canonicalize_mode.preserve_universes() {
+                            // FIXME: perf problem described in #55921.
+                            ui = ty::UniverseIndex::ROOT;
+                        }
                         self.canonicalize_ty_var(
                             CanonicalVarInfo {
                                 kind: CanonicalVarKind::Ty(CanonicalTyVarKind::General(ui)),
@@ -409,8 +475,8 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        match ct.val {
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        match ct.val() {
             ty::ConstKind::Infer(InferConst::Var(vid)) => {
                 debug!("canonical: const var found with vid {:?}", vid);
                 match self.infcx.probe_const_var(vid) {
@@ -422,10 +488,12 @@ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
                     // `ConstVar(vid)` is unresolved, track its universe index in the
                     // canonicalized result
                     Err(mut ui) => {
-                        // FIXME: perf problem described in #55921.
-                        ui = ty::UniverseIndex::ROOT;
+                        if !self.canonicalize_mode.preserve_universes() {
+                            // FIXME: perf problem described in #55921.
+                            ui = ty::UniverseIndex::ROOT;
+                        }
                         return self.canonicalize_const_var(
-                            CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty) },
+                            CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty()) },
                             ct,
                         );
                     }
@@ -462,7 +530,7 @@ fn canonicalize<V>(
         value: V,
         infcx: &InferCtxt<'_, 'tcx>,
         tcx: TyCtxt<'tcx>,
-        canonicalize_region_mode: &dyn CanonicalizeRegionMode,
+        canonicalize_region_mode: &dyn CanonicalizeMode,
         query_state: &mut OriginalQueryValues<'tcx>,
     ) -> Canonicalized<'tcx, V>
     where
@@ -493,7 +561,7 @@ fn canonicalize<V>(
         let mut canonicalizer = Canonicalizer {
             infcx,
             tcx,
-            canonicalize_region_mode,
+            canonicalize_mode: canonicalize_region_mode,
             needs_canonical_flags,
             variables: SmallVec::new(),
             query_state,
@@ -504,10 +572,11 @@ fn canonicalize<V>(
 
         // Once we have canonicalized `out_value`, it should not
         // contain anything that ties it to this inference context
-        // anymore, so it should live in the global arena.
-        debug_assert!(!out_value.needs_infer());
+        // anymore.
+        debug_assert!(!out_value.needs_infer() && !out_value.has_placeholders());
 
-        let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables);
+        let canonical_variables =
+            tcx.intern_canonical_var_infos(&canonicalizer.universe_canonicalized_variables());
 
         let max_universe = canonical_variables
             .iter()
@@ -527,6 +596,19 @@ fn canonical_var(&mut self, info: CanonicalVarInfo<'tcx>, kind: GenericArg<'tcx>
 
         let var_values = &mut query_state.var_values;
 
+        let universe = info.universe();
+        if universe != ty::UniverseIndex::ROOT {
+            assert!(self.canonicalize_mode.preserve_universes());
+
+            // Insert universe into the universe map. To preserve the order of the
+            // universes in the value being canonicalized, we don't update the
+            // universe in `info` until we have finished canonicalizing.
+            match query_state.universe_map.binary_search(&universe) {
+                Err(idx) => query_state.universe_map.insert(idx, universe),
+                Ok(_) => {}
+            }
+        }
+
         // This code is hot. `variables` and `var_values` are usually small
         // (fewer than 8 elements ~95% of the time). They are SmallVec's to
         // avoid allocations in those cases. We also don't use `indices` to
@@ -569,6 +651,61 @@ fn canonical_var(&mut self, info: CanonicalVarInfo<'tcx>, kind: GenericArg<'tcx>
         }
     }
 
+    /// Replaces the universe indexes used in `var_values` with their index in
+    /// `query_state.universe_map`. This minimizes the maximum universe used in
+    /// the canonicalized value.
+    fn universe_canonicalized_variables(self) -> SmallVec<[CanonicalVarInfo<'tcx>; 8]> {
+        if self.query_state.universe_map.len() == 1 {
+            return self.variables;
+        }
+
+        let reverse_universe_map: FxHashMap<ty::UniverseIndex, ty::UniverseIndex> = self
+            .query_state
+            .universe_map
+            .iter()
+            .enumerate()
+            .map(|(idx, universe)| (*universe, ty::UniverseIndex::from_usize(idx)))
+            .collect();
+
+        self.variables
+            .iter()
+            .map(|v| CanonicalVarInfo {
+                kind: match v.kind {
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int | CanonicalTyVarKind::Float) => {
+                        return *v;
+                    }
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::General(u)) => {
+                        CanonicalVarKind::Ty(CanonicalTyVarKind::General(reverse_universe_map[&u]))
+                    }
+                    CanonicalVarKind::Region(u) => {
+                        CanonicalVarKind::Region(reverse_universe_map[&u])
+                    }
+                    CanonicalVarKind::Const(u, t) => {
+                        CanonicalVarKind::Const(reverse_universe_map[&u], t)
+                    }
+                    CanonicalVarKind::PlaceholderTy(placeholder) => {
+                        CanonicalVarKind::PlaceholderTy(ty::Placeholder {
+                            universe: reverse_universe_map[&placeholder.universe],
+                            ..placeholder
+                        })
+                    }
+                    CanonicalVarKind::PlaceholderRegion(placeholder) => {
+                        CanonicalVarKind::PlaceholderRegion(ty::Placeholder {
+                            universe: reverse_universe_map[&placeholder.universe],
+                            ..placeholder
+                        })
+                    }
+                    CanonicalVarKind::PlaceholderConst(placeholder) => {
+                        CanonicalVarKind::PlaceholderConst(ty::Placeholder {
+                            universe: reverse_universe_map[&placeholder.universe],
+                            ..placeholder
+                        })
+                    }
+                },
+            })
+            .collect()
+    }
+
     /// Shorthand helper that creates a canonical region variable for
     /// `r` (always in the root universe). The reason that we always
     /// put these variables into the root universe is because this
@@ -632,17 +769,17 @@ fn canonicalize_ty_var(&mut self, info: CanonicalVarInfo<'tcx>, ty_var: Ty<'tcx>
     fn canonicalize_const_var(
         &mut self,
         info: CanonicalVarInfo<'tcx>,
-        const_var: &'tcx ty::Const<'tcx>,
-    ) -> &'tcx ty::Const<'tcx> {
+        const_var: ty::Const<'tcx>,
+    ) -> ty::Const<'tcx> {
         let infcx = self.infcx;
         let bound_to = infcx.shallow_resolve(const_var);
         if bound_to != const_var {
             self.fold_const(bound_to)
         } else {
             let var = self.canonical_var(info, const_var.into());
-            self.tcx().mk_const(ty::Const {
+            self.tcx().mk_const(ty::ConstS {
                 val: ty::ConstKind::Bound(self.binder_index, var),
-                ty: self.fold_ty(const_var.ty),
+                ty: self.fold_ty(const_var.ty()),
             })
         }
     }
index 2d2edb07d9eda871bce69855d3ba3cf8b7446c0a..798568679851913db782e4db41f7f73c9632e661 100644 (file)
@@ -149,7 +149,7 @@ fn instantiate_canonical_var(
                 let universe_mapped = universe_map(universe);
                 let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name };
                 self.tcx
-                    .mk_const(ty::Const {
+                    .mk_const(ty::ConstS {
                         val: ty::ConstKind::Placeholder(placeholder_mapped),
                         ty: name.ty,
                     })
index 5b4a9d9dfad456e43b201933ffe15107eb2f73d9..48d5c21f9eb880ee3ca13963b1a9268d04fbec1a 100644 (file)
@@ -237,10 +237,9 @@ pub fn instantiate_nll_query_response_and_region_obligations<R>(
                 v.var_values[BoundVar::new(index)]
             });
             match (original_value.unpack(), result_value.unpack()) {
-                (
-                    GenericArgKind::Lifetime(ty::ReErased),
-                    GenericArgKind::Lifetime(ty::ReErased),
-                ) => {
+                (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
+                    if re1.is_erased() && re2.is_erased() =>
+                {
                     // No action needed.
                 }
 
@@ -429,7 +428,7 @@ fn query_response_substitution_guess<R>(
                 }
                 GenericArgKind::Lifetime(result_value) => {
                     // e.g., here `result_value` might be `'?1` in the example above...
-                    if let &ty::RegionKind::ReLateBound(debruijn, br) = result_value {
+                    if let ty::ReLateBound(debruijn, br) = *result_value {
                         // ... in which case we would set `canonical_vars[0]` to `Some('static)`.
 
                         // We only allow a `ty::INNERMOST` index in substitutions.
@@ -438,12 +437,12 @@ fn query_response_substitution_guess<R>(
                     }
                 }
                 GenericArgKind::Const(result_value) => {
-                    if let ty::Const { val: ty::ConstKind::Bound(debrujin, b), .. } = result_value {
+                    if let ty::ConstKind::Bound(debrujin, b) = result_value.val() {
                         // ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
 
                         // We only allow a `ty::INNERMOST` index in substitutions.
-                        assert_eq!(*debrujin, ty::INNERMOST);
-                        opt_values[*b] = Some(*original_value);
+                        assert_eq!(debrujin, ty::INNERMOST);
+                        opt_values[b] = Some(*original_value);
                     }
                 }
             }
@@ -558,10 +557,9 @@ fn unify_canonical_vars(
                         obligations
                             .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations());
                     }
-                    (
-                        GenericArgKind::Lifetime(ty::ReErased),
-                        GenericArgKind::Lifetime(ty::ReErased),
-                    ) => {
+                    (GenericArgKind::Lifetime(re1), GenericArgKind::Lifetime(re2))
+                        if re1.is_erased() && re2.is_erased() =>
+                    {
                         // no action needed
                     }
                     (GenericArgKind::Lifetime(v1), GenericArgKind::Lifetime(v2)) => {
@@ -672,7 +670,7 @@ fn push_outlives(
         });
     }
 
-    fn const_equate(&mut self, _a: &'tcx Const<'tcx>, _b: &'tcx Const<'tcx>) {
+    fn const_equate(&mut self, _a: Const<'tcx>, _b: Const<'tcx>) {
         span_bug!(
             self.cause.span(self.infcx.tcx),
             "generic_const_exprs: unreachable `const_equate`"
index a77fd8fae8d20d059cbfc110d90bda00580111d9..e1b5d04ccfb8fc376554d5d3cd5ddc4a39378871 100644 (file)
@@ -123,9 +123,9 @@ pub fn super_combine_tys<R>(
     pub fn super_combine_consts<R>(
         &self,
         relation: &mut R,
-        a: &'tcx ty::Const<'tcx>,
-        b: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>>
     where
         R: ConstEquateRelation<'tcx>,
     {
@@ -139,7 +139,7 @@ pub fn super_combine_consts<R>(
 
         let a_is_expected = relation.a_is_expected();
 
-        match (a.val, b.val) {
+        match (a.val(), b.val()) {
             (
                 ty::ConstKind::Infer(InferConst::Var(a_vid)),
                 ty::ConstKind::Infer(InferConst::Var(b_vid)),
@@ -226,9 +226,9 @@ fn unify_const_variable(
         &self,
         param_env: ty::ParamEnv<'tcx>,
         target_vid: ty::ConstVid<'tcx>,
-        ct: &'tcx ty::Const<'tcx>,
+        ct: ty::Const<'tcx>,
         vid_is_expected: bool,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         let (for_universe, span) = {
             let mut inner = self.inner.borrow_mut();
             let variable_table = &mut inner.const_unification_table();
@@ -451,8 +451,8 @@ fn generalize(
     pub fn add_const_equate_obligation(
         &mut self,
         a_is_expected: bool,
-        a: &'tcx ty::Const<'tcx>,
-        b: &'tcx ty::Const<'tcx>,
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
     ) {
         let predicate = if a_is_expected {
             ty::PredicateKind::ConstEquate(a, b)
@@ -716,12 +716,12 @@ fn regions(
 
     fn consts(
         &mut self,
-        c: &'tcx ty::Const<'tcx>,
-        c2: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+        c: ty::Const<'tcx>,
+        c2: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
 
-        match c.val {
+        match c.val() {
             ty::ConstKind::Infer(InferConst::Var(vid)) => {
                 let mut inner = self.infcx.inner.borrow_mut();
                 let variable_table = &mut inner.const_unification_table();
@@ -739,7 +739,7 @@ fn consts(
                                 origin: var_value.origin,
                                 val: ConstVariableValue::Unknown { universe: self.for_universe },
                             });
-                            Ok(self.tcx().mk_const_var(new_var_id, c.ty))
+                            Ok(self.tcx().mk_const_var(new_var_id, c.ty()))
                         }
                     }
                 }
@@ -754,8 +754,8 @@ fn consts(
                     substs,
                     substs,
                 )?;
-                Ok(self.tcx().mk_const(ty::Const {
-                    ty: c.ty,
+                Ok(self.tcx().mk_const(ty::ConstS {
+                    ty: c.ty(),
                     val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
                 }))
             }
@@ -768,7 +768,7 @@ pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> {
     /// Register an obligation that both constants must be equal to each other.
     ///
     /// If they aren't equal then the relation doesn't hold.
-    fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
+    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
 }
 
 pub trait RelateResultCompare<'tcx, T> {
@@ -788,7 +788,7 @@ fn compare<F>(&self, t: T, f: F) -> RelateResult<'tcx, T>
 
 pub fn const_unification_error<'tcx>(
     a_is_expected: bool,
-    (a, b): (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>),
+    (a, b): (ty::Const<'tcx>, ty::Const<'tcx>),
 ) -> TypeError<'tcx> {
     TypeError::ConstMismatch(ExpectedFound::new(a_is_expected, a, b))
 }
@@ -915,7 +915,7 @@ fn regions(
         debug_assert_eq!(r, _r);
         debug!("ConstInferUnifier: r={:?}", r);
 
-        match r {
+        match *r {
             // Never make variables for regions bound within the type itself,
             // nor for erased regions.
             ty::ReLateBound(..) | ty::ReErased => {
@@ -945,13 +945,13 @@ fn regions(
     #[tracing::instrument(level = "debug", skip(self))]
     fn consts(
         &mut self,
-        c: &'tcx ty::Const<'tcx>,
-        _c: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+        c: ty::Const<'tcx>,
+        _c: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         debug_assert_eq!(c, _c);
         debug!("ConstInferUnifier: c={:?}", c);
 
-        match c.val {
+        match c.val() {
             ty::ConstKind::Infer(InferConst::Var(vid)) => {
                 // Check if the current unification would end up
                 // unifying `target_vid` with a const which contains
@@ -985,7 +985,7 @@ fn consts(
                                         },
                                     },
                                 );
-                            Ok(self.tcx().mk_const_var(new_var_id, c.ty))
+                            Ok(self.tcx().mk_const_var(new_var_id, c.ty()))
                         }
                     }
                 }
@@ -1000,8 +1000,8 @@ fn consts(
                     substs,
                     substs,
                 )?;
-                Ok(self.tcx().mk_const(ty::Const {
-                    ty: c.ty,
+                Ok(self.tcx().mk_const(ty::ConstS {
+                    ty: c.ty(),
                     val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
                 }))
             }
index 90c0ff9226f7783618ff2219672a0965043cfa73..5ac9ad6850c4040ce4a8029682807c5711130fe5 100644 (file)
@@ -117,9 +117,9 @@ fn regions(
 
     fn consts(
         &mut self,
-        a: &'tcx ty::Const<'tcx>,
-        b: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         self.fields.infcx.super_combine_consts(self, a, b)
     }
 
@@ -143,7 +143,7 @@ fn binders<T>(
 }
 
 impl<'tcx> ConstEquateRelation<'tcx> for Equate<'_, '_, 'tcx> {
-    fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
+    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
         self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
     }
 }
index 1eb8190bd7d2fb5d5747640174ed1692fb6ba620..d900379c44c629a9c29ee6d919c9c0db1dbce46c 100644 (file)
@@ -239,7 +239,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
     );
 
     // Explain the region we are capturing.
-    match hidden_region {
+    match *hidden_region {
         ty::ReEmpty(ty::UniverseIndex::ROOT) => {
             // All lifetimes shorter than the function body are `empty` in
             // lexical region resolution. The default explanation of "an empty
@@ -515,7 +515,7 @@ fn print_dyn_existential(
                 Err(NonTrivialPath)
             }
 
-            fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+            fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
                 Err(NonTrivialPath)
             }
 
@@ -915,13 +915,13 @@ fn cmp_type_arg(
     ) -> Option<()> {
         for (i, ta) in sub.types().enumerate() {
             if ta == other_ty {
-                self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty);
+                self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, other_ty);
                 return Some(());
             }
             if let ty::Adt(def, _) = ta.kind() {
                 let path_ = self.tcx.def_path_str(def.did);
                 if path_ == other_path {
-                    self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty);
+                    self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, other_ty);
                     return Some(());
                 }
             }
@@ -1036,7 +1036,7 @@ fn cmp_fn_sig(
         let len2 = sig2.inputs().len();
         if len1 == len2 {
             for (i, (l, r)) in iter::zip(sig1.inputs(), sig2.inputs()).enumerate() {
-                let (x1, x2) = self.cmp(l, r);
+                let (x1, x2) = self.cmp(*l, *r);
                 (values.0).0.extend(x1.0);
                 (values.1).0.extend(x2.0);
                 self.push_comma(&mut values.0, &mut values.1, len1, i);
@@ -1114,7 +1114,7 @@ fn equals<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
         }
 
         fn push_ty_ref<'tcx>(
-            region: &ty::Region<'tcx>,
+            region: ty::Region<'tcx>,
             ty: Ty<'tcx>,
             mutbl: hir::Mutability,
             s: &mut DiagnosticStyledString,
@@ -1263,7 +1263,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
                             path1.clone(),
                             sub_no_defaults_1,
                             path2.clone(),
-                            &t2,
+                            t2,
                         )
                         .is_some()
                     {
@@ -1281,7 +1281,7 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
                             path2,
                             sub_no_defaults_2,
                             path1,
-                            &t1,
+                            t1,
                         )
                         .is_some()
                     {
@@ -1333,26 +1333,26 @@ fn lifetime_display(lifetime: Region<'_>) -> String {
             }
 
             // When finding T != &T, highlight only the borrow
-            (&ty::Ref(r1, ref_ty1, mutbl1), _) if equals(&ref_ty1, &t2) => {
+            (&ty::Ref(r1, ref_ty1, mutbl1), _) if equals(ref_ty1, t2) => {
                 let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
-                push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0);
+                push_ty_ref(r1, ref_ty1, mutbl1, &mut values.0);
                 values.1.push_normal(t2.to_string());
                 values
             }
-            (_, &ty::Ref(r2, ref_ty2, mutbl2)) if equals(&t1, &ref_ty2) => {
+            (_, &ty::Ref(r2, ref_ty2, mutbl2)) if equals(t1, ref_ty2) => {
                 let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
                 values.0.push_normal(t1.to_string());
-                push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1);
+                push_ty_ref(r2, ref_ty2, mutbl2, &mut values.1);
                 values
             }
 
             // When encountering &T != &mut T, highlight only the borrow
             (&ty::Ref(r1, ref_ty1, mutbl1), &ty::Ref(r2, ref_ty2, mutbl2))
-                if equals(&ref_ty1, &ref_ty2) =>
+                if equals(ref_ty1, ref_ty2) =>
             {
                 let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new());
-                push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0);
-                push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1);
+                push_ty_ref(r1, ref_ty1, mutbl1, &mut values.0);
+                push_ty_ref(r2, ref_ty2, mutbl2, &mut values.1);
                 values
             }
 
@@ -1582,18 +1582,18 @@ enum Mismatch<'a> {
             None => (None, Mismatch::Fixed("type"), false),
             Some(values) => {
                 let (is_simple_error, exp_found) = match values {
-                    ValuePairs::Types(exp_found) => {
-                        let is_simple_err =
-                            exp_found.expected.is_simple_text() && exp_found.found.is_simple_text();
-                        OpaqueTypesVisitor::visit_expected_found(
-                            self.tcx,
-                            exp_found.expected,
-                            exp_found.found,
-                            span,
-                        )
-                        .report(diag);
+                    ValuePairs::Terms(infer::ExpectedFound {
+                        expected: ty::Term::Ty(expected),
+                        found: ty::Term::Ty(found),
+                    }) => {
+                        let is_simple_err = expected.is_simple_text() && found.is_simple_text();
+                        OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
+                            .report(diag);
 
-                        (is_simple_err, Mismatch::Variable(exp_found))
+                        (
+                            is_simple_err,
+                            Mismatch::Variable(infer::ExpectedFound { expected, found }),
+                        )
                     }
                     ValuePairs::TraitRefs(_) => (false, Mismatch::Fixed("trait")),
                     _ => (false, Mismatch::Fixed("type")),
@@ -1624,7 +1624,7 @@ enum Mismatch<'a> {
                 };
                 if let Some((sp, msg)) = secondary_span {
                     if swap_secondary_and_primary {
-                        let terr = if let Some(infer::ValuePairs::Types(infer::ExpectedFound {
+                        let terr = if let Some(infer::ValuePairs::Terms(infer::ExpectedFound {
                             expected,
                             ..
                         })) = values
@@ -1923,7 +1923,7 @@ fn suggest_accessing_field_where_appropriate(
                 .iter()
                 .filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
                 .map(|field| (field.name, field.ty(self.tcx, expected_substs)))
-                .find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found))
+                .find(|(_, ty)| same_type_modulo_infer(*ty, exp_found.found))
             {
                 if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
                     if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
@@ -2036,27 +2036,14 @@ pub fn report_and_explain_type_error(
             }
             FailureCode::Error0308(failure_str) => {
                 let mut err = struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str);
-                if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
-                    trace.values
-                {
+                if let Some((expected, found)) = trace.values.ty() {
                     match (expected.kind(), found.kind()) {
                         (ty::Tuple(_), ty::Tuple(_)) => {}
                         // If a tuple of length one was expected and the found expression has
                         // parentheses around it, perhaps the user meant to write `(expr,)` to
                         // build a tuple (issue #86100)
-                        (ty::Tuple(_), _) if expected.tuple_fields().count() == 1 => {
-                            if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span) {
-                                if let Some(code) =
-                                    code.strip_prefix('(').and_then(|s| s.strip_suffix(')'))
-                                {
-                                    err.span_suggestion(
-                                        span,
-                                        "use a trailing comma to create a tuple with one element",
-                                        format!("({},)", code),
-                                        Applicability::MaybeIncorrect,
-                                    );
-                                }
-                            }
+                        (ty::Tuple(_), _) => {
+                            self.emit_tuple_wrap_err(&mut err, span, found, expected)
                         }
                         // If a character was expected and the found expression is a string literal
                         // containing a single character, perhaps the user meant to write `'c'` to
@@ -2066,7 +2053,7 @@ pub fn report_and_explain_type_error(
                                 if let Some(code) =
                                     code.strip_prefix('"').and_then(|s| s.strip_suffix('"'))
                                 {
-                                    if code.chars().nth(1).is_none() {
+                                    if code.chars().count() == 1 {
                                         err.span_suggestion(
                                             span,
                                             "if you meant to write a `char` literal, use single quotes",
@@ -2119,14 +2106,48 @@ pub fn report_and_explain_type_error(
         diag
     }
 
+    fn emit_tuple_wrap_err(
+        &self,
+        err: &mut DiagnosticBuilder<'tcx>,
+        span: Span,
+        found: Ty<'tcx>,
+        expected: Ty<'tcx>,
+    ) {
+        let [expected_tup_elem] = &expected.tuple_fields().collect::<Vec<_>>()[..]
+            else { return };
+
+        if !same_type_modulo_infer(*expected_tup_elem, found) {
+            return;
+        }
+
+        let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
+            else { return };
+
+        let msg = "use a trailing comma to create a tuple with one element";
+        if code.starts_with('(') && code.ends_with(')') {
+            let before_close = span.hi() - BytePos::from_u32(1);
+            err.span_suggestion(
+                span.with_hi(before_close).shrink_to_hi(),
+                msg,
+                ",".into(),
+                Applicability::MachineApplicable,
+            );
+        } else {
+            err.multipart_suggestion(
+                msg,
+                vec![(span.shrink_to_lo(), "(".into()), (span.shrink_to_hi(), ",)".into())],
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     fn values_str(
         &self,
         values: ValuePairs<'tcx>,
     ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
         match values {
-            infer::Types(exp_found) => self.expected_found_str_ty(exp_found),
             infer::Regions(exp_found) => self.expected_found_str(exp_found),
-            infer::Consts(exp_found) => self.expected_found_str(exp_found),
+            infer::Terms(exp_found) => self.expected_found_str_term(exp_found),
             infer::TraitRefs(exp_found) => {
                 let pretty_exp_found = ty::error::ExpectedFound {
                     expected: exp_found.expected.print_only_trait_path(),
@@ -2154,16 +2175,22 @@ fn values_str(
         }
     }
 
-    fn expected_found_str_ty(
+    fn expected_found_str_term(
         &self,
-        exp_found: ty::error::ExpectedFound<Ty<'tcx>>,
+        exp_found: ty::error::ExpectedFound<ty::Term<'tcx>>,
     ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
         let exp_found = self.resolve_vars_if_possible(exp_found);
         if exp_found.references_error() {
             return None;
         }
 
-        Some(self.cmp(exp_found.expected, exp_found.found))
+        Some(match (exp_found.expected, exp_found.found) {
+            (ty::Term::Ty(expected), ty::Term::Ty(found)) => self.cmp(expected, found),
+            (expected, found) => (
+                DiagnosticStyledString::highlighted(expected.to_string()),
+                DiagnosticStyledString::highlighted(found.to_string()),
+            ),
+        })
     }
 
     /// Returns a string of the form "expected `{}`, found `{}`".
@@ -2199,7 +2226,7 @@ pub fn construct_generic_bound_failure(
         bound_kind: GenericKind<'tcx>,
         sub: Region<'tcx>,
     ) -> DiagnosticBuilder<'a> {
-        let hir = &self.tcx.hir();
+        let hir = self.tcx.hir();
         // Attempt to obtain the span of the parameter so we can
         // suggest adding an explicit lifetime bound to it.
         let generics = self
index 4c93ec7ab18f1cdaaa3e95c2523e8f1edbc1d2c0..a61100d907bcfd86e845c1e5fb7f69d83dce97b4 100644 (file)
@@ -369,7 +369,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
     pub fn extract_inference_diagnostics_data(
         &self,
         arg: GenericArg<'tcx>,
-        highlight: Option<ty::print::RegionHighlightMode>,
+        highlight: Option<ty::print::RegionHighlightMode<'tcx>>,
     ) -> InferenceDiagnosticsData {
         match arg.unpack() {
             GenericArgKind::Type(ty) => {
@@ -409,7 +409,7 @@ pub fn extract_inference_diagnostics_data(
                 }
             }
             GenericArgKind::Const(ct) => {
-                match ct.val {
+                match ct.val() {
                     ty::ConstKind::Infer(InferConst::Var(vid)) => {
                         let origin = self
                             .inner
@@ -459,7 +459,7 @@ pub fn extract_inference_diagnostics_data(
                                     }
                                     _ => {}
                                 },
-                                GenericArgKind::Const(c) => match c.val {
+                                GenericArgKind::Const(c) => match c.val() {
                                     ty::ConstKind::Infer(InferConst::Var(_)) => {
                                         return self.extract_inference_diagnostics_data(s, None);
                                     }
@@ -553,8 +553,7 @@ pub fn emit_inference_failure_err(
         let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) {
             (_, Some(_)) => String::new(),
             (Some(ty), _) if ty.is_closure() => {
-                let substs =
-                    if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
+                let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
                 let fn_sig = substs.as_closure().sig();
                 let args = closure_args(&fn_sig);
                 let ret = fn_sig.output().skip_binder().to_string();
@@ -597,8 +596,7 @@ pub fn emit_inference_failure_err(
         let param_type = arg_data.kind.descr();
         let suffix = match local_visitor.found_node_ty {
             Some(ty) if ty.is_closure() => {
-                let substs =
-                    if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() };
+                let ty::Closure(_, substs) = *ty.kind() else { unreachable!() };
                 let fn_sig = substs.as_closure().sig();
                 let ret = fn_sig.output().skip_binder().to_string();
 
@@ -935,9 +933,9 @@ fn new(tcx: TyCtxt<'tcx>) -> Self {
     }
 
     /// Replace not yet inferred const params with their def name.
-    fn replace_infers(&self, c: &'tcx Const<'tcx>, index: u32, name: Symbol) -> &'tcx Const<'tcx> {
-        match c.val {
-            ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty),
+    fn replace_infers(&self, c: Const<'tcx>, index: u32, name: Symbol) -> Const<'tcx> {
+        match c.val() {
+            ty::ConstKind::Infer(..) => self.tcx().mk_const_param(index, name, c.ty()),
             _ => c,
         }
     }
@@ -962,7 +960,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
                     .map(|(subst, param)| match &(subst.unpack(), &param.kind) {
                         (_, ty::GenericParamDefKind::Type { has_default: true, .. }) => subst,
                         (crate::infer::GenericArgKind::Const(c), _) => {
-                            self.replace_infers(c, param.index, param.name).into()
+                            self.replace_infers(*c, param.index, param.name).into()
                         }
                         _ => subst.super_fold_with(self),
                     })
@@ -985,7 +983,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
                 }
             }
             ty::Ref(_, ty, _) => {
-                let ty = self.fold_ty(ty);
+                let ty = self.fold_ty(*ty);
                 match ty.kind() {
                     // Avoid `&_`, these can be safely presented as `_`.
                     ty::Error(_) => self.tcx().ty_error(),
@@ -1002,7 +1000,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
             | ty::Projection(_)
             | ty::Never => t.super_fold_with(self),
             ty::Array(ty, c) => {
-                self.tcx().mk_ty(ty::Array(self.fold_ty(ty), self.replace_infers(c, 0, sym::N)))
+                self.tcx().mk_ty(ty::Array(self.fold_ty(*ty), self.replace_infers(*c, 0, sym::N)))
             }
             // We don't want to hide type params that haven't been resolved yet.
             // This would be the type that will be written out with the type param
index d3b47e396ec2ba278e1d2adc3578c82e38327699..ef4c9c24f3eb97c5db7c7f53c69af39ee93a0ebe 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_errors::{Applicability, ErrorReported};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
-use rustc_middle::ty::{self, TypeVisitor};
+use rustc_middle::ty::TypeVisitor;
 use rustc_span::MultiSpan;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -22,7 +22,7 @@ pub(super) fn try_report_mismatched_static_lifetime(&self) -> Option<ErrorReport
             RegionResolutionError::ConcreteFailure(origin, sub, sup) => (origin, sub, sup),
             _ => return None,
         };
-        if *sub != ty::RegionKind::ReStatic {
+        if !sub.is_static() {
             return None;
         }
         let cause = match origin {
index fd295b743420ca799acf2e12dc03e5ffb57ea79b..f44e6e04346b253440244ba96c8785ee9623fcd0 100644 (file)
@@ -64,11 +64,11 @@ pub fn try_report(&self) -> Option<ErrorReported> {
             .or_else(|| self.try_report_mismatched_static_lifetime())
     }
 
-    pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
+    pub(super) fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
         match (&self.error, self.regions) {
-            (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)),
+            (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), *sub, *sup)),
             (Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
-                Some((origin.span(), sub, sup))
+                Some((origin.span(), *sub, *sup))
             }
             (None, Some((span, sub, sup))) => Some((span, sub, sup)),
             _ => None,
index eb1c80ecb018c1454ae38c876ff50557ec532b8d..17ff5d45c89f99180e00652b0e138be87289e4d3 100644 (file)
@@ -48,7 +48,7 @@ pub(super) fn try_report_named_anon_conflict(&self) -> Option<DiagnosticBuilder<
 
         // Suggesting to add a `'static` lifetime to a parameter is nearly always incorrect,
         // and can steer users down the wrong path.
-        if *named == ty::ReStatic {
+        if named.is_static() {
             return None;
         }
 
index 7178bfa525bcb6dd7c8663a88fa5eaf26189be5b..7d82c60e6d3e073fd4f6bf952d8e32dce3b81021 100644 (file)
@@ -3,13 +3,14 @@
 use crate::infer::ValuePairs;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::{ObligationCause, ObligationCauseCode};
+use rustc_data_structures::intern::Interned;
 use rustc_errors::DiagnosticBuilder;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
 
 use std::fmt::{self, Write};
 
@@ -31,15 +32,15 @@ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder
                 vid,
                 _,
                 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
-                sub_placeholder @ ty::RePlaceholder(_),
+                sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
                 _,
-                sup_placeholder @ ty::RePlaceholder(_),
+                sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
                 _,
             )) => self.try_report_trait_placeholder_mismatch(
-                Some(self.tcx().mk_region(ty::ReVar(*vid))),
+                Some(self.tcx().mk_region(ReVar(*vid))),
                 cause,
-                Some(sub_placeholder),
-                Some(sup_placeholder),
+                Some(*sub_placeholder),
+                Some(*sup_placeholder),
                 values,
             ),
 
@@ -47,14 +48,14 @@ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder
                 vid,
                 _,
                 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
-                sub_placeholder @ ty::RePlaceholder(_),
+                sub_placeholder @ Region(Interned(RePlaceholder(_), _)),
                 _,
                 _,
                 _,
             )) => self.try_report_trait_placeholder_mismatch(
-                Some(self.tcx().mk_region(ty::ReVar(*vid))),
+                Some(self.tcx().mk_region(ReVar(*vid))),
                 cause,
-                Some(sub_placeholder),
+                Some(*sub_placeholder),
                 None,
                 values,
             ),
@@ -65,10 +66,10 @@ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder
                 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 _,
                 _,
-                sup_placeholder @ ty::RePlaceholder(_),
+                sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
                 _,
             )) => self.try_report_trait_placeholder_mismatch(
-                Some(self.tcx().mk_region(ty::ReVar(*vid))),
+                Some(self.tcx().mk_region(ReVar(*vid))),
                 cause,
                 None,
                 Some(*sup_placeholder),
@@ -81,10 +82,10 @@ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder
                 _,
                 _,
                 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
-                sup_placeholder @ ty::RePlaceholder(_),
+                sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
                 _,
             )) => self.try_report_trait_placeholder_mismatch(
-                Some(self.tcx().mk_region(ty::ReVar(*vid))),
+                Some(self.tcx().mk_region(ReVar(*vid))),
                 cause,
                 None,
                 Some(*sup_placeholder),
@@ -96,9 +97,9 @@ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder
                 _,
                 _,
                 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
-                sup_placeholder @ ty::RePlaceholder(_),
+                sup_placeholder @ Region(Interned(RePlaceholder(_), _)),
             )) => self.try_report_trait_placeholder_mismatch(
-                Some(self.tcx().mk_region(ty::ReVar(*vid))),
+                Some(self.tcx().mk_region(ReVar(*vid))),
                 cause,
                 None,
                 Some(*sup_placeholder),
@@ -107,8 +108,8 @@ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder
 
             Some(RegionResolutionError::ConcreteFailure(
                 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
-                sub_region @ ty::RePlaceholder(_),
-                sup_region @ ty::RePlaceholder(_),
+                sub_region @ Region(Interned(RePlaceholder(_), _)),
+                sup_region @ Region(Interned(RePlaceholder(_), _)),
             )) => self.try_report_trait_placeholder_mismatch(
                 None,
                 cause,
@@ -119,12 +120,12 @@ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder
 
             Some(RegionResolutionError::ConcreteFailure(
                 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
-                sub_region @ ty::RePlaceholder(_),
+                sub_region @ Region(Interned(RePlaceholder(_), _)),
                 sup_region,
             )) => self.try_report_trait_placeholder_mismatch(
-                (!sup_region.has_name()).then_some(sup_region),
+                (!sup_region.has_name()).then_some(*sup_region),
                 cause,
-                Some(sub_region),
+                Some(*sub_region),
                 None,
                 values,
             ),
@@ -132,12 +133,12 @@ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder
             Some(RegionResolutionError::ConcreteFailure(
                 SubregionOrigin::Subtype(box TypeTrace { cause, values }),
                 sub_region,
-                sup_region @ ty::RePlaceholder(_),
+                sup_region @ Region(Interned(RePlaceholder(_), _)),
             )) => self.try_report_trait_placeholder_mismatch(
-                (!sub_region.has_name()).then_some(sub_region),
+                (!sub_region.has_name()).then_some(*sub_region),
                 cause,
                 None,
-                Some(sup_region),
+                Some(*sup_region),
                 values,
             ),
 
@@ -147,10 +148,10 @@ pub(super) fn try_report_placeholder_conflict(&self) -> Option<DiagnosticBuilder
 
     fn try_report_trait_placeholder_mismatch(
         &self,
-        vid: Option<ty::Region<'tcx>>,
+        vid: Option<Region<'tcx>>,
         cause: &ObligationCause<'tcx>,
-        sub_placeholder: Option<ty::Region<'tcx>>,
-        sup_placeholder: Option<ty::Region<'tcx>>,
+        sub_placeholder: Option<Region<'tcx>>,
+        sup_placeholder: Option<Region<'tcx>>,
         value_pairs: &ValuePairs<'tcx>,
     ) -> Option<DiagnosticBuilder<'tcx>> {
         let (expected_substs, found_substs, trait_def_id) = match value_pairs {
@@ -193,10 +194,10 @@ fn try_report_trait_placeholder_mismatch(
     #[instrument(level = "debug", skip(self))]
     fn report_trait_placeholder_mismatch(
         &self,
-        vid: Option<ty::Region<'tcx>>,
+        vid: Option<Region<'tcx>>,
         cause: &ObligationCause<'tcx>,
-        sub_placeholder: Option<ty::Region<'tcx>>,
-        sup_placeholder: Option<ty::Region<'tcx>>,
+        sub_placeholder: Option<Region<'tcx>>,
+        sup_placeholder: Option<Region<'tcx>>,
         trait_def_id: DefId,
         expected_substs: SubstsRef<'tcx>,
         actual_substs: SubstsRef<'tcx>,
@@ -306,13 +307,13 @@ fn report_trait_placeholder_mismatch(
     fn explain_actual_impl_that_was_found(
         &self,
         err: &mut DiagnosticBuilder<'_>,
-        sub_placeholder: Option<ty::Region<'tcx>>,
-        sup_placeholder: Option<ty::Region<'tcx>>,
+        sub_placeholder: Option<Region<'tcx>>,
+        sup_placeholder: Option<Region<'tcx>>,
         has_sub: Option<usize>,
         has_sup: Option<usize>,
         expected_trait_ref: ty::TraitRef<'tcx>,
         actual_trait_ref: ty::TraitRef<'tcx>,
-        vid: Option<ty::Region<'tcx>>,
+        vid: Option<Region<'tcx>>,
         expected_has_vid: Option<usize>,
         actual_has_vid: Option<usize>,
         any_self_ty_has_vid: bool,
@@ -322,7 +323,7 @@ fn explain_actual_impl_that_was_found(
         #[derive(Copy, Clone)]
         struct Highlighted<'tcx, T> {
             tcx: TyCtxt<'tcx>,
-            highlight: RegionHighlightMode,
+            highlight: RegionHighlightMode<'tcx>,
             value: T,
         }
 
@@ -366,7 +367,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
         let highlight_trait_ref = |trait_ref| Highlighted {
             tcx: self.tcx(),
-            highlight: RegionHighlightMode::default(),
+            highlight: RegionHighlightMode::new(self.tcx()),
             value: trait_ref,
         };
 
index 0a9f59fbc9783dc378000dbf3520de5752927eed..625fd8642186d914e58fc71b82b8d5a7da3a7da8 100644 (file)
@@ -10,8 +10,7 @@
 use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
 use rustc_middle::ty::{
-    self, AssocItemContainer, RegionKind, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable,
-    TypeVisitor,
+    self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable, TypeVisitor,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::{MultiSpan, Span};
@@ -33,25 +32,23 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
                 sup_origin,
                 sup_r,
                 spans,
-            ) if **sub_r == RegionKind::ReStatic => {
-                (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans)
-            }
+            ) if sub_r.is_static() => (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans),
             RegionResolutionError::ConcreteFailure(
                 SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
                 sub_r,
                 sup_r,
-            ) if **sub_r == RegionKind::ReStatic => {
+            ) if sub_r.is_static() => {
                 // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.
                 if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() {
                     // This may have a closure and it would cause ICE
                     // through `find_param_with_region` (#78262).
-                    let anon_reg_sup = tcx.is_suitable_region(sup_r)?;
+                    let anon_reg_sup = tcx.is_suitable_region(*sup_r)?;
                     let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
                     if fn_returns.is_empty() {
                         return None;
                     }
 
-                    let param = self.find_param_with_region(sup_r, sub_r)?;
+                    let param = self.find_param_with_region(*sup_r, *sub_r)?;
                     let lifetime = if sup_r.has_name() {
                         format!("lifetime `{}`", sup_r)
                     } else {
@@ -101,11 +98,11 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
             "try_report_static_impl_trait(var={:?}, sub={:?} {:?} sup={:?} {:?})",
             var_origin, sub_origin, sub_r, sup_origin, sup_r
         );
-        let anon_reg_sup = tcx.is_suitable_region(sup_r)?;
+        let anon_reg_sup = tcx.is_suitable_region(*sup_r)?;
         debug!("try_report_static_impl_trait: anon_reg_sup={:?}", anon_reg_sup);
         let sp = var_origin.span();
         let return_sp = sub_origin.span();
-        let param = self.find_param_with_region(sup_r, sub_r)?;
+        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 {
@@ -560,7 +557,7 @@ fn suggest_constrain_dyn_trait_in_impl(
 impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match t.kind() {
-            ty::Dynamic(preds, RegionKind::ReStatic) => {
+            ty::Dynamic(preds, re) if re.is_static() => {
                 if let Some(def_id) = preds.principal_def_id() {
                     self.0.insert(def_id);
                 }
index bbea450a76973a868c48b05e169bd936b50944c2..9216fa3ca1d31ffc6ec8d6fbabc259544d26cf62 100644 (file)
@@ -2,7 +2,7 @@
 
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::{SubregionOrigin, Subtype, ValuePairs};
+use crate::infer::{SubregionOrigin, Subtype};
 use crate::traits::ObligationCauseCode::CompareImplMethodObligation;
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
@@ -34,16 +34,16 @@ pub(super) fn try_report_impl_not_conforming_to_trait(&self) -> Option<ErrorRepo
         {
             if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) {
                 if let (
-                    ValuePairs::Types(sub_expected_found),
-                    ValuePairs::Types(sup_expected_found),
+                    sub_expected_found @ Some((sub_expected, sub_found)),
+                    sup_expected_found @ Some(_),
                     CompareImplMethodObligation { trait_item_def_id, .. },
-                ) = (&sub_trace.values, &sup_trace.values, sub_trace.cause.code())
+                ) = (&sub_trace.values.ty(), &sup_trace.values.ty(), sub_trace.cause.code())
                 {
                     if sup_expected_found == sub_expected_found {
                         self.emit_err(
                             var_origin.span(),
-                            sub_expected_found.expected,
-                            sub_expected_found.found,
+                            *sub_expected,
+                            *sub_found,
                             *trait_item_def_id,
                         );
                         return Some(ErrorReported);
@@ -81,21 +81,21 @@ fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id:
 
         // Mark all unnamed regions in the type with a number.
         // This diagnostic is called in response to lifetime errors, so be informative.
-        struct HighlightBuilder {
-            highlight: RegionHighlightMode,
+        struct HighlightBuilder<'tcx> {
+            highlight: RegionHighlightMode<'tcx>,
             counter: usize,
         }
 
-        impl HighlightBuilder {
-            fn build(ty: Ty<'_>) -> RegionHighlightMode {
+        impl<'tcx> HighlightBuilder<'tcx> {
+            fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode<'tcx> {
                 let mut builder =
-                    HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 };
+                    HighlightBuilder { highlight: RegionHighlightMode::new(tcx), counter: 1 };
                 builder.visit_ty(ty);
                 builder.highlight
             }
         }
 
-        impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder {
+        impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder<'tcx> {
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if !r.has_name() && self.counter <= 3 {
                     self.highlight.highlighting_region(r, self.counter);
@@ -105,12 +105,12 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
         }
 
-        let expected_highlight = HighlightBuilder::build(expected);
+        let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
         let expected = self
             .infcx
             .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
             .name;
-        let found_highlight = HighlightBuilder::build(found);
+        let found_highlight = HighlightBuilder::build(self.tcx(), found);
         let found =
             self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
 
@@ -203,7 +203,8 @@ fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
                         .map(|res| {
                             matches!(
                                 res,
-                                Res::SelfTy(_, _) | Res::Def(hir::def::DefKind::TyParam, _)
+                                Res::SelfTy { trait_: _, alias_to: _ }
+                                    | Res::Def(hir::def::DefKind::TyParam, _)
                             )
                         })
                         .unwrap_or(false) =>
index 6d71d702cc89b069950d2cf733d37d07eb932b42..719f6b37a434353b2d4c9bb83657a32815868119 100644 (file)
@@ -70,7 +70,7 @@ pub(super) fn find_param_with_region(
                 let ty = fn_sig.inputs()[index];
                 let mut found_anon_region = false;
                 let new_param_ty = self.tcx().fold_regions(ty, &mut false, |r, _| {
-                    if *r == *anon_region {
+                    if r == anon_region {
                         found_anon_region = true;
                         replace_region
                     } else {
index 82bd8890dda21c74dad4edca1f98778ea6052468..8671ecba6e92462e2244ff4a16c5886cb0e8a0e9 100644 (file)
@@ -102,6 +102,9 @@ pub(super) fn note_region_origin(
                     "...so that the definition in impl matches the definition from the trait",
                 );
             }
+            infer::CheckAssociatedTypeBounds { ref parent, .. } => {
+                self.note_region_origin(err, &parent);
+            }
         }
     }
 
@@ -115,7 +118,7 @@ pub(super) fn report_concrete_failure(
             infer::Subtype(box trace) => {
                 let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
                 let mut err = self.report_and_explain_type_error(trace, &terr);
-                match (sub, sup) {
+                match (*sub, *sup) {
                     (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
                     (ty::RePlaceholder(_), _) => {
                         note_and_explain_region(
@@ -345,6 +348,55 @@ pub(super) fn report_concrete_failure(
                     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);
+                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::stable_set::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 where_clause_span = self
+                        .tcx
+                        .hir()
+                        .get_generics(impl_item_def_id.expect_local())
+                        .unwrap()
+                        .where_clause
+                        .tail_span_for_suggestion();
+
+                    let suggestion = format!(
+                        "{} {}",
+                        if !impl_predicates.is_empty() { "," } else { " where" },
+                        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
+            }
         }
     }
 
index e93cdf7942118033c722eb3e2b34976730a769ff..187c67df3eb31cd552c31f3066f03ab13beb717a 100644 (file)
@@ -41,8 +41,8 @@ pub struct FreeRegionMap<'tcx> {
 }
 
 impl<'tcx> FreeRegionMap<'tcx> {
-    pub fn elements(&self) -> impl Iterator<Item = &Region<'tcx>> {
-        self.relation.elements()
+    pub fn elements(&self) -> impl Iterator<Item = Region<'tcx>> + '_ {
+        self.relation.elements().copied()
     }
 
     pub fn is_empty(&self) -> bool {
@@ -91,7 +91,7 @@ fn check_relation(&self, r_a: Region<'tcx>, r_b: Region<'tcx>) -> bool {
 
     /// True for free regions other than `'static`.
     pub fn is_free(&self, r: Region<'_>) -> bool {
-        matches!(r, ty::ReEarlyBound(_) | ty::ReFree(_))
+        matches!(*r, ty::ReEarlyBound(_) | ty::ReFree(_))
     }
 
     /// True if `r` is a free region or static of the sort that this
index 4af1bdf97a773f7e9796b857d02ce31ff6f24b32..e9d3b6a8aa1a4167d777c0645541392bf9529e37 100644 (file)
@@ -46,7 +46,7 @@ pub struct TypeFreshener<'a, 'tcx> {
     ty_freshen_count: u32,
     const_freshen_count: u32,
     ty_freshen_map: FxHashMap<ty::InferTy, Ty<'tcx>>,
-    const_freshen_map: FxHashMap<ty::InferConst<'tcx>, &'tcx ty::Const<'tcx>>,
+    const_freshen_map: FxHashMap<ty::InferConst<'tcx>, ty::Const<'tcx>>,
     keep_static: bool,
 }
 
@@ -89,11 +89,11 @@ fn freshen_ty<F>(
 
     fn freshen_const<F>(
         &mut self,
-        opt_ct: Option<&'tcx ty::Const<'tcx>>,
+        opt_ct: Option<ty::Const<'tcx>>,
         key: ty::InferConst<'tcx>,
         freshener: F,
         ty: Ty<'tcx>,
-    ) -> &'tcx ty::Const<'tcx>
+    ) -> ty::Const<'tcx>
     where
         F: FnOnce(u32) -> ty::InferConst<'tcx>,
     {
@@ -221,8 +221,8 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        match ct.val {
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        match ct.val() {
             ty::ConstKind::Infer(ty::InferConst::Var(v)) => {
                 let opt_ct = self
                     .infcx
@@ -236,7 +236,7 @@ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
                     opt_ct,
                     ty::InferConst::Var(v),
                     ty::InferConst::Fresh,
-                    ct.ty,
+                    ct.ty(),
                 );
             }
             ty::ConstKind::Infer(ty::InferConst::Fresh(i)) => {
index 773753a0363264400be63ce562bae19850ffa3e8..c5c131a5b796bb074ccea1b53c2ae83f03e90069 100644 (file)
@@ -230,14 +230,14 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         r
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if let ty::Const { val: ty::ConstKind::Infer(ty::InferConst::Var(vid)), ty } = ct {
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.val() {
             if self.const_vars.0.contains(&vid) {
                 // This variable was created during the fudging.
                 // Recreate it with a fresh variable here.
                 let idx = (vid.index - self.const_vars.0.start.index) as usize;
                 let origin = self.const_vars.1[idx];
-                self.infcx.next_const_var(ty, origin)
+                self.infcx.next_const_var(ct.ty(), origin)
             } else {
                 ct
             }
index 862f5a5fbb8c1805ca84a47bc2e1ff71f7c9d7d2..381097344ec68eec5e000f22196e5b257d862cfd 100644 (file)
@@ -78,9 +78,9 @@ fn regions(
 
     fn consts(
         &mut self,
-        a: &'tcx ty::Const<'tcx>,
-        b: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         self.fields.infcx.super_combine_consts(self, a, b)
     }
 
@@ -120,7 +120,7 @@ fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResul
 }
 
 impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {
-    fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
+    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
         self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
     }
 }
index ae85e55da6ae321b7a8889ca74e009b1795d401c..82454b89156a6110d5b7a5199aab761ad56e6529 100644 (file)
@@ -94,7 +94,7 @@ pub fn replace_bound_vars_with_placeholders<T>(&self, binder: ty::Binder<'tcx, T
         };
 
         let fld_c = |bound_var: ty::BoundVar, ty| {
-            self.tcx.mk_const(ty::Const {
+            self.tcx.mk_const(ty::ConstS {
                 val: ty::ConstKind::Placeholder(ty::PlaceholderConst {
                     universe: next_universe,
                     name: ty::BoundConst { var: bound_var, ty },
index a5ec84a4f14469591e8fe8fc07b616d1a65cdf63..4e50585ff524f454233fa495b5452a686331b661 100644 (file)
@@ -13,6 +13,7 @@
 use rustc_data_structures::graph::implementation::{
     Direction, Graph, NodeIndex, INCOMING, OUTGOING,
 };
+use rustc_data_structures::intern::Interned;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -61,6 +62,7 @@ pub(crate) fn resolve<'tcx>(
 
 /// Contains the result of lexical region resolution. Offers methods
 /// to lookup up the final value of a region variable.
+#[derive(Clone)]
 pub struct LexicalRegionResolutions<'tcx> {
     values: IndexVec<RegionVid, VarValue<'tcx>>,
     error_region: ty::Region<'tcx>,
@@ -249,8 +251,8 @@ fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
                 changes.push(b_vid);
             }
             if let Some(a_vid) = a_vid {
-                match *b_data {
-                    VarValue::Value(ReStatic) | VarValue::ErrorValue => (),
+                match b_data {
+                    VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue => (),
                     _ => {
                         constraints[a_vid].push((a_vid, b_vid));
                         constraints[b_vid].push((a_vid, b_vid));
@@ -269,7 +271,10 @@ fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
                 if self.expand_node(a_region, b_vid, b_data) {
                     changes.push(b_vid);
                 }
-                !matches!(b_data, VarValue::Value(ReStatic) | VarValue::ErrorValue)
+                !matches!(
+                    b_data,
+                    VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue
+                )
             });
         }
     }
@@ -300,8 +305,8 @@ fn expand_node(
                 // check below for a common case, here purely as an
                 // optimization.
                 let b_universe = self.var_infos[b_vid].universe;
-                if let ReEmpty(a_universe) = a_region {
-                    if *a_universe == b_universe {
+                if let ReEmpty(a_universe) = *a_region {
+                    if a_universe == b_universe {
                         return false;
                     }
                 }
@@ -320,7 +325,7 @@ fn expand_node(
                 // tighter bound than `'static`.
                 //
                 // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
-                if let ty::RePlaceholder(p) = lub {
+                if let ty::RePlaceholder(p) = *lub {
                     if b_universe.cannot_name(p.universe) {
                         lub = self.tcx().lifetimes.re_static;
                     }
@@ -371,12 +376,12 @@ fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
     /// term "concrete regions").
     #[instrument(level = "trace", skip(self))]
     fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
-        let r = match (a, b) {
-            (&ReLateBound(..), _) | (_, &ReLateBound(..)) | (&ReErased, _) | (_, &ReErased) => {
+        let r = match (*a, *b) {
+            (ReLateBound(..), _) | (_, ReLateBound(..)) | (ReErased, _) | (_, ReErased) => {
                 bug!("cannot relate region: LUB({:?}, {:?})", a, b);
             }
 
-            (&ReVar(v_id), _) | (_, &ReVar(v_id)) => {
+            (ReVar(v_id), _) | (_, ReVar(v_id)) => {
                 span_bug!(
                     self.var_infos[v_id].origin.span(),
                     "lub_concrete_regions invoked with non-concrete \
@@ -386,27 +391,32 @@ fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx>
                 );
             }
 
-            (&ReStatic, _) | (_, &ReStatic) => {
+            (ReStatic, _) | (_, ReStatic) => {
                 // nothing lives longer than `'static`
                 self.tcx().lifetimes.re_static
             }
 
-            (&ReEmpty(_), r @ (ReEarlyBound(_) | ReFree(_)))
-            | (r @ (ReEarlyBound(_) | ReFree(_)), &ReEmpty(_)) => {
+            (ReEmpty(_), ReEarlyBound(_) | ReFree(_)) => {
                 // All empty regions are less than early-bound, free,
                 // and scope regions.
-                r
+                b
             }
 
-            (&ReEmpty(a_ui), &ReEmpty(b_ui)) => {
+            (ReEarlyBound(_) | ReFree(_), ReEmpty(_)) => {
+                // All empty regions are less than early-bound, free,
+                // and scope regions.
+                a
+            }
+
+            (ReEmpty(a_ui), ReEmpty(b_ui)) => {
                 // Empty regions are ordered according to the universe
                 // they are associated with.
                 let ui = a_ui.min(b_ui);
                 self.tcx().mk_region(ReEmpty(ui))
             }
 
-            (&ReEmpty(empty_ui), &RePlaceholder(placeholder))
-            | (&RePlaceholder(placeholder), &ReEmpty(empty_ui)) => {
+            (ReEmpty(empty_ui), RePlaceholder(placeholder))
+            | (RePlaceholder(placeholder), ReEmpty(empty_ui)) => {
                 // If this empty region is from a universe that can
                 // name the placeholder, then the placeholder is
                 // larger; otherwise, the only ancestor is `'static`.
@@ -417,13 +427,13 @@ fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx>
                 }
             }
 
-            (&ReEarlyBound(_) | &ReFree(_), &ReEarlyBound(_) | &ReFree(_)) => {
+            (ReEarlyBound(_) | ReFree(_), ReEarlyBound(_) | ReFree(_)) => {
                 self.region_rels.lub_free_regions(a, b)
             }
 
             // For these types, we cannot define any additional
             // relationship:
-            (&RePlaceholder(..), _) | (_, &RePlaceholder(..)) => {
+            (RePlaceholder(..), _) | (_, RePlaceholder(..)) => {
                 if a == b {
                     a
                 } else {
@@ -675,7 +685,7 @@ fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 {
         let node_universe = self.var_infos[node_idx].universe;
 
         for lower_bound in &lower_bounds {
-            let effective_lower_bound = if let ty::RePlaceholder(p) = lower_bound.region {
+            let effective_lower_bound = if let ty::RePlaceholder(p) = *lower_bound.region {
                 if node_universe.cannot_name(p.universe) {
                     self.tcx().lifetimes.re_static
                 } else {
@@ -720,7 +730,7 @@ fn region_order_key(x: &RegionAndOrigin<'_>) -> u8 {
             .expect("lower_vid_bounds should at least include `node_idx`");
 
         for upper_bound in &upper_bounds {
-            if let ty::RePlaceholder(p) = upper_bound.region {
+            if let ty::RePlaceholder(p) = *upper_bound.region {
                 if min_universe.cannot_name(p.universe) {
                     let origin = self.var_infos[node_idx].origin;
                     errors.push(RegionResolutionError::UpperBoundUniverseConflict(
@@ -854,11 +864,11 @@ fn bound_is_met(
             }
 
             VerifyBound::OutlivedBy(r) => {
-                self.sub_concrete_regions(min, var_values.normalize(self.tcx(), r))
+                self.sub_concrete_regions(min, var_values.normalize(self.tcx(), *r))
             }
 
             VerifyBound::IsEmpty => {
-                matches!(min, ty::ReEmpty(_))
+                matches!(*min, ty::ReEmpty(_))
             }
 
             VerifyBound::AnyBound(bs) => {
@@ -883,8 +893,8 @@ fn normalize<T>(&self, tcx: TyCtxt<'tcx>, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
     {
-        tcx.fold_regions(value, &mut false, |r, _db| match r {
-            ty::ReVar(rid) => self.resolve_var(*rid),
+        tcx.fold_regions(value, &mut false, |r, _db| match *r {
+            ty::ReVar(rid) => self.resolve_var(rid),
             _ => r,
         })
     }
index 5191d1c1cc1008c8706a9fcc2d866affe976360a..57cbe2c54f7aec978ddbee9e837b0e54cae8eda9 100644 (file)
@@ -78,9 +78,9 @@ fn regions(
 
     fn consts(
         &mut self,
-        a: &'tcx ty::Const<'tcx>,
-        b: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         self.fields.infcx.super_combine_consts(self, a, b)
     }
 
@@ -103,7 +103,7 @@ fn binders<T>(
 }
 
 impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> {
-    fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
+    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
         self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
     }
 }
index d1b24b332bdcc65b2cef56a189b3f05cdeff0f53..57ac98ca897ee7cf012b151f24d69114b615e855 100644 (file)
@@ -130,6 +130,7 @@ pub fn for_item_body(tcx: TyCtxt<'_>) -> Self {
 /// `RefCell` and are involved with taking/rolling back snapshots. Snapshot
 /// operations are hot enough that we want only one call to `borrow_mut` per
 /// call to `start_snapshot` and `rollback_to`.
+#[derive(Clone)]
 pub struct InferCtxtInner<'tcx> {
     /// Cache for projections. This cache is snapshotted along with the infcx.
     ///
@@ -368,13 +369,26 @@ pub struct InferCtxt<'a, 'tcx> {
 /// See the `error_reporting` module for more details.
 #[derive(Clone, Copy, Debug, PartialEq, Eq, TypeFoldable)]
 pub enum ValuePairs<'tcx> {
-    Types(ExpectedFound<Ty<'tcx>>),
     Regions(ExpectedFound<ty::Region<'tcx>>),
-    Consts(ExpectedFound<&'tcx ty::Const<'tcx>>),
+    Terms(ExpectedFound<ty::Term<'tcx>>),
     TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
     PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
 }
 
+impl<'tcx> ValuePairs<'tcx> {
+    pub fn ty(&self) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
+        if let ValuePairs::Terms(ExpectedFound {
+            expected: ty::Term::Ty(expected),
+            found: ty::Term::Ty(found),
+        }) = self
+        {
+            Some((*expected, *found))
+        } else {
+            None
+        }
+    }
+}
+
 /// The trace designates the path through inference that we took to
 /// encounter an error or subtyping constraint.
 ///
@@ -424,6 +438,13 @@ pub enum SubregionOrigin<'tcx> {
     /// Comparing the signature and requirements of an impl associated type
     /// against the containing trait
     CompareImplTypeObligation { span: Span, impl_item_def_id: DefId, trait_item_def_id: DefId },
+
+    /// Checking that the bounds of a trait's associated type hold for a given impl
+    CheckAssociatedTypeBounds {
+        parent: Box<SubregionOrigin<'tcx>>,
+        impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+    },
 }
 
 // `SubregionOrigin` is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -1065,11 +1086,7 @@ pub fn next_ty_var_in_universe(
         self.tcx.mk_ty_var(vid)
     }
 
-    pub fn next_const_var(
-        &self,
-        ty: Ty<'tcx>,
-        origin: ConstVariableOrigin,
-    ) -> &'tcx ty::Const<'tcx> {
+    pub fn next_const_var(&self, ty: Ty<'tcx>, origin: ConstVariableOrigin) -> ty::Const<'tcx> {
         self.tcx.mk_const_var(self.next_const_var_id(origin), ty)
     }
 
@@ -1078,7 +1095,7 @@ pub fn next_const_var_in_universe(
         ty: Ty<'tcx>,
         origin: ConstVariableOrigin,
         universe: ty::UniverseIndex,
-    ) -> &'tcx ty::Const<'tcx> {
+    ) -> ty::Const<'tcx> {
         let vid = self
             .inner
             .borrow_mut()
@@ -1421,7 +1438,7 @@ pub fn unresolved_type_vars<T>(&self, value: &T) -> Option<(Ty<'tcx>, Option<Spa
     pub fn probe_const_var(
         &self,
         vid: ty::ConstVid<'tcx>,
-    ) -> Result<&'tcx ty::Const<'tcx>, ty::UniverseIndex> {
+    ) -> Result<ty::Const<'tcx>, ty::UniverseIndex> {
         match self.inner.borrow_mut().const_unification_table().probe_value(vid).val {
             ConstVariableValue::Known { value } => Ok(value),
             ConstVariableValue::Unknown { universe } => Err(universe),
@@ -1487,8 +1504,8 @@ pub fn report_mismatched_types(
     pub fn report_mismatched_consts(
         &self,
         cause: &ObligationCause<'tcx>,
-        expected: &'tcx ty::Const<'tcx>,
-        actual: &'tcx ty::Const<'tcx>,
+        expected: ty::Const<'tcx>,
+        actual: ty::Const<'tcx>,
         err: TypeError<'tcx>,
     ) -> DiagnosticBuilder<'tcx> {
         let trace = TypeTrace::consts(cause, true, expected, actual);
@@ -1742,8 +1759,8 @@ pub fn maybe_from_ty(ty: Ty<'tcx>) -> Option<Self> {
 
     /// Tries to extract an inference variable from a constant, returns `None`
     /// for constants other than `ty::ConstKind::Infer(_)` (or `InferConst::Fresh`).
-    pub fn maybe_from_const(ct: &'tcx ty::Const<'tcx>) -> Option<Self> {
-        match ct.val {
+    pub fn maybe_from_const(ct: ty::Const<'tcx>) -> Option<Self> {
+        match ct.val() {
             ty::ConstKind::Infer(InferConst::Var(v)) => Some(TyOrConstInferVar::Const(v)),
             _ => None,
         }
@@ -1763,13 +1780,13 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         self.infcx.shallow_resolve_ty(ty)
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = ct {
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val() {
             self.infcx
                 .inner
                 .borrow_mut()
                 .const_unification_table()
-                .probe_value(*vid)
+                .probe_value(vid)
                 .val
                 .known()
                 .unwrap_or(ct)
@@ -1790,16 +1807,22 @@ pub fn types(
         a: Ty<'tcx>,
         b: Ty<'tcx>,
     ) -> TypeTrace<'tcx> {
-        TypeTrace { cause: cause.clone(), values: Types(ExpectedFound::new(a_is_expected, a, b)) }
+        TypeTrace {
+            cause: cause.clone(),
+            values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+        }
     }
 
     pub fn consts(
         cause: &ObligationCause<'tcx>,
         a_is_expected: bool,
-        a: &'tcx ty::Const<'tcx>,
-        b: &'tcx ty::Const<'tcx>,
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
     ) -> TypeTrace<'tcx> {
-        TypeTrace { cause: cause.clone(), values: Consts(ExpectedFound::new(a_is_expected, a, b)) }
+        TypeTrace {
+            cause: cause.clone(),
+            values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+        }
     }
 }
 
@@ -1816,6 +1839,7 @@ pub fn span(&self) -> Span {
             ReferenceOutlivesReferent(_, a) => a,
             CompareImplMethodObligation { span, .. } => span,
             CompareImplTypeObligation { span, .. } => span,
+            CheckAssociatedTypeBounds { ref parent, .. } => parent.span(),
         }
     }
 
@@ -1846,6 +1870,15 @@ pub fn from_obligation_cause<F>(cause: &traits::ObligationCause<'tcx>, default:
                 trait_item_def_id,
             },
 
+            traits::ObligationCauseCode::CheckAssociatedTypeBounds {
+                impl_item_def_id,
+                trait_item_def_id,
+            } => SubregionOrigin::CheckAssociatedTypeBounds {
+                impl_item_def_id,
+                trait_item_def_id,
+                parent: Box::new(default()),
+            },
+
             _ => default(),
         }
     }
index 0a210ed053ce4ec7f61c9bbc0aa4ea3e0e13c6e5..60f776d8c1f6783750b4a35b2257507d04f278d3 100644 (file)
@@ -87,7 +87,7 @@ fn push_outlives(
         info: ty::VarianceDiagInfo<'tcx>,
     );
 
-    fn const_equate(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>);
+    fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
 
     /// Creates a new universe index. Used when instantiating placeholders.
     fn create_next_universe(&mut self) -> ty::UniverseIndex;
@@ -244,8 +244,8 @@ fn replace_bound_region(
         scopes: &[BoundRegionScope<'tcx>],
     ) -> ty::Region<'tcx> {
         debug!("replace_bound_regions(scopes={:?})", scopes);
-        if let ty::ReLateBound(debruijn, br) = r {
-            Self::lookup_bound_region(*debruijn, br, first_free_index, scopes)
+        if let ty::ReLateBound(debruijn, br) = *r {
+            Self::lookup_bound_region(debruijn, &br, first_free_index, scopes)
         } else {
             r
         }
@@ -450,7 +450,7 @@ fn relate_generalized_ty<D>(
     where
         D: TypeRelatingDelegate<'tcx>,
     {
-        relate.relate(&generalized_ty, &self.value_ty())
+        relate.relate(generalized_ty, self.value_ty())
     }
 }
 
@@ -482,7 +482,7 @@ fn relate_generalized_ty<D>(
     where
         D: TypeRelatingDelegate<'tcx>,
     {
-        relate.relate(&self.value_ty(), &generalized_ty)
+        relate.relate(self.value_ty(), generalized_ty)
     }
 }
 
@@ -609,16 +609,16 @@ fn regions(
 
     fn consts(
         &mut self,
-        a: &'tcx ty::Const<'tcx>,
-        mut b: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+        a: ty::Const<'tcx>,
+        mut b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         let a = self.infcx.shallow_resolve(a);
 
         if !D::forbid_inference_vars() {
             b = self.infcx.shallow_resolve(b);
         }
 
-        match b.val {
+        match b.val() {
             ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
                 // Forbid inference variables in the RHS.
                 bug!("unexpected inference var {:?}", b)
@@ -745,7 +745,7 @@ impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D>
 where
     D: TypeRelatingDelegate<'tcx>,
 {
-    fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
+    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
         self.delegate.const_equate(a, b);
     }
 }
@@ -779,9 +779,9 @@ fn visit_binder<T: TypeFoldable<'tcx>>(
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         let ScopeInstantiator { bound_region_scope, next_region, .. } = self;
 
-        match r {
-            ty::ReLateBound(debruijn, br) if *debruijn == self.target_index => {
-                bound_region_scope.map.entry(*br).or_insert_with(|| next_region(*br));
+        match *r {
+            ty::ReLateBound(debruijn, br) if debruijn == self.target_index => {
+                bound_region_scope.map.entry(br).or_insert_with(|| next_region(br));
             }
 
             _ => {}
@@ -963,8 +963,8 @@ fn regions(
     ) -> RelateResult<'tcx, ty::Region<'tcx>> {
         debug!("TypeGeneralizer::regions(a={:?})", a);
 
-        if let ty::ReLateBound(debruijn, _) = a {
-            if *debruijn < self.first_free_index {
+        if let ty::ReLateBound(debruijn, _) = *a {
+            if debruijn < self.first_free_index {
                 return Ok(a);
             }
         }
@@ -992,10 +992,10 @@ fn regions(
 
     fn consts(
         &mut self,
-        a: &'tcx ty::Const<'tcx>,
-        _: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
-        match a.val {
+        a: ty::Const<'tcx>,
+        _: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+        match a.val() {
             ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
                 bug!("unexpected inference variable encountered in NLL generalization: {:?}", a);
             }
@@ -1010,7 +1010,7 @@ fn consts(
                             origin: var_value.origin,
                             val: ConstVariableValue::Unknown { universe: self.universe },
                         });
-                        Ok(self.tcx().mk_const_var(new_var_id, a.ty))
+                        Ok(self.tcx().mk_const_var(new_var_id, a.ty()))
                     }
                 }
             }
index 3947282aa6217f4dba820c79d75c6596e4294262..bd8bb9e1fa9ea2b2eb7420ca1b75afd659028484 100644 (file)
@@ -2,8 +2,9 @@
 use crate::infer::{GenericKind, InferCtxt};
 use crate::traits::query::OutlivesBound;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::intern::Interned;
 use rustc_hir as hir;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, ReEarlyBound, ReFree, ReVar, Region};
 
 use super::explicit_outlives_bounds;
 
@@ -66,7 +67,7 @@ pub struct OutlivesEnvironment<'tcx> {
 /// "Region-bound pairs" tracks outlives relations that are known to
 /// be true, either because of explicit where-clauses like `T: 'a` or
 /// because of implied bounds.
-pub type RegionBoundPairs<'tcx> = Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>;
+pub type RegionBoundPairs<'tcx> = Vec<(Region<'tcx>, GenericKind<'tcx>)>;
 
 impl<'a, 'tcx> OutlivesEnvironment<'tcx> {
     pub fn new(param_env: ty::ParamEnv<'tcx>) -> Self {
@@ -164,10 +165,10 @@ pub fn add_outlives_bounds<I>(
             debug!("add_outlives_bounds: outlives_bound={:?}", outlives_bound);
             match outlives_bound {
                 OutlivesBound::RegionSubRegion(
-                    r_a @ (&ty::ReEarlyBound(_) | &ty::ReFree(_)),
-                    &ty::ReVar(vid_b),
+                    r_a @ (Region(Interned(ReEarlyBound(_), _)) | Region(Interned(ReFree(_), _))),
+                    Region(Interned(ReVar(vid_b), _)),
                 ) => {
-                    infcx.expect("no infcx provided but region vars found").add_given(r_a, vid_b);
+                    infcx.expect("no infcx provided but region vars found").add_given(r_a, *vid_b);
                 }
                 OutlivesBound::RegionSubParam(r_a, param_b) => {
                     self.region_bound_pairs_accum.push((r_a, GenericKind::Param(param_b)));
index a5276afc5bfa7ed03b59fd2cc5ccecaa4378a70c..0224aba01ef2884dc22c39c3628e660d56c82ae6 100644 (file)
@@ -285,7 +285,7 @@ fn components_must_outlive(
             let origin = origin.clone();
             match component {
                 Component::Region(region1) => {
-                    self.delegate.push_sub_region_constraint(origin, region, region1);
+                    self.delegate.push_sub_region_constraint(origin, region, *region1);
                 }
                 Component::Param(param_ty) => {
                     self.param_ty_must_outlive(origin, region, *param_ty);
index 2d4c1e5d050baa160271b2c135b243289b3c1912..36d18aebfe2a06630dcb0920770af3e913409460 100644 (file)
@@ -154,17 +154,17 @@ fn assign_placeholder_values(&mut self) -> RelateResult<'tcx, ()> {
             let scc = self.mini_graph.sccs.scc(*leak_check_node);
 
             // Set the universe of each SCC to be the minimum of its constituent universes
-            let universe = self.rcc.universe(region);
+            let universe = self.rcc.universe(*region);
             debug!(
                 "assign_placeholder_values: scc={:?} universe={:?} region={:?}",
                 scc, universe, region
             );
-            self.scc_universes[scc].take_min(universe, region);
+            self.scc_universes[scc].take_min(universe, *region);
 
             // Detect those SCCs that directly contain a placeholder
-            if let ty::RePlaceholder(placeholder) = region {
+            if let ty::RePlaceholder(placeholder) = **region {
                 if self.universe_at_start_of_snapshot.cannot_name(placeholder.universe) {
-                    self.assign_scc_value(scc, *placeholder)?;
+                    self.assign_scc_value(scc, placeholder)?;
                 }
             }
         }
index 29775a96685311bf6cb091fb79ac63d522cc5c3d..a5bd3b15c8d8f2d890c1f55b04255d384a2d2e57 100644 (file)
@@ -8,6 +8,7 @@
 };
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_data_structures::unify as ut;
@@ -28,7 +29,7 @@
 
 pub use rustc_middle::infer::MemberConstraint;
 
-#[derive(Default)]
+#[derive(Clone, Default)]
 pub struct RegionConstraintStorage<'tcx> {
     /// For each `RegionVid`, the corresponding `RegionVariableOrigin`.
     var_infos: IndexVec<RegionVid, RegionVariableInfo>,
@@ -502,14 +503,15 @@ pub fn make_eqregion(
             self.make_subregion(origin, sup, sub);
 
             match (sub, sup) {
-                (&ty::ReVar(sub), &ty::ReVar(sup)) => {
+                (Region(Interned(ReVar(sub), _)), Region(Interned(ReVar(sup), _))) => {
                     debug!("make_eqregion: unifying {:?} with {:?}", sub, sup);
-                    self.unification_table().union(sub, sup);
+                    self.unification_table().union(*sub, *sup);
                     self.any_unifications = true;
                 }
-                (&ty::ReVar(vid), value) | (value, &ty::ReVar(vid)) => {
+                (Region(Interned(ReVar(vid), _)), value)
+                | (value, Region(Interned(ReVar(vid), _))) => {
                     debug!("make_eqregion: unifying {:?} with {:?}", vid, value);
-                    self.unification_table().union_value(vid, UnifiedRegion(Some(value)));
+                    self.unification_table().union_value(*vid, UnifiedRegion(Some(value)));
                     self.any_unifications = true;
                 }
                 (_, _) => {}
@@ -550,20 +552,20 @@ pub fn make_subregion(
         // cannot add constraints once regions are resolved
         debug!("origin = {:#?}", origin);
 
-        match (sub, sup) {
-            (&ReLateBound(..), _) | (_, &ReLateBound(..)) => {
+        match (*sub, *sup) {
+            (ReLateBound(..), _) | (_, ReLateBound(..)) => {
                 span_bug!(origin.span(), "cannot relate bound region: {:?} <= {:?}", sub, sup);
             }
-            (_, &ReStatic) => {
+            (_, ReStatic) => {
                 // all regions are subregions of static, so we can ignore this
             }
-            (&ReVar(sub_id), &ReVar(sup_id)) => {
+            (ReVar(sub_id), ReVar(sup_id)) => {
                 self.add_constraint(Constraint::VarSubVar(sub_id, sup_id), origin);
             }
-            (_, &ReVar(sup_id)) => {
+            (_, ReVar(sup_id)) => {
                 self.add_constraint(Constraint::RegSubVar(sub, sup_id), origin);
             }
-            (&ReVar(sub_id), _) => {
+            (ReVar(sub_id), _) => {
                 self.add_constraint(Constraint::VarSubReg(sub_id, sup), origin);
             }
             _ => {
@@ -591,16 +593,12 @@ pub fn lub_regions(
     ) -> Region<'tcx> {
         // cannot add constraints once regions are resolved
         debug!("RegionConstraintCollector: lub_regions({:?}, {:?})", a, b);
-        match (a, b) {
-            (r @ &ReStatic, _) | (_, r @ &ReStatic) => {
-                r // nothing lives longer than static
-            }
-
-            _ if a == b => {
-                a // LUB(a,a) = a
-            }
-
-            _ => self.combine_vars(tcx, Lub, a, b, origin),
+        if a.is_static() || b.is_static() {
+            a // nothing lives longer than static
+        } else if a == b {
+            a // LUB(a,a) = a
+        } else {
+            self.combine_vars(tcx, Lub, a, b, origin)
         }
     }
 
@@ -613,16 +611,14 @@ pub fn glb_regions(
     ) -> Region<'tcx> {
         // cannot add constraints once regions are resolved
         debug!("RegionConstraintCollector: glb_regions({:?}, {:?})", a, b);
-        match (a, b) {
-            (&ReStatic, r) | (r, &ReStatic) => {
-                r // static lives longer than everything else
-            }
-
-            _ if a == b => {
-                a // GLB(a,a) = a
-            }
-
-            _ => self.combine_vars(tcx, Glb, a, b, origin),
+        if a.is_static() {
+            b // static lives longer than everything else
+        } else if b.is_static() {
+            a // static lives longer than everything else
+        } else if a == b {
+            a // GLB(a,a) = a
+        } else {
+            self.combine_vars(tcx, Glb, a, b, origin)
         }
     }
 
@@ -639,11 +635,11 @@ pub fn opportunistic_resolve_region(
         tcx: TyCtxt<'tcx>,
         region: ty::Region<'tcx>,
     ) -> ty::Region<'tcx> {
-        match region {
+        match *region {
             ty::ReVar(rid) => {
-                let unified_region = self.unification_table().probe_value(*rid);
+                let unified_region = self.unification_table().probe_value(rid);
                 unified_region.0.unwrap_or_else(|| {
-                    let root = self.unification_table().find(*rid).vid;
+                    let root = self.unification_table().find(rid).vid;
                     tcx.reuse_or_mk_region(region, ty::ReVar(root))
                 })
             }
@@ -767,8 +763,7 @@ impl<'tcx> VerifyBound<'tcx> {
     pub fn must_hold(&self) -> bool {
         match self {
             VerifyBound::IfEq(..) => false,
-            VerifyBound::OutlivedBy(ty::ReStatic) => true,
-            VerifyBound::OutlivedBy(_) => false,
+            VerifyBound::OutlivedBy(re) => re.is_static(),
             VerifyBound::IsEmpty => false,
             VerifyBound::AnyBound(bs) => bs.iter().any(|b| b.must_hold()),
             VerifyBound::AllBounds(bs) => bs.iter().all(|b| b.must_hold()),
index 744599113849b2282cc6df446f889bd85093d19d..08358bf506778b85af4c4a1ad8d92ca0d6b970ba 100644 (file)
@@ -39,7 +39,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx Const<'tcx>) -> &'tcx Const<'tcx> {
+    fn fold_const(&mut self, ct: Const<'tcx>) -> Const<'tcx> {
         if !ct.has_infer_types_or_consts() {
             ct // micro-optimize -- if there is nothing in this const that this fold affects...
         } else {
@@ -98,7 +98,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         if !ct.has_infer_regions() {
             ct // micro-optimize -- if there is nothing in this const that this fold affects...
         } else {
@@ -218,15 +218,12 @@ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, S
         }
     }
 
-    fn try_fold_const(
-        &mut self,
-        c: &'tcx ty::Const<'tcx>,
-    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
         if !c.needs_infer() {
             Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
         } else {
             let c = self.infcx.shallow_resolve(c);
-            match c.val {
+            match c.val() {
                 ty::ConstKind::Infer(InferConst::Var(vid)) => {
                     return Err(FixupError::UnresolvedConst(vid));
                 }
index ccac0efd6c9eec22084e869b9073afeb97aae04a..9ec1b3390d0ad3cf8aea208d765d6759ae19c4d0 100644 (file)
@@ -151,9 +151,9 @@ fn regions(
 
     fn consts(
         &mut self,
-        a: &'tcx ty::Const<'tcx>,
-        b: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         self.fields.infcx.super_combine_consts(self, a, b)
     }
 
@@ -170,7 +170,7 @@ fn binders<T>(
 }
 
 impl<'tcx> ConstEquateRelation<'tcx> for Sub<'_, '_, 'tcx> {
-    fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Const<'tcx>) {
+    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
         self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
     }
 }
index 82970f214fa66f9b67fdadf09070cf5ca84e55e1..0864edf44510ad5c227155bb8029d797a4e19eb5 100644 (file)
@@ -14,6 +14,7 @@
 use rustc_data_structures::undo_log::{Rollback, UndoLogs};
 
 /// Represents a single undo-able action that affects a type inference variable.
+#[derive(Clone)]
 pub(crate) enum UndoLog<'tcx> {
     EqRelation(sv::UndoLog<ut::Delegate<TyVidEqKey<'tcx>>>),
     SubRelation(sv::UndoLog<ut::Delegate<ty::TyVid>>),
@@ -58,6 +59,7 @@ fn reverse(&mut self, undo: UndoLog<'tcx>) {
     }
 }
 
+#[derive(Clone)]
 pub struct TypeVariableStorage<'tcx> {
     values: sv::SnapshotVecStorage<Delegate>,
 
@@ -137,6 +139,7 @@ pub enum TypeVariableOriginKind {
     LatticeVariable,
 }
 
+#[derive(Clone)]
 pub(crate) struct TypeVariableData {
     origin: TypeVariableOrigin,
 }
@@ -165,6 +168,7 @@ pub fn is_unknown(&self) -> bool {
     }
 }
 
+#[derive(Clone)]
 pub(crate) struct Instantiate;
 
 pub(crate) struct Delegate;
@@ -412,6 +416,7 @@ impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> {
     fn index(&self) -> u32 {
         self.vid.as_u32()
     }
+    #[inline]
     fn from_index(i: u32) -> Self {
         TyVidEqKey::from(ty::TyVid::from_u32(i))
     }
index 89db8f464b4e7c7e41c2c003a4ab7def776c3341..ecd886b547834f3b86a7966c63fb8772f56fd2d4 100644 (file)
@@ -17,6 +17,7 @@ pub struct Snapshot<'tcx> {
 }
 
 /// Records the "undo" data for a single operation that affects some form of inference variable.
+#[derive(Clone)]
 pub(crate) enum UndoLog<'tcx> {
     TypeVariables(type_variable::UndoLog<'tcx>),
     ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>),
@@ -84,6 +85,7 @@ fn reverse(&mut self, undo: UndoLog<'tcx>) {
 
 /// The combined undo log for all the various unification tables. For each change to the storage
 /// for any kind of inference variable, we record an UndoLog entry in the vector here.
+#[derive(Clone)]
 pub(crate) struct InferCtxtUndoLogs<'tcx> {
     logs: Vec<UndoLog<'tcx>>,
     num_open_snapshots: usize,
index e1f3b548e97fe7c8ffcbdda70345e5a53827574b..85bb727a6c8048dac439d5ff02d65dbec78f089e 100644 (file)
@@ -101,7 +101,7 @@ pub enum FulfillmentErrorCode<'tcx> {
     CodeSelectionError(SelectionError<'tcx>),
     CodeProjectionError(MismatchedProjectionTypes<'tcx>),
     CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
-    CodeConstEquateError(ExpectedFound<&'tcx Const<'tcx>>, TypeError<'tcx>),
+    CodeConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
     CodeAmbiguity,
 }
 
index a1a1168a21d2e8fa216670c452d8d0a7a8407685..b84ed3dc689376c830a32a9e4064ab153a8d16e9 100644 (file)
@@ -70,7 +70,7 @@ pub struct ProjectionCache<'a, 'tcx> {
     undo_log: &'a mut InferCtxtUndoLogs<'tcx>,
 }
 
-#[derive(Default)]
+#[derive(Clone, Default)]
 pub struct ProjectionCacheStorage<'tcx> {
     map: SnapshotMapStorage<ProjectionCacheKey<'tcx>, ProjectionCacheEntry<'tcx>>,
 }
index 3c7908fae79beb45ff2e576ac433509a52cb6498..a18e2d1d638879fd264bb87775703e8d390546e7 100644 (file)
@@ -4,7 +4,7 @@
 //! `rustc_data_structures::AtomicRef` type, which allows us to setup a global
 //! static which can then be set in this file at program startup.
 //!
-//! See `SPAN_DEBUG` for an example of how to set things up.
+//! See `SPAN_TRACK` for an example of how to set things up.
 //!
 //! The functions in this file should fall back to the default set in their
 //! origin crate when the `TyCtxt` is not present in TLS.
 use rustc_middle::ty::tls;
 use std::fmt;
 
-/// This is a callback from `rustc_ast` as it cannot access the implicit state
-/// in `rustc_middle` otherwise.
-fn span_debug(span: rustc_span::Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    tls::with_opt(|tcx| {
-        if let Some(tcx) = tcx {
-            rustc_span::debug_with_source_map(span, f, tcx.sess.source_map())
-        } else {
-            rustc_span::default_span_debug(span, f)
-        }
-    })
-}
-
 fn track_span_parent(def_id: rustc_span::def_id::LocalDefId) {
     tls::with_opt(|tcx| {
         if let Some(tcx) = tcx {
@@ -65,7 +53,6 @@ fn def_id_debug(def_id: rustc_hir::def_id::DefId, f: &mut fmt::Formatter<'_>) ->
 /// Sets up the callbacks in prior crates which we want to refer to the
 /// TyCtxt in.
 pub fn setup_callbacks() {
-    rustc_span::SPAN_DEBUG.swap(&(span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
     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(&_)));
index 263435619590e1ba78a938f701318bd2f3d1b74d..9a588b55393e5d0e6db9d6bcdcf5bad45e26f0af 100644 (file)
@@ -21,7 +21,6 @@
 use rustc_span::source_map::{FileLoader, FileName};
 use std::path::PathBuf;
 use std::result;
-use std::sync::{Arc, Mutex};
 
 pub type Result<T> = result::Result<T, ErrorReported>;
 
@@ -126,7 +125,7 @@ macro_rules! error {
 
                 // If the user tried to use a key="value" flag, but is missing the quotes, provide
                 // a hint about how to resolve this.
-                if s.contains("=") && !s.contains("=\"") && !s.ends_with("\"") {
+                if s.contains('=') && !s.contains("=\"") && !s.ends_with('"') {
                     error!(concat!(
                         r#"expected `key` or `key="value"`, ensure escaping is appropriate"#,
                         r#" for your shell, try 'key="value"' or key=\"value\""#
@@ -155,9 +154,6 @@ pub struct Config {
     pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
     pub diagnostic_output: DiagnosticOutput,
 
-    /// Set to capture stderr output during compiler execution
-    pub stderr: Option<Arc<Mutex<Vec<u8>>>>,
-
     pub lint_caps: FxHashMap<lint::LintId, lint::Level>,
 
     /// This is a callback from the driver that is called when [`ParseSess`] is created.
@@ -186,6 +182,8 @@ pub struct Config {
 }
 
 pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R) -> R {
+    crate::callbacks::setup_callbacks();
+
     let registry = &config.registry;
     let (mut sess, codegen_backend) = util::create_session(
         config.opts,
@@ -235,13 +233,11 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
     })
 }
 
-pub fn run_compiler<R: Send>(mut config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
+pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Send) -> R {
     tracing::trace!("run_compiler");
-    let stderr = config.stderr.take();
-    util::setup_callbacks_and_run_in_thread_pool_with_globals(
+    util::run_in_thread_pool_with_globals(
         config.opts.edition,
         config.opts.debugging_opts.threads,
-        &stderr,
         || create_compiler_and_run(config, f),
     )
 }
index eebeabbd45272fece4faa37a91c5b6e865a769eb..dcad3036cc24d3af834d54eb4d927a89a63b0aa8 100644 (file)
@@ -15,6 +15,7 @@
 mod queries;
 pub mod util;
 
+pub use callbacks::setup_callbacks;
 pub use interface::{run_compiler, Config};
 pub use passes::{DEFAULT_EXTERN_QUERY_PROVIDERS, DEFAULT_QUERY_PROVIDERS};
 pub use queries::Queries;
index 7a3d77466c55f4a8636628d55e1fb84366a3ec6c..c0552fd200be8d83680401202cc82d9cf3a318a7 100644 (file)
@@ -286,8 +286,7 @@ pub fn configure_and_expand(
     rustc_builtin_macros::register_builtin_macros(resolver);
 
     krate = sess.time("crate_injection", || {
-        let alt_std_name = sess.opts.alt_std_name.as_ref().map(|s| Symbol::intern(s));
-        rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess, alt_std_name)
+        rustc_builtin_macros::standard_library_imports::inject(krate, resolver, sess)
     });
 
     util::check_attr_crate_type(sess, &krate.attrs, &mut resolver.lint_buffer());
@@ -394,8 +393,18 @@ pub fn configure_and_expand(
     });
 
     let crate_types = sess.crate_types();
+    let is_executable_crate = crate_types.contains(&CrateType::Executable);
     let is_proc_macro_crate = crate_types.contains(&CrateType::ProcMacro);
 
+    if crate_types.len() > 1 {
+        if is_executable_crate {
+            sess.err("cannot mix `bin` crate type with others");
+        }
+        if is_proc_macro_crate {
+            sess.err("cannot mix `proc-macro` crate type with others");
+        }
+    }
+
     // For backwards compatibility, we don't try to run proc macro injection
     // if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being
     // specified. This should only affect users who manually invoke 'rustdoc', as
@@ -412,7 +421,6 @@ pub fn configure_and_expand(
         msg.emit()
     } else {
         krate = sess.time("maybe_create_a_macro_crate", || {
-            let num_crate_types = crate_types.len();
             let is_test_crate = sess.opts.test;
             rustc_builtin_macros::proc_macro_harness::inject(
                 sess,
@@ -421,7 +429,6 @@ pub fn configure_and_expand(
                 is_proc_macro_crate,
                 has_proc_macro_decls,
                 is_test_crate,
-                num_crate_types,
                 sess.diagnostic(),
             )
         });
@@ -658,13 +665,13 @@ fn write_out_deps(
             boxed_resolver.borrow_mut().access(|resolver| {
                 for cnum in resolver.cstore().crates_untracked() {
                     let source = resolver.cstore().crate_source_untracked(cnum);
-                    if let Some((path, _)) = source.dylib {
+                    if let Some((path, _)) = &source.dylib {
                         files.push(escape_dep_filename(&path.display().to_string()));
                     }
-                    if let Some((path, _)) = source.rlib {
+                    if let Some((path, _)) = &source.rlib {
                         files.push(escape_dep_filename(&path.display().to_string()));
                     }
-                    if let Some((path, _)) = source.rmeta {
+                    if let Some((path, _)) = &source.rmeta {
                         files.push(escape_dep_filename(&path.display().to_string()));
                     }
                 }
index e635ee1e0ec8a44394df59e7a2b2069e3ae7e537..89390ee1d6ccdcb30edfe75da2d307556b2a24c5 100644 (file)
@@ -13,7 +13,6 @@
 use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::ty::{GlobalCtxt, TyCtxt};
 use rustc_query_impl::Queries as TcxQueries;
-use rustc_serialize::json;
 use rustc_session::config::{self, OutputFilenames, OutputType};
 use rustc_session::{output::find_crate_name, Session};
 use rustc_span::symbol::sym;
@@ -367,12 +366,10 @@ pub fn link(self) -> Result<()> {
         }
 
         if sess.opts.debugging_opts.no_link {
-            // FIXME: use a binary format to encode the `.rlink` file
-            let rlink_data = json::encode(&codegen_results).map_err(|err| {
-                sess.fatal(&format!("failed to encode rlink: {}", err));
-            })?;
+            let mut encoder = rustc_serialize::opaque::Encoder::new(Vec::new());
+            rustc_serialize::Encodable::encode(&codegen_results, &mut encoder).unwrap();
             let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT);
-            std::fs::write(&rlink_file, rlink_data).map_err(|err| {
+            std::fs::write(&rlink_file, encoder.into_inner()).map_err(|err| {
                 sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err));
             })?;
             return Ok(());
@@ -403,10 +400,6 @@ pub fn enter<F, T>(&self, f: F) -> T
                 gcx.enter(rustc_query_impl::alloc_self_profile_query_strings);
             }
 
-            if self.session().opts.debugging_opts.query_stats {
-                gcx.enter(rustc_query_impl::print_stats);
-            }
-
             self.session()
                 .time("serialize_dep_graph", || gcx.enter(rustc_incremental::save_dep_graph));
         }
index 44acbd3cf2159d592a0523de7ed609883e5ed6e8..9ab138c1b12a51f54e900efd0989ef8bf2329739 100644 (file)
@@ -575,6 +575,7 @@ macro_rules! tracked {
     tracked!(force_frame_pointers, Some(false));
     tracked!(force_unwind_tables, Some(true));
     tracked!(inline_threshold, Some(0xf007ba11));
+    tracked!(instrument_coverage, Some(InstrumentCoverage::All));
     tracked!(linker_plugin_lto, LinkerPluginLto::LinkerPluginAuto);
     tracked!(link_dead_code, Some(true));
     tracked!(llvm_args, vec![String::from("1"), String::from("2")]);
@@ -683,7 +684,6 @@ macro_rules! untracked {
     untracked!(print_type_sizes, true);
     untracked!(proc_macro_backtrace, true);
     untracked!(query_dep_graph, true);
-    untracked!(query_stats, true);
     untracked!(save_analysis, true);
     untracked!(self_profile, SwitchWithOptPath::Enabled(None));
     untracked!(self_profile_events, Some(vec![String::new()]));
@@ -729,6 +729,7 @@ macro_rules! tracked {
     tracked!(debug_info_for_profiling, true);
     tracked!(debug_macros, true);
     tracked!(dep_info_omit_d_target, true);
+    tracked!(drop_tracking, true);
     tracked!(dual_proc_macros, true);
     tracked!(fewer_names, Some(true));
     tracked!(force_unstable_if_unmarked, true);
index 6d9183eda9d32e9a00c6fa0fbc6773b96640a7c0..700710c82c9e08d48ff4a86fe2f3f19e4b17e291 100644 (file)
@@ -27,7 +27,6 @@
 use smallvec::SmallVec;
 use std::env;
 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
-use std::io;
 use std::lazy::SyncOnceCell;
 use std::mem;
 use std::ops::DerefMut;
@@ -35,7 +34,6 @@
 use std::panic;
 use std::path::{Path, PathBuf};
 use std::sync::atomic::{AtomicBool, Ordering};
-use std::sync::{Arc, Mutex};
 use std::thread;
 use tracing::info;
 
@@ -118,7 +116,7 @@ fn get_stack_size() -> Option<usize> {
 /// Like a `thread::Builder::spawn` followed by a `join()`, but avoids the need
 /// for `'static` bounds.
 #[cfg(not(parallel_compiler))]
-pub fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
+fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
     // SAFETY: join() is called immediately, so any closure captures are still
     // alive.
     match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() {
@@ -128,10 +126,9 @@ pub fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f:
 }
 
 #[cfg(not(parallel_compiler))]
-pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     edition: Edition,
     _threads: usize,
-    stderr: &Option<Arc<Mutex<Vec<u8>>>>,
     f: F,
 ) -> R {
     let mut cfg = thread::Builder::new().name("rustc".to_string());
@@ -140,14 +137,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
         cfg = cfg.stack_size(size);
     }
 
-    crate::callbacks::setup_callbacks();
-
-    let main_handler = move || {
-        rustc_span::create_session_globals_then(edition, || {
-            io::set_output_capture(stderr.clone());
-            f()
-        })
-    };
+    let main_handler = move || rustc_span::create_session_globals_then(edition, f);
 
     scoped_thread(cfg, main_handler)
 }
@@ -176,14 +166,11 @@ unsafe fn handle_deadlock() {
 }
 
 #[cfg(parallel_compiler)]
-pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
+pub fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     edition: Edition,
     threads: usize,
-    stderr: &Option<Arc<Mutex<Vec<u8>>>>,
     f: F,
 ) -> R {
-    crate::callbacks::setup_callbacks();
-
     let mut config = rayon::ThreadPoolBuilder::new()
         .thread_name(|_| "rustc".to_string())
         .acquire_thread_handler(jobserver::acquire_thread)
@@ -203,10 +190,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals<F: FnOnce() -> R + Se
             // the thread local rustc uses. `session_globals` is captured and set
             // on the new threads.
             let main_handler = move |thread: rayon::ThreadBuilder| {
-                rustc_span::set_session_globals_then(session_globals, || {
-                    io::set_output_capture(stderr.clone());
-                    thread.run()
-                })
+                rustc_span::set_session_globals_then(session_globals, || thread.run())
             };
 
             config.build_scoped(main_handler, with_pool).unwrap()
@@ -343,6 +327,7 @@ fn current_dll_path() -> Option<PathBuf> {
     #[cfg(windows)]
     fn current_dll_path() -> Option<PathBuf> {
         use std::ffi::OsString;
+        use std::io;
         use std::os::windows::prelude::*;
         use std::ptr;
 
@@ -379,7 +364,7 @@ fn current_dll_path() -> Option<PathBuf> {
     }
 }
 
-pub fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
+fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
     // For now we only allow this function to be called once as it'll dlopen a
     // few things, which seems to work best if we only do that once. In
     // general this assertion never trips due to the once guard in `get_codegen_backend`,
index 734b32bb92f1e88d4233b44de19690cc1769bbc1..a397db7f32921d733a573af5d95d0ab2f85f9982 100644 (file)
@@ -2050,7 +2050,7 @@ fn lifetimes_outliving_lifetime<'tcx>(
         inferred_outlives
             .iter()
             .filter_map(|(pred, _)| match pred.kind().skip_binder() {
-                ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match a {
+                ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a {
                     ty::ReEarlyBound(ebr) if ebr.index == index => Some(b),
                     _ => None,
                 },
@@ -2111,10 +2111,10 @@ fn collect_outlives_bound_spans<'tcx>(
                 if let hir::GenericBound::Outlives(lifetime) = bound {
                     let is_inferred = match tcx.named_region(lifetime.hir_id) {
                         Some(Region::Static) if infer_static => {
-                            inferred_outlives.iter().any(|r| matches!(r, ty::ReStatic))
+                            inferred_outlives.iter().any(|r| matches!(**r, ty::ReStatic))
                         }
                         Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| {
-                            if let ty::ReEarlyBound(ebr) = r { ebr.index == index } else { false }
+                            if let ty::ReEarlyBound(ebr) = **r { ebr.index == index } else { false }
                         }),
                         _ => false,
                     };
@@ -2895,26 +2895,22 @@ fn structurally_same_type_impl<'tcx>(
                         }
                         (Array(a_ty, a_const), Array(b_ty, b_const)) => {
                             // For arrays, we also check the constness of the type.
-                            a_const.val == b_const.val
-                                && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+                            a_const.val() == b_const.val()
+                                && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
                         }
                         (Slice(a_ty), Slice(b_ty)) => {
-                            structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+                            structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
                         }
                         (RawPtr(a_tymut), RawPtr(b_tymut)) => {
                             a_tymut.mutbl == b_tymut.mutbl
                                 && structurally_same_type_impl(
-                                    seen_types,
-                                    cx,
-                                    &a_tymut.ty,
-                                    &b_tymut.ty,
-                                    ckind,
+                                    seen_types, cx, a_tymut.ty, b_tymut.ty, ckind,
                                 )
                         }
                         (Ref(_a_region, a_ty, a_mut), Ref(_b_region, b_ty, b_mut)) => {
                             // For structural sameness, we don't need the region to be same.
                             a_mut == b_mut
-                                && structurally_same_type_impl(seen_types, cx, a_ty, b_ty, ckind)
+                                && structurally_same_type_impl(seen_types, cx, *a_ty, *b_ty, ckind)
                         }
                         (FnDef(..), FnDef(..)) => {
                             let a_poly_sig = a.fn_sig(tcx);
@@ -2927,7 +2923,7 @@ fn structurally_same_type_impl<'tcx>(
                             (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
                                 == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
                                 && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
-                                    structurally_same_type_impl(seen_types, cx, a, b, ckind)
+                                    structurally_same_type_impl(seen_types, cx, *a, *b, ckind)
                                 })
                                 && structurally_same_type_impl(
                                     seen_types,
index 5da77b9f9466fcd24814acbebd80bb4cdc12c0a2..d2d853efda2d25db2c69b2d029118b65939c5c76 100644 (file)
@@ -974,7 +974,7 @@ fn print_dyn_existential(
                 Ok(())
             }
 
-            fn print_const(self, _ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+            fn print_const(self, _ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
                 Ok(())
             }
 
index fa8cbeaaf51e2b90d374a0adfcfbb8f96bac39db..944a0996427557a7fdef625e8836d08ca4c8b019 100644 (file)
@@ -202,7 +202,7 @@ fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
                 }
             }
             // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
-            Res::SelfTy(None, Some((did, _))) => {
+            Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
                 if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
                     if let Some(name @ (sym::Ty | sym::TyCtxt)) =
                         cx.tcx.get_diagnostic_name(adt.did)
index 6bf25732f6035fc485044dfb840fd339accfbe8a..3130d57c2a9716233247f52df79fbd07dab29961 100644 (file)
@@ -49,9 +49,11 @@ impl<'tcx> LateLintPass<'tcx> for NonPanicFmt {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
         if let hir::ExprKind::Call(f, [arg]) = &expr.kind {
             if let &ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(f).kind() {
+                let f_diagnostic_name = cx.tcx.get_diagnostic_name(def_id);
+
                 if Some(def_id) == cx.tcx.lang_items().begin_panic_fn()
                     || Some(def_id) == cx.tcx.lang_items().panic_fn()
-                    || Some(def_id) == cx.tcx.lang_items().panic_str()
+                    || f_diagnostic_name == Some(sym::panic_str)
                 {
                     if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
                         if matches!(
@@ -61,6 +63,22 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
                             check_panic(cx, f, arg);
                         }
                     }
+                } else if f_diagnostic_name == Some(sym::unreachable_display) {
+                    if let Some(id) = f.span.ctxt().outer_expn_data().macro_def_id {
+                        if cx.tcx.is_diagnostic_item(sym::unreachable_2015_macro, id) {
+                            check_panic(
+                                cx,
+                                f,
+                                // This is safe because we checked above that the callee is indeed
+                                // unreachable_display
+                                match &arg.kind {
+                                    // Get the borrowed arg not the borrow
+                                    hir::ExprKind::AddrOf(ast::BorrowKind::Ref, _, arg) => arg,
+                                    _ => bug!("call to unreachable_display without borrow"),
+                                },
+                            );
+                        }
+                    }
                 }
             }
         }
@@ -85,8 +103,8 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
         return;
     }
 
-    // Find the span of the argument to `panic!()`, before expansion in the
-    // case of `panic!(some_macro!())`.
+    // Find the span of the argument to `panic!()` or `unreachable!`, before expansion in the
+    // case of `panic!(some_macro!())` or `unreachable!(some_macro!())`.
     // We don't use source_callsite(), because this `panic!(..)` might itself
     // be expanded from another macro, in which case we want to stop at that
     // expansion.
@@ -319,6 +337,7 @@ fn panic_call<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>) -> (Span,
                 | sym::std_panic_macro
                 | sym::assert_macro
                 | sym::debug_assert_macro
+                | sym::unreachable_macro
         ) {
             break;
         }
index 2caf929788f182f6efbc873525aa92a7824633fc..c47fdc063a96544d22a4f2dbac7f0dcc1d4ab517 100644 (file)
@@ -7,9 +7,10 @@
 use rustc_span::symbol::sym;
 
 declare_tool_lint! {
-    /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to always be passed by value.
-    /// This is usually used for types that are thin wrappers around references, so there is no benefit to an extra
-    /// layer of indirection. (Example: `Ty` which is a reference to a `TyS`)
+    /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to
+    /// always be passed by value. This is usually used for types that are thin wrappers around
+    /// references, so there is no benefit to an extra layer of indirection. (Example: `Ty` which
+    /// is a reference to an `Interned<TyS>`)
     pub rustc::PASS_BY_VALUE,
     Warn,
     "pass by reference of a type flagged as `#[rustc_pass_by_value]`",
@@ -54,7 +55,7 @@ fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<Stri
                 let path_segment = path.segments.last().unwrap();
                 return Some(format!("{}{}", name, gen_args(cx, path_segment)));
             }
-            Res::SelfTy(None, Some((did, _))) => {
+            Res::SelfTy { trait_: None, alias_to: Some((did, _)) } => {
                 if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
                     if cx.tcx.has_attr(adt.did, sym::rustc_pass_by_value) {
                         return Some(cx.tcx.def_path_str_with_substs(adt.did, substs));
index bceb5e536e7110af987f910c868c2d652a7fa2dc..fc88e8cd912ea92aed4f12f3303582f4e7e06db9 100644 (file)
@@ -249,7 +249,7 @@ fn report_bin_hex_error(
             ));
         }
         if let Some(sugg_ty) =
-            get_type_suggestion(&cx.typeck_results().node_type(expr.hir_id), val, negative)
+            get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
         {
             if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
                 let (sans_suffix, _) = repr_str.split_at(pos);
@@ -367,7 +367,7 @@ fn lint_int_literal<'tcx>(
                 max,
             ));
             if let Some(sugg_ty) =
-                get_type_suggestion(&cx.typeck_results().node_type(e.hir_id), v, negative)
+                get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
             {
                 err.help(&format!("consider using the type `{}` instead", sugg_ty));
             }
@@ -1095,7 +1095,7 @@ fn check_type_for_ffi(&self, cache: &mut FxHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> F
                     }
                 }
                 for arg in sig.inputs() {
-                    let r = self.check_type_for_ffi(cache, arg);
+                    let r = self.check_type_for_ffi(cache, *arg);
                     match r {
                         FfiSafe => {}
                         _ => {
@@ -1257,7 +1257,7 @@ fn check_foreign_fn(&mut self, id: hir::HirId, decl: &hir::FnDecl<'_>) {
         let sig = self.cx.tcx.erase_late_bound_regions(sig);
 
         for (input_ty, input_hir) in iter::zip(sig.inputs(), decl.inputs) {
-            self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty, false, false);
+            self.check_type_for_ffi_and_report_errors(input_hir.span, *input_ty, false, false);
         }
 
         if let hir::FnRetTy::Return(ref ret_hir) = decl.output {
index e2ce7da0e84afc0eca5ad033ef8a7d4e253efaaa..9e0a9b354e19675ee40eef1290144342d31ac0d3 100644 (file)
@@ -82,6 +82,7 @@ enum LLVMRustAttribute {
   StackProtectReq = 30,
   StackProtectStrong = 31,
   StackProtect = 32,
+  NoUndef = 33,
 };
 
 typedef struct OpaqueRustString *RustStringRef;
index dcd6327c92f6a38789a747473ac8ca6d11bc1b55..23333199506515712d5a32e678086e477f87c48b 100644 (file)
@@ -76,6 +76,10 @@ extern "C" void LLVMRustInstallFatalErrorHandler() {
   install_fatal_error_handler(FatalErrorHandler);
 }
 
+extern "C" void LLVMRustDisableSystemDialogsOnCrash() {
+  sys::DisableSystemDialogsOnCrash();
+}
+
 extern "C" char *LLVMRustGetLastError(void) {
   char *Ret = LastError;
   LastError = nullptr;
@@ -220,6 +224,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
     return Attribute::StackProtectStrong;
   case StackProtect:
     return Attribute::StackProtect;
+  case NoUndef:
+    return Attribute::NoUndef;
   }
   report_fatal_error("bad AttributeKind");
 }
@@ -328,6 +334,17 @@ extern "C" void LLVMRustAddStructRetAttr(LLVMValueRef Fn, unsigned Index,
   AddAttribute(F, Index, Attr);
 }
 
+extern "C" void LLVMRustEmitUWTableAttr(LLVMValueRef Fn, bool Async) {
+  Function *F = unwrap<Function>(Fn);
+#if LLVM_VERSION_LT(15, 0)
+  Attribute Attr = Attribute::get(F->getContext(), Attribute::UWTable);
+#else
+  Attribute Attr = Attribute::getWithUWTableKind(
+      F->getContext(), Async ? UWTableKind::Async : UWTableKind::Sync);
+#endif
+  AddAttribute(F, AttributeList::AttrIndex::FunctionIndex, Attr);
+}
+
 extern "C" void LLVMRustAddFunctionAttrStringValue(LLVMValueRef Fn,
                                                    unsigned Index,
                                                    const char *Name,
index 13ea089e245a63048d16668c47627c4a72a9a801..550b22a2a3c657d376cecac2b51f167432388e3b 100644 (file)
 use rustc_errors::{struct_span_err, FatalError};
 use rustc_session::config::{self, CrateType};
 use rustc_session::cstore::{CrateSource, MetadataLoader};
-use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch};
+use rustc_session::filesearch::FileSearch;
 use rustc_session::search_paths::PathKind;
 use rustc_session::utils::CanonicalizedPath;
 use rustc_session::Session;
@@ -371,15 +371,20 @@ fn find_library_crate(
         extra_prefix: &str,
         seen_paths: &mut FxHashSet<PathBuf>,
     ) -> Result<Option<Library>, CrateError> {
-        // want: crate_name.dir_part() + prefix + crate_name.file_part + "-"
-        let dylib_prefix = format!("{}{}{}", self.target.dll_prefix, self.crate_name, extra_prefix);
-        let rlib_prefix = format!("lib{}{}", self.crate_name, extra_prefix);
+        let rmeta_prefix = &format!("lib{}{}", self.crate_name, extra_prefix);
+        let rlib_prefix = rmeta_prefix;
+        let dylib_prefix =
+            &format!("{}{}{}", self.target.dll_prefix, self.crate_name, extra_prefix);
         let staticlib_prefix =
-            format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix);
+            &format!("{}{}{}", self.target.staticlib_prefix, self.crate_name, extra_prefix);
+
+        let rmeta_suffix = ".rmeta";
+        let rlib_suffix = ".rlib";
+        let dylib_suffix = &self.target.dll_suffix;
+        let staticlib_suffix = &self.target.staticlib_suffix;
 
         let mut candidates: FxHashMap<_, (FxHashMap<_, _>, FxHashMap<_, _>, FxHashMap<_, _>)> =
             Default::default();
-        let mut staticlibs = vec![];
 
         // First, find all possible candidate rlibs and dylibs purely based on
         // the name of the files themselves. We're trying to match against an
@@ -394,46 +399,50 @@ fn find_library_crate(
         // of the crate id (path/name/id).
         //
         // The goal of this step is to look at as little metadata as possible.
-        self.filesearch.search(|spf, kind| {
-            let file = match &spf.file_name_str {
-                None => return FileDoesntMatch,
-                Some(file) => file,
-            };
-            let (hash, found_kind) = if file.starts_with(&rlib_prefix) && file.ends_with(".rlib") {
-                (&file[(rlib_prefix.len())..(file.len() - ".rlib".len())], CrateFlavor::Rlib)
-            } else if file.starts_with(&rlib_prefix) && file.ends_with(".rmeta") {
-                (&file[(rlib_prefix.len())..(file.len() - ".rmeta".len())], CrateFlavor::Rmeta)
-            } else if file.starts_with(&dylib_prefix) && file.ends_with(&self.target.dll_suffix) {
-                (
-                    &file[(dylib_prefix.len())..(file.len() - self.target.dll_suffix.len())],
-                    CrateFlavor::Dylib,
-                )
-            } else {
-                if file.starts_with(&staticlib_prefix)
-                    && file.ends_with(&self.target.staticlib_suffix)
-                {
-                    staticlibs
-                        .push(CrateMismatch { path: spf.path.clone(), got: "static".to_string() });
-                }
-                return FileDoesntMatch;
-            };
+        // Unfortunately, the prefix-based matching sometimes is over-eager.
+        // E.g. if `rlib_suffix` is `libstd` it'll match the file
+        // `libstd_detect-8d6701fb958915ad.rlib` (incorrect) as well as
+        // `libstd-f3ab5b1dea981f17.rlib` (correct). But this is hard to avoid
+        // given that `extra_filename` comes from the `-C extra-filename`
+        // option and thus can be anything, and the incorrect match will be
+        // handled safely in `extract_one`.
+        for search_path in self.filesearch.search_paths() {
+            debug!("searching {}", search_path.dir.display());
+            for spf in search_path.files.iter() {
+                debug!("testing {}", spf.path.display());
+
+                let f = &spf.file_name_str;
+                let (hash, kind) = if f.starts_with(rlib_prefix) && f.ends_with(rlib_suffix) {
+                    (&f[rlib_prefix.len()..(f.len() - rlib_suffix.len())], CrateFlavor::Rlib)
+                } else if f.starts_with(rmeta_prefix) && f.ends_with(rmeta_suffix) {
+                    (&f[rmeta_prefix.len()..(f.len() - rmeta_suffix.len())], CrateFlavor::Rmeta)
+                } else if f.starts_with(dylib_prefix) && f.ends_with(dylib_suffix) {
+                    (&f[dylib_prefix.len()..(f.len() - dylib_suffix.len())], CrateFlavor::Dylib)
+                } else {
+                    if f.starts_with(staticlib_prefix) && f.ends_with(staticlib_suffix) {
+                        self.crate_rejections.via_kind.push(CrateMismatch {
+                            path: spf.path.clone(),
+                            got: "static".to_string(),
+                        });
+                    }
+                    continue;
+                };
 
-            info!("lib candidate: {}", spf.path.display());
+                info!("lib candidate: {}", spf.path.display());
 
-            let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
-            let path = fs::canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
-            if seen_paths.contains(&path) {
-                return FileDoesntMatch;
-            };
-            seen_paths.insert(path.clone());
-            match found_kind {
-                CrateFlavor::Rlib => rlibs.insert(path, kind),
-                CrateFlavor::Rmeta => rmetas.insert(path, kind),
-                CrateFlavor::Dylib => dylibs.insert(path, kind),
-            };
-            FileMatches
-        });
-        self.crate_rejections.via_kind.extend(staticlibs);
+                let (rlibs, rmetas, dylibs) = candidates.entry(hash.to_string()).or_default();
+                let path = fs::canonicalize(&spf.path).unwrap_or_else(|_| spf.path.clone());
+                if seen_paths.contains(&path) {
+                    continue;
+                };
+                seen_paths.insert(path.clone());
+                match kind {
+                    CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),
+                    CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
+                    CrateFlavor::Dylib => dylibs.insert(path, search_path.kind),
+                };
+            }
+        }
 
         // We have now collected all known libraries into a set of candidates
         // keyed of the filename hash listed. For each filename, we also have a
index 13cd8e4a046b03ba3d8a84da0ad655868ff83fde..88292a4422419774019d3a1db67a7b384d1ce27a 100644 (file)
@@ -404,11 +404,13 @@ fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize {
     fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport {
         let calling_convention = if self.tcx.sess.target.arch == "x86" {
             match abi {
-                Abi::C { .. } | Abi::Cdecl => DllCallingConvention::C,
+                Abi::C { .. } | Abi::Cdecl { .. } => DllCallingConvention::C,
                 Abi::Stdcall { .. } | Abi::System { .. } => {
                     DllCallingConvention::Stdcall(self.i686_arg_list_size(item))
                 }
-                Abi::Fastcall => DllCallingConvention::Fastcall(self.i686_arg_list_size(item)),
+                Abi::Fastcall { .. } => {
+                    DllCallingConvention::Fastcall(self.i686_arg_list_size(item))
+                }
                 // Vectorcall is intentionally not supported at this time.
                 _ => {
                     self.tcx.sess.span_fatal(
@@ -419,7 +421,7 @@ fn build_dll_import(&self, abi: Abi, item: &hir::ForeignItemRef) -> DllImport {
             }
         } else {
             match abi {
-                Abi::C { .. } | Abi::Win64 | Abi::System { .. } => DllCallingConvention::C,
+                Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C,
                 _ => {
                     self.tcx.sess.span_fatal(
                         item.span,
index fb1c71fb8cdbedfae8aa0ae88c53301f03fed952..66968c9ba54ab77d9036b3efd031fc3cea8ba2db 100644 (file)
@@ -120,7 +120,7 @@ fn deref(&self) -> &[u8] {
     /// How to link (or not link) this crate to the currently compiled crate.
     dep_kind: Lock<CrateDepKind>,
     /// Filesystem location of this crate.
-    source: CrateSource,
+    source: Lrc<CrateSource>,
     /// Whether or not this crate should be consider a private dependency
     /// for purposes of the 'exported_private_dependencies' lint
     private_dep: bool,
@@ -1032,13 +1032,11 @@ fn get_lib_features(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)]
     }
 
     /// Iterates over the language items in the given crate.
-    fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
-        tcx.arena.alloc_from_iter(
-            self.root
-                .lang_items
-                .decode(self)
-                .map(|(def_index, index)| (self.local_def_id(def_index), index)),
-        )
+    fn get_lang_items(self) -> impl Iterator<Item = (DefId, usize)> + 'a {
+        self.root
+            .lang_items
+            .decode(self)
+            .map(move |(def_index, index)| (self.local_def_id(def_index), index))
     }
 
     /// Iterates over the diagnostic items in the given crate.
@@ -1369,10 +1367,27 @@ fn get_inherent_implementations_for_type(
         )
     }
 
+    /// Decodes all inherent impls in the crate (for rustdoc).
+    fn get_inherent_impls(self) -> impl Iterator<Item = (DefId, DefId)> + 'a {
+        (0..self.root.tables.inherent_impls.size()).flat_map(move |i| {
+            let ty_index = DefIndex::from_usize(i);
+            let ty_def_id = self.local_def_id(ty_index);
+            self.root
+                .tables
+                .inherent_impls
+                .get(self, ty_index)
+                .unwrap_or_else(Lazy::empty)
+                .decode(self)
+                .map(move |impl_index| (ty_def_id, self.local_def_id(impl_index)))
+        })
+    }
+
+    /// Decodes all traits in the crate (for rustdoc and rustc diagnostics).
     fn get_traits(self) -> impl Iterator<Item = DefId> + 'a {
         self.root.traits.decode(self).map(move |index| self.local_def_id(index))
     }
 
+    /// Decodes all trait impls in the crate (for rustdoc).
     fn get_trait_impls(self) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + 'a {
         self.cdata.trait_impls.iter().flat_map(move |((trait_cnum_raw, trait_index), impls)| {
             let trait_def_id = DefId {
@@ -1858,7 +1873,7 @@ impl CrateMetadata {
             cnum_map,
             dependencies,
             dep_kind: Lock::new(dep_kind),
-            source,
+            source: Lrc::new(source),
             private_dep,
             host_hash,
             extern_crate: Lock::new(None),
@@ -1886,7 +1901,7 @@ impl CrateMetadata {
     }
 
     crate fn source(&self) -> &CrateSource {
-        &self.source
+        &*self.source
     }
 
     crate fn dep_kind(&self) -> CrateDepKind {
index 2f8e35648ec2d6f8c31e5ddab6a0ba1e2feda36c..7708b5193f4505e9522542715649c4c0b2bac00e 100644 (file)
@@ -3,7 +3,6 @@
 use crate::native_libs;
 
 use rustc_ast as ast;
-use rustc_data_structures::stable_map::FxHashMap;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
@@ -13,7 +12,7 @@
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::{ExternProviders, Providers};
 use rustc_middle::ty::{self, TyCtxt, Visibility};
-use rustc_session::cstore::{CrateSource, CrateStore, ForeignModule};
+use rustc_session::cstore::{CrateSource, CrateStore};
 use rustc_session::utils::NativeLibKind;
 use rustc_session::{Session, StableCrateId};
 use rustc_span::hygiene::{ExpnHash, ExpnId};
@@ -118,7 +117,7 @@ fn into_args(self) -> (DefId, DefId) {
     promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
     thir_abstract_const => { cdata.get_thir_abstract_const(tcx, def_id.index) }
     unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
-    const_param_default => { tcx.mk_const(cdata.get_const_param_default(tcx, def_id.index)) }
+    const_param_default => { cdata.get_const_param_default(tcx, def_id.index) }
     mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
     fn_sig => { cdata.fn_sig(def_id.index, tcx) }
     inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
@@ -179,10 +178,8 @@ fn into_args(self) -> (DefId, DefId) {
 
         reachable_non_generics
     }
-    native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess).collect()) }
-    foreign_modules => {
-        Lrc::new(cdata.get_foreign_modules(tcx.sess).map(|m| (m.def_id, m)).collect())
-    }
+    native_libraries => { cdata.get_native_libraries(tcx.sess).collect() }
+    foreign_modules => { cdata.get_foreign_modules(tcx.sess).map(|m| (m.def_id, m)).collect() }
     crate_hash => { cdata.root.hash }
     crate_host_hash => { cdata.host_hash }
     crate_name => { cdata.root.name }
@@ -203,7 +200,7 @@ fn into_args(self) -> (DefId, DefId) {
         tcx.arena.alloc_slice(&result)
     }
     defined_lib_features => { cdata.get_lib_features(tcx) }
-    defined_lang_items => { cdata.get_lang_items(tcx) }
+    defined_lang_items => { tcx.arena.alloc_from_iter(cdata.get_lang_items()) }
     diagnostic_items => { cdata.get_diagnostic_items() }
     missing_lang_items => { cdata.get_missing_lang_items(tcx) }
 
@@ -212,7 +209,7 @@ fn into_args(self) -> (DefId, DefId) {
         r
     }
 
-    used_crate_source => { Lrc::new(cdata.source.clone()) }
+    used_crate_source => { Lrc::clone(&cdata.source) }
 
     exported_symbols => {
         let syms = cdata.exported_symbols(tcx);
@@ -266,13 +263,11 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
         },
         native_libraries: |tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
-            Lrc::new(native_libs::collect(tcx))
+            native_libs::collect(tcx)
         },
         foreign_modules: |tcx, cnum| {
             assert_eq!(cnum, LOCAL_CRATE);
-            let modules: FxHashMap<DefId, ForeignModule> =
-                foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect();
-            Lrc::new(modules)
+            foreign_modules::collect(tcx).into_iter().map(|m| (m.def_id, m)).collect()
         },
 
         // Returns a map from a sufficiently visible external item (i.e., an
@@ -354,7 +349,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                 visible_parent_map.entry(child).or_insert(parent);
             }
 
-            Lrc::new(visible_parent_map)
+            visible_parent_map
         },
 
         dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)),
@@ -438,7 +433,7 @@ pub fn fn_has_self_parameter_untracked(&self, def: DefId) -> bool {
         self.get_crate_data(def.krate).get_fn_has_self_parameter(def.index)
     }
 
-    pub fn crate_source_untracked(&self, cnum: CrateNum) -> CrateSource {
+    pub fn crate_source_untracked(&self, cnum: CrateNum) -> Lrc<CrateSource> {
         self.get_crate_data(cnum).source.clone()
     }
 
@@ -486,16 +481,31 @@ pub fn get_proc_macro_quoted_span_untracked(
         self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
     }
 
+    /// Decodes all traits in the crate (for rustdoc).
     pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ {
         self.get_crate_data(cnum).get_traits()
     }
 
+    /// Decodes all trait impls in the crate (for rustdoc).
     pub fn trait_impls_in_crate_untracked(
         &self,
         cnum: CrateNum,
     ) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + '_ {
         self.get_crate_data(cnum).get_trait_impls()
     }
+
+    /// Decodes all inherent impls in the crate (for rustdoc).
+    pub fn inherent_impls_in_crate_untracked(
+        &self,
+        cnum: CrateNum,
+    ) -> impl Iterator<Item = (DefId, DefId)> + '_ {
+        self.get_crate_data(cnum).get_inherent_impls()
+    }
+
+    /// Decodes all lang items in the crate (for rustdoc).
+    pub fn lang_items_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ {
+        self.get_crate_data(cnum).get_lang_items().map(|(def_id, _)| def_id)
+    }
 }
 
 impl CrateStore for CStore {
index 3fae652ee2e971b804a4731ed74658d164bb2564..4dea04e62ff07875ff2571439d96feb08cbcbe47 100644 (file)
@@ -26,7 +26,7 @@
 use rustc_middle::thir;
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::codec::TyEncoder;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
 use rustc_serialize::{opaque, Encodable, Encoder};
@@ -982,7 +982,7 @@ fn encode_def_ids(&mut self) {
         for local_id in hir.iter_local_def_id() {
             let def_id = local_id.to_def_id();
             let def_kind = tcx.opt_def_kind(local_id);
-            let def_kind = if let Some(def_kind) = def_kind { def_kind } else { continue };
+            let Some(def_kind) = def_kind else { continue };
             record!(self.tables.def_kind[def_id] <- match def_kind {
                 // Replace Ctor by the enclosing object to avoid leaking details in children crates.
                 DefKind::Ctor(CtorOf::Struct, _) => DefKind::Struct,
@@ -1742,7 +1742,7 @@ fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> {
                     hash: self.tcx.crate_hash(cnum),
                     host_hash: self.tcx.crate_host_hash(cnum),
                     kind: self.tcx.dep_kind(cnum),
-                    extra_filename: self.tcx.extra_filename(cnum),
+                    extra_filename: self.tcx.extra_filename(cnum).clone(),
                 };
                 (cnum, dep)
             })
@@ -2066,7 +2066,6 @@ fn visit_item(&mut self, item: &hir::Item<'_>) {
                         self.tcx,
                         trait_ref.self_ty(),
                         SimplifyParams::No,
-                        StripReferences::No,
                     );
 
                     self.impls
index a936852f4e7af96787ff9d89a863dd1b3cd59223..c4e6734aa0fa71efa23fc2c361a991e462889b35 100644 (file)
@@ -52,6 +52,9 @@ macro_rules! arena_types {
                         Vec<rustc_middle::traits::query::OutlivesBound<'tcx>>
                     >
                 >,
+            [] dtorck_constraint: rustc_middle::traits::query::DtorckConstraint<'tcx>,
+            [] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>,
+            [] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>,
             [] type_op_subtype:
                 rustc_middle::infer::canonical::Canonical<'tcx,
                     rustc_middle::infer::canonical::QueryResponse<'tcx, ()>
@@ -85,7 +88,8 @@ macro_rules! arena_types {
 
             // Interned types
             [] tys: rustc_middle::ty::TyS<'tcx>,
-            [] predicates: rustc_middle::ty::PredicateInner<'tcx>,
+            [] predicates: rustc_middle::ty::PredicateS<'tcx>,
+            [] consts: rustc_middle::ty::ConstS<'tcx>,
 
             // Note that this deliberately duplicates items in the `rustc_hir::arena`,
             // since we need to allocate this type on both the `rustc_hir` arena
@@ -95,6 +99,7 @@ macro_rules! arena_types {
             // This is used to decode the &'tcx [Span] for InlineAsm's line_spans.
             [decode] span: rustc_span::Span,
             [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
+            [decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
 
             [] dep_kind: rustc_middle::dep_graph::DepKindStruct,
         ]);
index cf50378ad606baa93e44abc69d7bbf0ff098aac5..6bfd1b7ffab2443a024db15cfe6b46a4832e9be3 100644 (file)
@@ -61,7 +61,7 @@ fn read_deps<OP>(op: OP)
         OP: for<'a> FnOnce(TaskDepsRef<'a>),
     {
         ty::tls::with_context_opt(|icx| {
-            let icx = if let Some(icx) = icx { icx } else { return };
+            let Some(icx) = icx else { return };
             op(icx.task_deps)
         })
     }
index 649cb34bd5f3cbd089d4d8f8683ddc30aaf3f7d3..f36847c778109249544df0d16fc5b77532854aa4 100644 (file)
@@ -149,18 +149,18 @@ fn next(&mut self) -> Option<Self::Item> {
 }
 
 impl<'hir> Map<'hir> {
-    pub fn krate(&self) -> &'hir Crate<'hir> {
+    pub fn krate(self) -> &'hir Crate<'hir> {
         self.tcx.hir_crate(())
     }
 
-    pub fn root_module(&self) -> &'hir Mod<'hir> {
+    pub fn root_module(self) -> &'hir Mod<'hir> {
         match self.tcx.hir_owner(CRATE_DEF_ID).map(|o| o.node) {
             Some(OwnerNode::Crate(item)) => item,
             _ => bug!(),
         }
     }
 
-    pub fn items(&self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
+    pub fn items(self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
         let krate = self.krate();
         krate.owners.iter().filter_map(|owner| match owner.as_owner()?.node() {
             OwnerNode::Item(item) => Some(item),
@@ -168,16 +168,16 @@ pub fn items(&self) -> impl Iterator<Item = &'hir Item<'hir>> + 'hir {
         })
     }
 
-    pub fn def_key(&self, def_id: LocalDefId) -> DefKey {
+    pub fn def_key(self, def_id: LocalDefId) -> DefKey {
         // Accessing the DefKey is ok, since it is part of DefPathHash.
         self.tcx.untracked_resolutions.definitions.def_key(def_id)
     }
 
-    pub fn def_path_from_hir_id(&self, id: HirId) -> Option<DefPath> {
+    pub fn def_path_from_hir_id(self, id: HirId) -> Option<DefPath> {
         self.opt_local_def_id(id).map(|def_id| self.def_path(def_id))
     }
 
-    pub fn def_path(&self, def_id: LocalDefId) -> DefPath {
+    pub fn def_path(self, def_id: LocalDefId) -> DefPath {
         // Accessing the DefPath is ok, since it is part of DefPathHash.
         self.tcx.untracked_resolutions.definitions.def_path(def_id)
     }
@@ -189,7 +189,7 @@ pub fn def_path_hash(self, def_id: LocalDefId) -> DefPathHash {
     }
 
     #[inline]
-    pub fn local_def_id(&self, hir_id: HirId) -> LocalDefId {
+    pub fn local_def_id(self, hir_id: HirId) -> LocalDefId {
         self.opt_local_def_id(hir_id).unwrap_or_else(|| {
             bug!(
                 "local_def_id: no entry for `{:?}`, which has a map of `{:?}`",
@@ -200,7 +200,7 @@ pub fn local_def_id(&self, hir_id: HirId) -> LocalDefId {
     }
 
     #[inline]
-    pub fn opt_local_def_id(&self, hir_id: HirId) -> Option<LocalDefId> {
+    pub fn opt_local_def_id(self, hir_id: HirId) -> Option<LocalDefId> {
         if hir_id.local_id == ItemLocalId::new(0) {
             Some(hir_id.owner)
         } else {
@@ -214,18 +214,18 @@ pub fn opt_local_def_id(&self, hir_id: HirId) -> Option<LocalDefId> {
     }
 
     #[inline]
-    pub fn local_def_id_to_hir_id(&self, def_id: LocalDefId) -> HirId {
+    pub fn local_def_id_to_hir_id(self, def_id: LocalDefId) -> HirId {
         self.tcx.local_def_id_to_hir_id(def_id)
     }
 
-    pub fn iter_local_def_id(&self) -> impl Iterator<Item = LocalDefId> + '_ {
+    pub fn iter_local_def_id(self) -> impl Iterator<Item = LocalDefId> + 'hir {
         // Create a dependency to the crate to be sure we reexcute this when the amount of
         // definitions change.
         self.tcx.ensure().hir_crate(());
         self.tcx.untracked_resolutions.definitions.iter_local_def_id()
     }
 
-    pub fn opt_def_kind(&self, local_def_id: LocalDefId) -> Option<DefKind> {
+    pub fn opt_def_kind(self, local_def_id: LocalDefId) -> Option<DefKind> {
         let hir_id = self.local_def_id_to_hir_id(local_def_id);
         let def_kind = match self.find(hir_id)? {
             Node::Item(item) => match item.kind {
@@ -312,12 +312,12 @@ pub fn opt_def_kind(&self, local_def_id: LocalDefId) -> Option<DefKind> {
         Some(def_kind)
     }
 
-    pub fn def_kind(&self, local_def_id: LocalDefId) -> DefKind {
+    pub fn def_kind(self, local_def_id: LocalDefId) -> DefKind {
         self.opt_def_kind(local_def_id)
             .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", local_def_id))
     }
 
-    pub fn find_parent_node(&self, id: HirId) -> Option<HirId> {
+    pub fn find_parent_node(self, id: HirId) -> Option<HirId> {
         if id.local_id == ItemLocalId::from_u32(0) {
             Some(self.tcx.hir_owner_parent(id.owner))
         } else {
@@ -328,12 +328,12 @@ pub fn find_parent_node(&self, id: HirId) -> Option<HirId> {
         }
     }
 
-    pub fn get_parent_node(&self, hir_id: HirId) -> HirId {
+    pub fn get_parent_node(self, hir_id: HirId) -> HirId {
         self.find_parent_node(hir_id).unwrap()
     }
 
     /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
-    pub fn find(&self, id: HirId) -> Option<Node<'hir>> {
+    pub fn find(self, id: HirId) -> Option<Node<'hir>> {
         if id.local_id == ItemLocalId::from_u32(0) {
             let owner = self.tcx.hir_owner(id.owner)?;
             Some(owner.node.into())
@@ -346,26 +346,26 @@ pub fn find(&self, id: HirId) -> Option<Node<'hir>> {
 
     /// Retrieves the `Node` corresponding to `id`, returning `None` if cannot be found.
     #[inline]
-    pub fn find_by_def_id(&self, id: LocalDefId) -> Option<Node<'hir>> {
+    pub fn find_by_def_id(self, id: LocalDefId) -> Option<Node<'hir>> {
         self.find(self.local_def_id_to_hir_id(id))
     }
 
     /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
-    pub fn get(&self, id: HirId) -> Node<'hir> {
+    pub fn get(self, id: HirId) -> Node<'hir> {
         self.find(id).unwrap_or_else(|| bug!("couldn't find hir id {} in the HIR map", id))
     }
 
     /// Retrieves the `Node` corresponding to `id`, panicking if it cannot be found.
     #[inline]
-    pub fn get_by_def_id(&self, id: LocalDefId) -> Node<'hir> {
+    pub fn get_by_def_id(self, id: LocalDefId) -> Node<'hir> {
         self.find_by_def_id(id).unwrap_or_else(|| bug!("couldn't find {:?} in the HIR map", id))
     }
 
-    pub fn get_if_local(&self, id: DefId) -> Option<Node<'hir>> {
+    pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {
         id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
     }
 
-    pub fn get_generics(&self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
+    pub fn get_generics(self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
         let node = self.tcx.hir_owner(id)?;
         match node.node {
             OwnerNode::ImplItem(impl_item) => Some(&impl_item.generics),
@@ -386,27 +386,27 @@ pub fn get_generics(&self, id: LocalDefId) -> Option<&'hir Generics<'hir>> {
         }
     }
 
-    pub fn item(&self, id: ItemId) -> &'hir Item<'hir> {
+    pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
         self.tcx.hir_owner(id.def_id).unwrap().node.expect_item()
     }
 
-    pub fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
+    pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> {
         self.tcx.hir_owner(id.def_id).unwrap().node.expect_trait_item()
     }
 
-    pub fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
+    pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> {
         self.tcx.hir_owner(id.def_id).unwrap().node.expect_impl_item()
     }
 
-    pub fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
+    pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
         self.tcx.hir_owner(id.def_id).unwrap().node.expect_foreign_item()
     }
 
-    pub fn body(&self, id: BodyId) -> &'hir Body<'hir> {
+    pub fn body(self, id: BodyId) -> &'hir Body<'hir> {
         self.tcx.hir_owner_nodes(id.hir_id.owner).unwrap().bodies[&id.hir_id.local_id]
     }
 
-    pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
+    pub fn fn_decl_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
         if let Some(node) = self.find(hir_id) {
             fn_decl(node)
         } else {
@@ -414,7 +414,7 @@ pub fn fn_decl_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnDecl<'hir>> {
         }
     }
 
-    pub fn fn_sig_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> {
+    pub fn fn_sig_by_hir_id(self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> {
         if let Some(node) = self.find(hir_id) {
             fn_sig(node)
         } else {
@@ -422,7 +422,7 @@ pub fn fn_sig_by_hir_id(&self, hir_id: HirId) -> Option<&'hir FnSig<'hir>> {
         }
     }
 
-    pub fn enclosing_body_owner(&self, hir_id: HirId) -> HirId {
+    pub fn enclosing_body_owner(self, hir_id: HirId) -> HirId {
         for (parent, _) in self.parent_iter(hir_id) {
             if let Some(body) = self.maybe_body_owned_by(parent) {
                 return self.body_owner(body);
@@ -435,24 +435,24 @@ pub fn enclosing_body_owner(&self, hir_id: HirId) -> HirId {
     /// Returns the `HirId` that corresponds to the definition of
     /// 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 {
+    pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
         let parent = self.get_parent_node(hir_id);
         assert!(self.find(parent).map_or(false, |n| is_body_owner(n, hir_id)));
         parent
     }
 
-    pub fn body_owner_def_id(&self, id: BodyId) -> LocalDefId {
+    pub fn body_owner_def_id(self, id: BodyId) -> LocalDefId {
         self.local_def_id(self.body_owner(id))
     }
 
     /// Given a `HirId`, returns the `BodyId` associated with it,
     /// if the node is a body owner, otherwise returns `None`.
-    pub fn maybe_body_owned_by(&self, hir_id: HirId) -> Option<BodyId> {
+    pub fn maybe_body_owned_by(self, hir_id: HirId) -> Option<BodyId> {
         self.find(hir_id).map(associated_body).flatten()
     }
 
     /// Given a body owner's id, returns the `BodyId` associated with it.
-    pub fn body_owned_by(&self, id: HirId) -> BodyId {
+    pub fn body_owned_by(self, id: HirId) -> BodyId {
         self.maybe_body_owned_by(id).unwrap_or_else(|| {
             span_bug!(
                 self.span(id),
@@ -462,7 +462,7 @@ pub fn body_owned_by(&self, id: HirId) -> BodyId {
         })
     }
 
-    pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
+    pub fn body_param_names(self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir {
         self.body(id).params.iter().map(|arg| match arg.pat.kind {
             PatKind::Binding(_, _, ident, _) => ident,
             _ => Ident::empty(),
@@ -472,7 +472,7 @@ pub fn body_param_names(&self, id: BodyId) -> impl Iterator<Item = Ident> + 'hir
     /// Returns the `BodyOwnerKind` of this `LocalDefId`.
     ///
     /// Panics if `LocalDefId` does not have an associated body.
-    pub fn body_owner_kind(&self, id: HirId) -> BodyOwnerKind {
+    pub fn body_owner_kind(self, id: HirId) -> BodyOwnerKind {
         match self.get(id) {
             Node::Item(&Item { kind: ItemKind::Const(..), .. })
             | Node::TraitItem(&TraitItem { kind: TraitItemKind::Const(..), .. })
@@ -495,7 +495,7 @@ pub fn body_owner_kind(&self, id: HirId) -> BodyOwnerKind {
     /// This should only be used for determining the context of a body, a return
     /// value of `Some` does not always suggest that the owner of the body is `const`,
     /// just that it has to be checked as if it were.
-    pub fn body_const_context(&self, did: LocalDefId) -> Option<ConstContext> {
+    pub fn body_const_context(self, did: LocalDefId) -> Option<ConstContext> {
         let hir_id = self.local_def_id_to_hir_id(did);
         let ccx = match self.body_owner_kind(hir_id) {
             BodyOwnerKind::Const => ConstContext::Const,
@@ -549,7 +549,7 @@ pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) {
         });
     }
 
-    pub fn ty_param_owner(&self, id: HirId) -> LocalDefId {
+    pub fn ty_param_owner(self, id: HirId) -> LocalDefId {
         match self.get(id) {
             Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => {
                 id.expect_owner()
@@ -559,7 +559,7 @@ pub fn ty_param_owner(&self, id: HirId) -> LocalDefId {
         }
     }
 
-    pub fn ty_param_name(&self, id: HirId) -> Symbol {
+    pub fn ty_param_name(self, id: HirId) -> Symbol {
         match self.get(id) {
             Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => {
                 kw::SelfUpper
@@ -569,18 +569,18 @@ pub fn ty_param_name(&self, id: HirId) -> Symbol {
         }
     }
 
-    pub fn trait_impls(&self, trait_did: DefId) -> &'hir [LocalDefId] {
+    pub fn trait_impls(self, trait_did: DefId) -> &'hir [LocalDefId] {
         self.tcx.all_local_trait_impls(()).get(&trait_did).map_or(&[], |xs| &xs[..])
     }
 
     /// Gets the attributes on the crate. This is preferable to
     /// invoking `krate.attrs` because it registers a tighter
     /// dep-graph access.
-    pub fn krate_attrs(&self) -> &'hir [ast::Attribute] {
+    pub fn krate_attrs(self) -> &'hir [ast::Attribute] {
         self.attrs(CRATE_HIR_ID)
     }
 
-    pub fn get_module(&self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
+    pub fn get_module(self, module: LocalDefId) -> (&'hir Mod<'hir>, Span, HirId) {
         let hir_id = HirId::make_owner(module);
         match self.tcx.hir_owner(module).map(|o| o.node) {
             Some(OwnerNode::Item(&Item { span, kind: ItemKind::Mod(ref m), .. })) => {
@@ -620,7 +620,7 @@ pub fn walk_attributes(self, visitor: &mut impl Visitor<'hir>) {
     /// follows lexical scoping rules -- then you want a different
     /// approach. You should override `visit_nested_item` in your
     /// visitor and then call `intravisit::walk_crate` instead.
-    pub fn visit_all_item_likes<V>(&self, visitor: &mut V)
+    pub fn visit_all_item_likes<V>(self, visitor: &mut V)
     where
         V: itemlikevisit::ItemLikeVisitor<'hir>,
     {
@@ -637,7 +637,7 @@ pub fn visit_all_item_likes<V>(&self, visitor: &mut V)
     }
 
     /// A parallel version of `visit_all_item_likes`.
-    pub fn par_visit_all_item_likes<V>(&self, visitor: &V)
+    pub fn par_visit_all_item_likes<V>(self, visitor: &V)
     where
         V: itemlikevisit::ParItemLikeVisitor<'hir> + Sync + Send,
     {
@@ -653,7 +653,7 @@ pub fn par_visit_all_item_likes<V>(&self, visitor: &V)
         })
     }
 
-    pub fn visit_item_likes_in_module<V>(&self, module: LocalDefId, visitor: &mut V)
+    pub fn visit_item_likes_in_module<V>(self, module: LocalDefId, visitor: &mut V)
     where
         V: ItemLikeVisitor<'hir>,
     {
@@ -676,7 +676,7 @@ pub fn visit_item_likes_in_module<V>(&self, module: LocalDefId, visitor: &mut V)
         }
     }
 
-    pub fn for_each_module(&self, f: impl Fn(LocalDefId)) {
+    pub fn for_each_module(self, f: impl Fn(LocalDefId)) {
         let mut queue = VecDeque::new();
         queue.push_back(CRATE_DEF_ID);
 
@@ -689,12 +689,12 @@ pub fn for_each_module(&self, f: impl Fn(LocalDefId)) {
 
     #[cfg(not(parallel_compiler))]
     #[inline]
-    pub fn par_for_each_module(&self, f: impl Fn(LocalDefId)) {
+    pub fn par_for_each_module(self, f: impl Fn(LocalDefId)) {
         self.for_each_module(f)
     }
 
     #[cfg(parallel_compiler)]
-    pub fn par_for_each_module(&self, f: impl Fn(LocalDefId) + Sync) {
+    pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync) {
         use rustc_data_structures::sync::{par_iter, ParallelIterator};
         par_iter_submodules(self.tcx, CRATE_DEF_ID, &f);
 
@@ -721,7 +721,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 {
+    pub fn is_lhs(self, id: HirId) -> bool {
         match self.find(self.get_parent_node(id)) {
             Some(Node::Expr(expr)) => match expr.kind {
                 ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id,
@@ -733,7 +733,7 @@ pub fn is_lhs(&self, id: HirId) -> bool {
 
     /// Whether the expression pointed at by `hir_id` belongs to a `const` evaluation context.
     /// Used exclusively for diagnostics, to avoid suggestion function calls.
-    pub fn is_inside_const_context(&self, hir_id: HirId) -> bool {
+    pub fn is_inside_const_context(self, hir_id: HirId) -> bool {
         self.body_const_context(self.local_def_id(self.enclosing_body_owner(hir_id))).is_some()
     }
 
@@ -759,7 +759,7 @@ pub fn is_inside_const_context(&self, hir_id: HirId) -> bool {
     ///     false
     /// }
     /// ```
-    pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
+    pub fn get_return_block(self, id: HirId) -> Option<HirId> {
         let mut iter = self.parent_iter(id).peekable();
         let mut ignore_tail = false;
         if let Some(node) = self.find(id) {
@@ -799,7 +799,7 @@ pub fn get_return_block(&self, id: HirId) -> Option<HirId> {
     /// parent item is in this map. The "parent item" is the closest parent node
     /// in the HIR which is recorded by the map and is an item, either an item
     /// in a module, trait, or impl.
-    pub fn get_parent_item(&self, hir_id: HirId) -> LocalDefId {
+    pub fn get_parent_item(self, hir_id: HirId) -> LocalDefId {
         if let Some((def_id, _node)) = self.parent_owner_iter(hir_id).next() {
             def_id
         } else {
@@ -809,7 +809,7 @@ pub fn get_parent_item(&self, hir_id: HirId) -> LocalDefId {
 
     /// Returns the `HirId` of `id`'s nearest module parent, or `id` itself if no
     /// module parent is in this map.
-    pub(super) fn get_module_parent_node(&self, hir_id: HirId) -> LocalDefId {
+    pub(super) fn get_module_parent_node(self, hir_id: HirId) -> LocalDefId {
         for (def_id, node) in self.parent_owner_iter(hir_id) {
             if let OwnerNode::Item(&Item { kind: ItemKind::Mod(_), .. }) = node {
                 return def_id;
@@ -823,7 +823,7 @@ pub(super) fn get_module_parent_node(&self, hir_id: HirId) -> LocalDefId {
     ///
     /// Used by error reporting when there's a type error in an if or match arm caused by the
     /// expression needing to be unit.
-    pub fn get_if_cause(&self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
+    pub fn get_if_cause(self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
         for (_, node) in self.parent_iter(hir_id) {
             match node {
                 Node::Item(_)
@@ -841,7 +841,7 @@ pub fn get_if_cause(&self, hir_id: HirId) -> Option<&'hir Expr<'hir>> {
     }
 
     /// Returns the nearest enclosing scope. A scope is roughly an item or block.
-    pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
+    pub fn get_enclosing_scope(self, hir_id: HirId) -> Option<HirId> {
         for (hir_id, node) in self.parent_iter(hir_id) {
             if let Node::Item(Item {
                 kind:
@@ -868,7 +868,7 @@ pub fn get_enclosing_scope(&self, hir_id: HirId) -> Option<HirId> {
     }
 
     /// Returns the defining scope for an opaque type definition.
-    pub fn get_defining_scope(&self, id: HirId) -> HirId {
+    pub fn get_defining_scope(self, id: HirId) -> HirId {
         let mut scope = id;
         loop {
             scope = self.get_enclosing_scope(scope).unwrap_or(CRATE_HIR_ID);
@@ -878,7 +878,7 @@ pub fn get_defining_scope(&self, id: HirId) -> HirId {
         }
     }
 
-    pub fn get_foreign_abi(&self, hir_id: HirId) -> Abi {
+    pub fn get_foreign_abi(self, hir_id: HirId) -> Abi {
         let parent = self.get_parent_item(hir_id);
         if let Some(node) = self.tcx.hir_owner(parent) {
             if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node.node
@@ -892,35 +892,35 @@ pub fn get_foreign_abi(&self, hir_id: HirId) -> Abi {
         )
     }
 
-    pub fn expect_item(&self, id: LocalDefId) -> &'hir Item<'hir> {
+    pub fn expect_item(self, id: LocalDefId) -> &'hir Item<'hir> {
         match self.tcx.hir_owner(id) {
             Some(Owner { node: OwnerNode::Item(item), .. }) => item,
             _ => bug!("expected item, found {}", self.node_to_string(HirId::make_owner(id))),
         }
     }
 
-    pub fn expect_impl_item(&self, id: LocalDefId) -> &'hir ImplItem<'hir> {
+    pub fn expect_impl_item(self, id: LocalDefId) -> &'hir ImplItem<'hir> {
         match self.tcx.hir_owner(id) {
             Some(Owner { node: OwnerNode::ImplItem(item), .. }) => item,
             _ => bug!("expected impl item, found {}", self.node_to_string(HirId::make_owner(id))),
         }
     }
 
-    pub fn expect_trait_item(&self, id: LocalDefId) -> &'hir TraitItem<'hir> {
+    pub fn expect_trait_item(self, id: LocalDefId) -> &'hir TraitItem<'hir> {
         match self.tcx.hir_owner(id) {
             Some(Owner { node: OwnerNode::TraitItem(item), .. }) => item,
             _ => bug!("expected trait item, found {}", self.node_to_string(HirId::make_owner(id))),
         }
     }
 
-    pub fn expect_variant(&self, id: HirId) -> &'hir Variant<'hir> {
+    pub fn expect_variant(self, id: HirId) -> &'hir Variant<'hir> {
         match self.find(id) {
             Some(Node::Variant(variant)) => variant,
             _ => bug!("expected variant, found {}", self.node_to_string(id)),
         }
     }
 
-    pub fn expect_foreign_item(&self, id: LocalDefId) -> &'hir ForeignItem<'hir> {
+    pub fn expect_foreign_item(self, id: LocalDefId) -> &'hir ForeignItem<'hir> {
         match self.tcx.hir_owner(id) {
             Some(Owner { node: OwnerNode::ForeignItem(item), .. }) => item,
             _ => {
@@ -929,14 +929,14 @@ pub fn expect_foreign_item(&self, id: LocalDefId) -> &'hir ForeignItem<'hir> {
         }
     }
 
-    pub fn expect_expr(&self, id: HirId) -> &'hir Expr<'hir> {
+    pub fn expect_expr(self, id: HirId) -> &'hir Expr<'hir> {
         match self.find(id) {
             Some(Node::Expr(expr)) => expr,
             _ => bug!("expected expr, found {}", self.node_to_string(id)),
         }
     }
 
-    pub fn opt_name(&self, id: HirId) -> Option<Symbol> {
+    pub fn opt_name(self, id: HirId) -> Option<Symbol> {
         Some(match self.get(id) {
             Node::Item(i) => i.ident.name,
             Node::ForeignItem(fi) => fi.ident.name,
@@ -952,7 +952,7 @@ pub fn opt_name(&self, id: HirId) -> Option<Symbol> {
         })
     }
 
-    pub fn name(&self, id: HirId) -> Symbol {
+    pub fn name(self, id: HirId) -> Symbol {
         match self.opt_name(id) {
             Some(name) => name,
             None => bug!("no name for {}", self.node_to_string(id)),
@@ -961,18 +961,18 @@ pub fn name(&self, id: HirId) -> Symbol {
 
     /// Given a node ID, gets a list of attributes associated with the AST
     /// corresponding to the node-ID.
-    pub fn attrs(&self, id: HirId) -> &'hir [ast::Attribute] {
+    pub fn attrs(self, id: HirId) -> &'hir [ast::Attribute] {
         self.tcx.hir_attrs(id.owner).get(id.local_id)
     }
 
     /// Gets the span of the definition of the specified HIR node.
     /// This is used by `tcx.get_span`
-    pub fn span(&self, hir_id: HirId) -> Span {
+    pub fn span(self, hir_id: HirId) -> Span {
         self.opt_span(hir_id)
             .unwrap_or_else(|| bug!("hir::map::Map::span: id not in map: {:?}", hir_id))
     }
 
-    pub fn opt_span(&self, hir_id: HirId) -> Option<Span> {
+    pub fn opt_span(self, hir_id: HirId) -> Option<Span> {
         let span = match self.find(hir_id)? {
             Node::Param(param) => param.span,
             Node::Item(item) => match &item.kind {
@@ -1021,7 +1021,7 @@ pub fn opt_span(&self, hir_id: HirId) -> Option<Span> {
 
     /// Like `hir.span()`, but includes the body of function items
     /// (instead of just the function header)
-    pub fn span_with_body(&self, hir_id: HirId) -> Span {
+    pub fn span_with_body(self, hir_id: HirId) -> Span {
         match self.find(hir_id) {
             Some(Node::TraitItem(item)) => item.span,
             Some(Node::ImplItem(impl_item)) => impl_item.span,
@@ -1031,11 +1031,11 @@ pub fn span_with_body(&self, hir_id: HirId) -> Span {
         }
     }
 
-    pub fn span_if_local(&self, id: DefId) -> Option<Span> {
+    pub fn span_if_local(self, id: DefId) -> Option<Span> {
         id.as_local().and_then(|id| self.opt_span(self.local_def_id_to_hir_id(id)))
     }
 
-    pub fn res_span(&self, res: Res) -> Option<Span> {
+    pub fn res_span(self, res: Res) -> Option<Span> {
         match res {
             Res::Err => None,
             Res::Local(id) => Some(self.span(id)),
@@ -1045,13 +1045,13 @@ pub fn res_span(&self, res: Res) -> Option<Span> {
 
     /// Get a representation of this `id` for debugging purposes.
     /// NOTE: Do NOT use this in diagnostics!
-    pub fn node_to_string(&self, id: HirId) -> String {
+    pub fn node_to_string(self, id: HirId) -> String {
         hir_id_to_string(self, id)
     }
 
     /// 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_hir_id(&self, anon_const: HirId) -> Option<HirId> {
+    pub fn opt_const_param_default_param_hir_id(self, anon_const: HirId) -> Option<HirId> {
         match self.get(self.get_parent_node(anon_const)) {
             Node::GenericParam(GenericParam {
                 hir_id: param_id,
@@ -1065,27 +1065,27 @@ pub fn opt_const_param_default_param_hir_id(&self, anon_const: HirId) -> Option<
 
 impl<'hir> intravisit::Map<'hir> for Map<'hir> {
     fn find(&self, hir_id: HirId) -> Option<Node<'hir>> {
-        self.find(hir_id)
+        (*self).find(hir_id)
     }
 
     fn body(&self, id: BodyId) -> &'hir Body<'hir> {
-        self.body(id)
+        (*self).body(id)
     }
 
     fn item(&self, id: ItemId) -> &'hir Item<'hir> {
-        self.item(id)
+        (*self).item(id)
     }
 
     fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
-        self.trait_item(id)
+        (*self).trait_item(id)
     }
 
     fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
-        self.impl_item(id)
+        (*self).impl_item(id)
     }
 
     fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
-        self.foreign_item(id)
+        (*self).foreign_item(id)
     }
 }
 
@@ -1154,7 +1154,7 @@ fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> {
     upstream_crates
 }
 
-fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String {
+fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
     let id_str = format!(" (hir_id={})", id);
 
     let path_str = || {
index 28217aeab13ee51d91d752fcfc5802b5d167cc49..419ed429246ac889076f23e8bbdf432eda48c7a5 100644 (file)
@@ -64,9 +64,9 @@ pub struct CanonicalVarValues<'tcx> {
 /// result.
 #[derive(Clone, Debug)]
 pub struct OriginalQueryValues<'tcx> {
-    /// Map from the universes that appear in the query to the
-    /// universes in the caller context. For the time being, we only
-    /// ever put ROOT values into the query, so this map is very
+    /// Map from the universes that appear in the query to the universes in the
+    /// caller context. For all queries except `evaluate_goal` (used by Chalk),
+    /// we only ever put ROOT values into the query, so this map is very
     /// simple.
     pub universe_map: SmallVec<[ty::UniverseIndex; 4]>,
 
@@ -328,8 +328,8 @@ pub fn make_identity(&self, tcx: TyCtxt<'tcx>) -> Self {
                         tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
                     }
                     GenericArgKind::Const(ct) => tcx
-                        .mk_const(ty::Const {
-                            ty: ct.ty,
+                        .mk_const(ty::ConstS {
+                            ty: ct.ty(),
                             val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
                         })
                         .into(),
index dcc49a5357248f6844e2c1f85ba45d09395ab2e7..dd303aaada9005626e49cf330e3fb0e9eab4418c 100644 (file)
@@ -32,9 +32,11 @@ fn from(vid: ty::RegionVid) -> Self {
 
 impl<'tcx> UnifyKey for RegionVidKey<'tcx> {
     type Value = UnifiedRegion<'tcx>;
+    #[inline]
     fn index(&self) -> u32 {
         self.vid.as_u32()
     }
+    #[inline]
     fn from_index(i: u32) -> Self {
         RegionVidKey::from(ty::RegionVid::from_u32(i))
     }
@@ -95,14 +97,14 @@ pub enum ConstVariableOriginKind {
 
 #[derive(Copy, Clone, Debug)]
 pub enum ConstVariableValue<'tcx> {
-    Known { value: &'tcx ty::Const<'tcx> },
+    Known { value: ty::Const<'tcx> },
     Unknown { universe: ty::UniverseIndex },
 }
 
 impl<'tcx> ConstVariableValue<'tcx> {
     /// If this value is known, returns the const it is known to be.
     /// Otherwise, `None`.
-    pub fn known(&self) -> Option<&'tcx ty::Const<'tcx>> {
+    pub fn known(&self) -> Option<ty::Const<'tcx>> {
         match *self {
             ConstVariableValue::Unknown { .. } => None,
             ConstVariableValue::Known { value } => Some(value),
@@ -118,9 +120,11 @@ pub struct ConstVarValue<'tcx> {
 
 impl<'tcx> UnifyKey for ty::ConstVid<'tcx> {
     type Value = ConstVarValue<'tcx>;
+    #[inline]
     fn index(&self) -> u32 {
         self.index
     }
+    #[inline]
     fn from_index(i: u32) -> Self {
         ty::ConstVid { index: i, phantom: PhantomData }
     }
@@ -130,7 +134,7 @@ fn tag() -> &'static str {
 }
 
 impl<'tcx> UnifyValue for ConstVarValue<'tcx> {
-    type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>);
+    type Error = (ty::Const<'tcx>, ty::Const<'tcx>);
 
     fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
         Ok(match (value1.val, value2.val) {
@@ -162,18 +166,18 @@ fn unify_values(&value1: &Self, &value2: &Self) -> Result<Self, Self::Error> {
     }
 }
 
-impl<'tcx> EqUnifyValue for &'tcx ty::Const<'tcx> {}
+impl<'tcx> EqUnifyValue for ty::Const<'tcx> {}
 
 pub fn replace_if_possible<'tcx, V, L>(
     table: &mut UnificationTable<InPlace<ty::ConstVid<'tcx>, V, L>>,
-    c: &'tcx ty::Const<'tcx>,
-) -> &'tcx ty::Const<'tcx>
+    c: ty::Const<'tcx>,
+) -> ty::Const<'tcx>
 where
     V: snapshot_vec::VecLike<unify::Delegate<ty::ConstVid<'tcx>>>,
     L: UndoLogs<snapshot_vec::UndoLog<unify::Delegate<ty::ConstVid<'tcx>>>>,
 {
-    if let ty::Const { val: ty::ConstKind::Infer(InferConst::Var(vid)), .. } = c {
-        match table.probe_value(*vid).val.known() {
+    if let ty::ConstKind::Infer(InferConst::Var(vid)) = c.val() {
+        match table.probe_value(vid).val.known() {
             Some(c) => c,
             None => c,
         }
index b054d21adaa139354d5c3ba05fe70d18fd19e1d7..54eb2dc9e2890647b5f4652627c27e32e05a55b9 100644 (file)
@@ -89,6 +89,8 @@ pub struct CodegenFnAttrFlags: u32 {
         /// the MIR `InstrumentCoverage` pass and not added to the coverage map
         /// during codegen.
         const NO_COVERAGE               = 1 << 15;
+        /// `#[used(linker)]`: indicates that LLVM nor the linker can eliminate this function.
+        const USED_LINKER               = 1 << 16;
     }
 }
 
index 6d531d3e7d620fa68a52d06c25d4bd038ca2edf9..03cca51dc0b5474b28fa75dcb1627480197616b0 100644 (file)
@@ -29,7 +29,7 @@ pub enum StabilityLevel {
 }
 
 /// An entry in the `depr_map`.
-#[derive(Clone, HashStable, Debug)]
+#[derive(Copy, Clone, HashStable, Debug)]
 pub struct DeprecationEntry {
     /// The metadata of the attribute associated with this entry.
     pub attr: Deprecation,
index ec0f5b7d0595cb070a576d85111a675ce53e25f9..4a57f483c70e2b8a1069263ca031f8271ca817a5 100644 (file)
@@ -98,4 +98,12 @@ fn eval_to_allocation(
         let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?;
         Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory())
     }
+
+    /// Destructure a constant ADT or array into its variant index and its field values.
+    pub fn destructure_const(
+        self,
+        param_env_and_val: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>,
+    ) -> mir::DestructuredConst<'tcx> {
+        self.try_destructure_const(param_env_and_val).unwrap()
+    }
 }
index e9e6d61331077e4575757b67cb93953e19eda54c..7e5f8018dfc422e26521389256d216d3194b0012 100644 (file)
@@ -13,6 +13,7 @@
 use crate::ty::{self, List, Ty, TyCtxt};
 use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex};
 
+use rustc_errors::ErrorReported;
 use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
 use rustc_hir::{self, GeneratorKind};
@@ -284,6 +285,8 @@ pub struct Body<'tcx> {
 
     predecessor_cache: PredecessorCache,
     is_cyclic: GraphIsCyclicCache,
+
+    pub tainted_by_errors: Option<ErrorReported>,
 }
 
 impl<'tcx> Body<'tcx> {
@@ -297,6 +300,7 @@ pub fn new(
         var_debug_info: Vec<VarDebugInfo<'tcx>>,
         span: Span,
         generator_kind: Option<GeneratorKind>,
+        tainted_by_errors: Option<ErrorReported>,
     ) -> Self {
         // We need `arg_count` locals, and one for the return place.
         assert!(
@@ -329,6 +333,7 @@ pub fn new(
             is_polymorphic: false,
             predecessor_cache: PredecessorCache::new(),
             is_cyclic: GraphIsCyclicCache::new(),
+            tainted_by_errors,
         };
         body.is_polymorphic = body.has_param_types_or_consts();
         body
@@ -356,6 +361,7 @@ pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) ->
             is_polymorphic: false,
             predecessor_cache: PredecessorCache::new(),
             is_cyclic: GraphIsCyclicCache::new(),
+            tainted_by_errors: None,
         };
         body.is_polymorphic = body.has_param_types_or_consts();
         body
@@ -1577,7 +1583,7 @@ pub enum StatementKind<'tcx> {
     /// - `Bivariant` -- no effect
     AscribeUserType(Box<(Place<'tcx>, UserTypeProjection)>, ty::Variance),
 
-    /// Marks the start of a "coverage region", injected with '-Zinstrument-coverage'. A
+    /// Marks the start of a "coverage region", injected with '-Cinstrument-coverage'. A
     /// `Coverage` statement carries metadata about the coverage region, used to inject a coverage
     /// map into the binary. If `Coverage::kind` is a `Counter`, the statement also generates
     /// executable code, to increment a counter variable at runtime, each time the code region is
@@ -2179,7 +2185,7 @@ pub enum Rvalue<'tcx> {
     Use(Operand<'tcx>),
 
     /// [x; 32]
-    Repeat(Operand<'tcx>, &'tcx ty::Const<'tcx>),
+    Repeat(Operand<'tcx>, ty::Const<'tcx>),
 
     /// &x or &mut x
     Ref(Region<'tcx>, BorrowKind, Place<'tcx>),
@@ -2264,11 +2270,13 @@ pub enum BinOp {
     Mul,
     /// The `/` operator (division)
     ///
-    /// Division by zero is UB.
+    /// Division by zero is UB, because the compiler should have inserted checks
+    /// prior to this.
     Div,
     /// The `%` operator (modulus)
     ///
-    /// Using zero as the modulus (second operand) is UB.
+    /// Using zero as the modulus (second operand) is UB, because the compiler
+    /// should have inserted checks prior to this.
     Rem,
     /// The `^` operator (bitwise xor)
     BitXor,
@@ -2329,7 +2337,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
 
         match *self {
             Use(ref place) => write!(fmt, "{:?}", place),
-            Repeat(ref a, ref b) => {
+            Repeat(ref a, b) => {
                 write!(fmt, "[{:?}; ", a)?;
                 pretty_print_const(b, fmt, false)?;
                 write!(fmt, "]")
@@ -2508,7 +2516,7 @@ pub struct Constant<'tcx> {
 #[derive(Lift)]
 pub enum ConstantKind<'tcx> {
     /// This constant came from the type system
-    Ty(&'tcx ty::Const<'tcx>),
+    Ty(ty::Const<'tcx>),
     /// This constant cannot go back into the type system, as it represents
     /// something the type system cannot handle (e.g. pointers).
     Val(interpret::ConstValue<'tcx>, Ty<'tcx>),
@@ -2516,7 +2524,7 @@ pub enum ConstantKind<'tcx> {
 
 impl<'tcx> Constant<'tcx> {
     pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
-        match self.literal.const_for_ty()?.val.try_to_scalar() {
+        match self.literal.try_to_scalar() {
             Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
                 GlobalAlloc::Static(def_id) => {
                     assert!(!tcx.is_thread_local_static(def_id));
@@ -2533,33 +2541,33 @@ pub fn ty(&self) -> Ty<'tcx> {
     }
 }
 
-impl<'tcx> From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> {
+impl<'tcx> From<ty::Const<'tcx>> for ConstantKind<'tcx> {
     #[inline]
-    fn from(ct: &'tcx ty::Const<'tcx>) -> Self {
+    fn from(ct: ty::Const<'tcx>) -> Self {
         Self::Ty(ct)
     }
 }
 
 impl<'tcx> ConstantKind<'tcx> {
     /// Returns `None` if the constant is not trivially safe for use in the type system.
-    pub fn const_for_ty(&self) -> Option<&'tcx ty::Const<'tcx>> {
+    pub fn const_for_ty(&self) -> Option<ty::Const<'tcx>> {
         match self {
-            ConstantKind::Ty(c) => Some(c),
+            ConstantKind::Ty(c) => Some(*c),
             ConstantKind::Val(..) => None,
         }
     }
 
     pub fn ty(&self) -> Ty<'tcx> {
         match self {
-            ConstantKind::Ty(c) => c.ty,
-            ConstantKind::Val(_, ty) => ty,
+            ConstantKind::Ty(c) => c.ty(),
+            ConstantKind::Val(_, ty) => *ty,
         }
     }
 
     #[inline]
     pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> {
         match self {
-            ConstantKind::Ty(c) => c.val.try_to_value(),
+            ConstantKind::Ty(c) => c.val().try_to_value(),
             ConstantKind::Val(val, _) => Some(val),
         }
     }
@@ -2823,7 +2831,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
 }
 
 fn pretty_print_const<'tcx>(
-    c: &ty::Const<'tcx>,
+    c: ty::Const<'tcx>,
     fmt: &mut Formatter<'_>,
     print_types: bool,
 ) -> fmt::Result {
index f2ad591071114bb043961e8c8679a4211447c2e2..784babffeff42e0bb598c84bc90acb97ef1cd285 100644 (file)
@@ -17,9 +17,8 @@
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::MirSource;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, TyCtxt};
 use rustc_target::abi::Size;
-use std::ops::ControlFlow;
 
 const INDENT: &str = "    ";
 /// Alignment for lining up comments following MIR statements
@@ -427,12 +426,12 @@ fn push(&mut self, lines: &str) {
     }
 }
 
-fn use_verbose<'tcx>(ty: &&TyS<'tcx>, fn_def: bool) -> bool {
-    match ty.kind() {
+fn use_verbose<'tcx>(ty: Ty<'tcx>, fn_def: bool) -> bool {
+    match *ty.kind() {
         ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => false,
         // Unit type
         ty::Tuple(g_args) if g_args.is_empty() => false,
-        ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(&g_arg.expect_ty(), fn_def)),
+        ty::Tuple(g_args) => g_args.iter().any(|g_arg| use_verbose(g_arg.expect_ty(), fn_def)),
         ty::Array(ty, _) => use_verbose(ty, fn_def),
         ty::FnDef(..) => fn_def,
         _ => true,
@@ -443,7 +442,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
     fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
         self.super_constant(constant, location);
         let Constant { span, user_ty, literal } = constant;
-        if use_verbose(&literal.ty(), true) {
+        if use_verbose(literal.ty(), true) {
             self.push("mir::Constant");
             self.push(&format!(
                 "+ span: {}",
@@ -462,9 +461,10 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
         }
     }
 
-    fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
+    fn visit_const(&mut self, constant: ty::Const<'tcx>, _: Location) {
         self.super_const(constant);
-        let ty::Const { ty, val, .. } = constant;
+        let ty = constant.ty();
+        let val = constant.val();
         if use_verbose(ty, false) {
             self.push("ty::Const");
             self.push(&format!("+ ty: {:?}", ty));
@@ -668,6 +668,7 @@ pub fn write_allocations<'tcx>(
     fn alloc_ids_from_alloc(alloc: &Allocation) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
         alloc.relocations().values().map(|id| *id)
     }
+
     fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
         match val {
             ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _size)) => {
@@ -681,17 +682,29 @@ fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> +
             }
         }
     }
+
     struct CollectAllocIds(BTreeSet<AllocId>);
-    impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
-        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-            if let ty::ConstKind::Value(val) = c.val {
+
+    impl<'tcx> Visitor<'tcx> for CollectAllocIds {
+        fn visit_const(&mut self, c: ty::Const<'tcx>, _loc: Location) {
+            if let ty::ConstKind::Value(val) = c.val() {
                 self.0.extend(alloc_ids_from_const(val));
             }
-            c.super_visit_with(self)
+        }
+
+        fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) {
+            match c.literal {
+                ConstantKind::Ty(c) => self.visit_const(c, loc),
+                ConstantKind::Val(val, _) => {
+                    self.0.extend(alloc_ids_from_const(val));
+                }
+            }
         }
     }
+
     let mut visitor = CollectAllocIds(Default::default());
-    body.visit_with(&mut visitor);
+    visitor.visit_body(body);
+
     // `seen` contains all seen allocations, including the ones we have *not* printed yet.
     // The protocol is to first `insert` into `seen`, and only if that returns `true`
     // then push to `todo`.
index cb3f3850958ec90d85d9e4d1e0db2667fca32a93..5c616425957df5fef5242920d5327109e76f435b 100644 (file)
@@ -214,6 +214,7 @@ pub struct BorrowCheckResult<'tcx> {
     pub concrete_opaque_types: VecMap<OpaqueTypeKey<'tcx>, Ty<'tcx>>,
     pub closure_requirements: Option<ClosureRegionRequirements<'tcx>>,
     pub used_mut_upvars: SmallVec<[Field; 8]>,
+    pub tainted_by_errors: Option<ErrorReported>,
 }
 
 /// The result of the `mir_const_qualif` query.
@@ -227,7 +228,7 @@ pub struct ConstQualifs {
     pub needs_drop: bool,
     pub needs_non_const_drop: bool,
     pub custom_eq: bool,
-    pub error_occured: Option<ErrorReported>,
+    pub tainted_by_errors: Option<ErrorReported>,
 }
 
 /// After we borrow check a closure, we are left with various
@@ -386,11 +387,11 @@ pub enum ClosureOutlivesSubject<'tcx> {
 #[derive(Copy, Clone, Debug, HashStable)]
 pub struct DestructuredConst<'tcx> {
     pub variant: Option<VariantIdx>,
-    pub fields: &'tcx [&'tcx ty::Const<'tcx>],
+    pub fields: &'tcx [ty::Const<'tcx>],
 }
 
 /// Coverage information summarized from a MIR if instrumented for source code coverage (see
-/// compiler option `-Zinstrument-coverage`). This information is generated by the
+/// compiler option `-Cinstrument-coverage`). This information is generated by the
 /// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.
 #[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable)]
 pub struct CoverageInfo {
index dc53dc8de9de95129a800945dff0240da0a42bf2..302921cc4aa721fb30da49259460fe1a969e05d2 100644 (file)
@@ -57,7 +57,7 @@ pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> {
     /// `PlaceElem`, where we can just use the `Ty` that is already
     /// stored inline on field projection elems.
     pub fn projection_ty(self, tcx: TyCtxt<'tcx>, elem: PlaceElem<'tcx>) -> PlaceTy<'tcx> {
-        self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, ty| ty)
+        self.projection_ty_core(tcx, ty::ParamEnv::empty(), &elem, |_, _, &ty| ty)
     }
 
     /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@@ -93,11 +93,11 @@ pub fn projection_ty_core<V, T>(
             ProjectionElem::Subslice { from, to, from_end } => {
                 PlaceTy::from_ty(match self.ty.kind() {
                     ty::Slice(..) => self.ty,
-                    ty::Array(inner, _) if !from_end => tcx.mk_array(inner, (to - from) as u64),
+                    ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64),
                     ty::Array(inner, size) if from_end => {
                         let size = size.eval_usize(tcx, param_env);
                         let len = size - (from as u64) - (to as u64);
-                        tcx.mk_array(inner, len)
+                        tcx.mk_array(*inner, len)
                     }
                     _ => bug!("cannot subslice non-array type: `{:?}`", self),
                 })
index fafd847a1cbaa8ece09222a40c5623f1a1b1fad4..ae94bd121f9535bac46429ea4075e3bbf678afe2 100644 (file)
@@ -430,7 +430,7 @@ pub fn unwind_mut(&mut self) -> Option<&mut Option<BasicBlock>> {
     pub fn as_switch(&self) -> Option<(&Operand<'tcx>, Ty<'tcx>, &SwitchTargets)> {
         match self {
             TerminatorKind::SwitchInt { discr, switch_ty, targets } => {
-                Some((discr, switch_ty, targets))
+                Some((discr, *switch_ty, targets))
             }
             _ => None,
         }
index 8c930fd161efbf4ce6e86e0779f69b2bc228da2d..480f28620dc8fb0402484e337646cf6f3782502e 100644 (file)
@@ -4,8 +4,9 @@
 
 /// Preorder traversal of a graph.
 ///
-/// Preorder traversal is when each node is visited before any of its
-/// successors
+/// Preorder traversal is when each node is visited after at least one of its predecessors. If you
+/// are familar with some basic graph theory, then this performs a depth first search and returns
+/// nodes in order of discovery time.
 ///
 /// ```text
 ///
@@ -82,8 +83,9 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 
 /// Postorder traversal of a graph.
 ///
-/// Postorder traversal is when each node is visited after all of its
-/// successors, except when the successor is only reachable by a back-edge
+/// Postorder traversal is when each node is visited after all of its successors, except when the
+/// successor is only reachable by a back-edge. If you are familiar with some basic graph theory,
+/// then this performs a depth first search and returns nodes in order of completion time.
 ///
 ///
 /// ```text
index 4452ac5e3e0d4b92f0f46dc7b1e91d5343feb8fc..a618800cc1bd2c12a51a8b830f77ad276227f834 100644 (file)
@@ -194,13 +194,13 @@ fn visit_user_type_annotation(
             }
 
             fn visit_region(&mut self,
-                            region: & $($mutability)? ty::Region<'tcx>,
+                            region: $(& $mutability)? ty::Region<'tcx>,
                             _: Location) {
                 self.super_region(region);
             }
 
             fn visit_const(&mut self,
-                           constant: & $($mutability)? &'tcx ty::Const<'tcx>,
+                           constant: $(& $mutability)? ty::Const<'tcx>,
                            _: Location) {
                 self.super_const(constant);
             }
@@ -242,7 +242,7 @@ fn super_body(
             ) {
                 let span = body.span;
                 if let Some(gen) = &$($mutability)? body.generator {
-                    if let Some(yield_ty) = &$($mutability)? gen.yield_ty {
+                    if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
                         self.visit_ty(
                             yield_ty,
                             TyContext::YieldTy(SourceInfo::outermost(span))
@@ -266,7 +266,7 @@ macro_rules! basic_blocks {
                 }
 
                 self.visit_ty(
-                    &$($mutability)? body.return_ty(),
+                    $(& $mutability)? body.return_ty(),
                     TyContext::ReturnTy(SourceInfo::outermost(body.span))
                 );
 
@@ -355,7 +355,7 @@ fn super_source_scope_data(
                         ty::InstanceDef::DropGlue(_def_id, Some(ty)) |
                         ty::InstanceDef::CloneShim(_def_id, ty) => {
                             // FIXME(eddyb) use a better `TyContext` here.
-                            self.visit_ty(ty, TyContext::Location(location));
+                            self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
                         }
                     }
                     self.visit_substs(callee_substs, location);
@@ -487,7 +487,7 @@ fn super_terminator(&mut self,
                         targets: _
                     } => {
                         self.visit_operand(discr, location);
-                        self.visit_ty(switch_ty, TyContext::Location(location));
+                        self.visit_ty($(& $mutability)? *switch_ty, TyContext::Location(location));
                     }
 
                     TerminatorKind::Drop {
@@ -641,7 +641,7 @@ fn super_rvalue(&mut self,
                     Rvalue::ThreadLocalRef(_) => {}
 
                     Rvalue::Ref(r, bk, path) => {
-                        self.visit_region(r, location);
+                        self.visit_region($(& $mutability)? *r, location);
                         let ctx = match bk {
                             BorrowKind::Shared => PlaceContext::NonMutatingUse(
                                 NonMutatingUseContext::SharedBorrow
@@ -680,7 +680,7 @@ fn super_rvalue(&mut self,
 
                     Rvalue::Cast(_cast_kind, operand, ty) => {
                         self.visit_operand(operand, location);
-                        self.visit_ty(ty, TyContext::Location(location));
+                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
                     }
 
                     Rvalue::BinaryOp(_bin_op, box(lhs, rhs))
@@ -702,14 +702,14 @@ fn super_rvalue(&mut self,
                     }
 
                     Rvalue::NullaryOp(_op, ty) => {
-                        self.visit_ty(ty, TyContext::Location(location));
+                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
                     }
 
                     Rvalue::Aggregate(kind, operands) => {
                         let kind = &$($mutability)? **kind;
                         match kind {
                             AggregateKind::Array(ty) => {
-                                self.visit_ty(ty, TyContext::Location(location));
+                                self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
                             }
                             AggregateKind::Tuple => {
                             }
@@ -744,7 +744,7 @@ fn super_rvalue(&mut self,
 
                     Rvalue::ShallowInitBox(operand, ty) => {
                         self.visit_operand(operand, location);
-                        self.visit_ty(ty, TyContext::Location(location));
+                        self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
                     }
                 }
             }
@@ -815,7 +815,7 @@ fn super_local_decl(&mut self,
                     is_block_tail: _,
                 } = local_decl;
 
-                self.visit_ty(ty, TyContext::LocalDecl {
+                self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl {
                     local,
                     source_info: *source_info,
                 });
@@ -864,8 +864,8 @@ fn super_constant(&mut self,
                 self.visit_span(span);
                 drop(user_ty); // no visit method for this
                 match literal {
-                    ConstantKind::Ty(ct) => self.visit_const(ct, location),
-                    ConstantKind::Val(_, t) => self.visit_ty(t, TyContext::Location(location)),
+                    ConstantKind::Ty(ct) => self.visit_const($(& $mutability)? *ct, location),
+                    ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
                 }
             }
 
@@ -894,16 +894,16 @@ fn super_user_type_annotation(
                 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
             ) {
                 self.visit_span(& $($mutability)? ty.span);
-                self.visit_ty(& $($mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
+                self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
             }
 
             fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {
             }
 
-            fn super_region(&mut self, _region: & $($mutability)? ty::Region<'tcx>) {
+            fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) {
             }
 
-            fn super_const(&mut self, _const: & $($mutability)? &'tcx ty::Const<'tcx>) {
+            fn super_const(&mut self, _const: $(& $mutability)? ty::Const<'tcx>) {
             }
 
             fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) {
index 2e7dfb73c2cf4a3914c8e69be57c5f70ef457500..43cfe6f3b8a7a51e608f6ff6ed38d817ba1f6368 100644 (file)
 
     /// Given the def_id of a const-generic parameter, computes the associated default const
     /// parameter. e.g. `fn example<const N: usize=3>` called on `N` would return `3`.
-    query const_param_default(param: DefId) -> &'tcx ty::Const<'tcx> {
+    query const_param_default(param: DefId) -> ty::Const<'tcx> {
         desc { |tcx| "compute const default for a given parameter `{}`", tcx.def_path_str(param)  }
         separate_provide_extern
     }
         desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
     }
 
-    query native_libraries(_: CrateNum) -> Lrc<Vec<NativeLib>> {
+    query native_libraries(_: CrateNum) -> Vec<NativeLib> {
+        storage(ArenaCacheSelector<'tcx>)
         desc { "looking up the native libraries of a linked crate" }
         separate_provide_extern
     }
     /// Create a THIR tree for debugging.
     query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> String {
         no_hash
+        storage(ArenaCacheSelector<'tcx>)
         desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) }
     }
 
     query symbols_for_closure_captures(
         key: (LocalDefId, DefId)
     ) -> Vec<rustc_span::Symbol> {
+        storage(ArenaCacheSelector<'tcx>)
         desc {
             |tcx| "symbols for captures of closure `{}` in `{}`",
             tcx.def_path_str(key.1),
     }
 
     /// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
-    /// MIR pass (assuming the -Zinstrument-coverage option is enabled).
+    /// MIR pass (assuming the -Cinstrument-coverage option is enabled).
     query coverageinfo(key: ty::InstanceDef<'tcx>) -> mir::CoverageInfo {
         desc { |tcx| "retrieving coverage info from MIR for `{}`", tcx.def_path_str(key.def_id()) }
         storage(ArenaCacheSelector<'tcx>)
 
     query adt_dtorck_constraint(
         key: DefId
-    ) -> Result<DtorckConstraint<'tcx>, NoSolution> {
+    ) -> Result<&'tcx DtorckConstraint<'tcx>, NoSolution> {
         desc { |tcx| "computing drop-check constraints for `{}`", tcx.def_path_str(key) }
     }
 
     /// The map returned for `tcx.impl_item_implementor_ids(impl_id)` would be
     ///`{ trait_f: impl_f, trait_g: impl_g }`
     query impl_item_implementor_ids(impl_id: DefId) -> FxHashMap<DefId, DefId> {
-        desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) }
         storage(ArenaCacheSelector<'tcx>)
+        desc { |tcx| "comparing impl items against trait for {}", tcx.def_path_str(impl_id) }
     }
 
     /// Given an `impl_id`, return the trait it implements.
     }
 
     /// Destructure a constant ADT or array into its variant index and its
-    /// field values.
-    query destructure_const(
-        key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
-    ) -> mir::DestructuredConst<'tcx> {
+    /// field values or return `None` if constant is invalid.
+    ///
+    /// Use infallible `TyCtxt::destructure_const` when you know that constant is valid.
+    query try_destructure_const(
+        key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>
+    ) -> Option<mir::DestructuredConst<'tcx>> {
         desc { "destructure constant" }
         remap_env_constness
     }
     /// Dereference a constant reference or raw pointer and turn the result into a constant
     /// again.
     query deref_const(
-        key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>>
-    ) -> &'tcx ty::Const<'tcx> {
+        key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>
+    ) -> ty::Const<'tcx> {
         desc { "deref constant" }
         remap_env_constness
     }
 
     query lit_to_const(
         key: LitToConstInput<'tcx>
-    ) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
+    ) -> Result<ty::Const<'tcx>, LitToConstError> {
         desc { "converting literal to const" }
     }
 
     /// Gets the rendered value of the specified constant or associated constant.
     /// Used by rustdoc.
     query rendered_const(def_id: DefId) -> String {
+        storage(ArenaCacheSelector<'tcx>)
         desc { |tcx| "rendering constant intializer of `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
 
     query codegen_fulfill_obligation(
         key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
-    ) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
+    ) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorReported> {
         cache_on_disk_if { true }
         desc { |tcx|
             "checking if `{}` fulfills its obligations",
         desc { "computing whether `{}` is `Copy`", env.value }
         remap_env_constness
     }
-    /// Query backing `TyS::is_sized`.
+    /// Query backing `Ty::is_sized`.
     query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` is `Sized`", env.value }
         remap_env_constness
     }
-    /// Query backing `TyS::is_freeze`.
+    /// Query backing `Ty::is_freeze`.
     query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` is freeze", env.value }
         remap_env_constness
     }
-    /// Query backing `TyS::is_unpin`.
+    /// Query backing `Ty::is_unpin`.
     query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` is `Unpin`", env.value }
         remap_env_constness
     }
-    /// Query backing `TyS::needs_drop`.
+    /// Query backing `Ty::needs_drop`.
     query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` needs drop", env.value }
         remap_env_constness
     }
-    /// Query backing `TyS::has_significant_drop_raw`.
+    /// Query backing `Ty::has_significant_drop_raw`.
     query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
         desc { "computing whether `{}` has a significant drop", env.value }
         remap_env_constness
     }
 
-    /// Query backing `TyS::is_structural_eq_shallow`.
+    /// Query backing `Ty::is_structural_eq_shallow`.
     ///
     /// This is only correct for ADTs. Call `is_structural_eq_shallow` to handle all types
     /// correctly.
     }
 
     query dependency_formats(_: ()) -> Lrc<crate::middle::dependency_format::Dependencies> {
+        storage(ArenaCacheSelector<'tcx>)
         desc { "get the linkage format of all dependencies" }
     }
 
     /// You likely want to call `Instance::upstream_monomorphization()`
     /// instead of invoking this query directly.
     query upstream_monomorphizations_for(def_id: DefId)
-        -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>> {
-            desc { |tcx|
-                "collecting available upstream monomorphizations for `{}`",
-                tcx.def_path_str(def_id),
-            }
-            separate_provide_extern
+        -> Option<&'tcx FxHashMap<SubstsRef<'tcx>, CrateNum>>
+    {
+        storage(ArenaCacheSelector<'tcx>)
+        desc { |tcx|
+            "collecting available upstream monomorphizations for `{}`",
+            tcx.def_path_str(def_id),
         }
+        separate_provide_extern
+    }
 
     /// Returns the upstream crate that exports drop-glue for the given
     /// type (`substs` is expected to be a single-item list containing the
         desc { "available upstream drop-glue for `{:?}`", substs }
     }
 
-    query foreign_modules(_: CrateNum) -> Lrc<FxHashMap<DefId, ForeignModule>> {
+    query foreign_modules(_: CrateNum) -> FxHashMap<DefId, ForeignModule> {
+        storage(ArenaCacheSelector<'tcx>)
         desc { "looking up the foreign modules of a linked crate" }
         separate_provide_extern
     }
         separate_provide_extern
     }
     query extra_filename(_: CrateNum) -> String {
+        storage(ArenaCacheSelector<'tcx>)
         eval_always
         desc { "looking up the extra filename for a crate" }
         separate_provide_extern
     }
     query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
+        storage(ArenaCacheSelector<'tcx>)
         eval_always
         desc { "looking up the paths for extern crates" }
         separate_provide_extern
     /// for each parameter if a trait object were to be passed for that parameter.
     /// For example, for `struct Foo<'a, T, U>`, this would be `['static, 'static]`.
     /// For `struct Foo<'a, T: 'a, U>`, this would instead be `['a, 'static]`.
-    query object_lifetime_defaults_map(_: LocalDefId)
-        -> Option<Vec<ObjectLifetimeDefault>> {
+    query object_lifetime_defaults(_: LocalDefId) -> Option<&'tcx [ObjectLifetimeDefault]> {
         desc { "looking up lifetime defaults for a region on an item" }
     }
     query late_bound_vars_map(_: LocalDefId)
     }
 
     query lifetime_scope_map(_: LocalDefId) -> Option<FxHashMap<ItemLocalId, LifetimeScopeForPath>> {
+        storage(ArenaCacheSelector<'tcx>)
         desc { "finds the lifetime scope for an HirId of a PathSegment" }
     }
 
     /// check whether the forest is empty.
     query type_uninhabited_from(
         key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
-    ) -> ty::inhabitedness::DefIdForest {
+    ) -> ty::inhabitedness::DefIdForest<'tcx> {
         desc { "computing the inhabitedness of `{:?}`", key }
         remap_env_constness
     }
         desc { "calculating the missing lang items in a crate" }
         separate_provide_extern
     }
-    query visible_parent_map(_: ()) -> Lrc<DefIdMap<DefId>> {
+    query visible_parent_map(_: ()) -> DefIdMap<DefId> {
+        storage(ArenaCacheSelector<'tcx>)
         desc { "calculating the visible parent map" }
     }
     query trimmed_def_paths(_: ()) -> FxHashMap<DefId, Symbol> {
         separate_provide_extern
     }
     query used_crate_source(_: CrateNum) -> Lrc<CrateSource> {
+        storage(ArenaCacheSelector<'tcx>)
         eval_always
         desc { "looking at the source for a crate" }
         separate_provide_extern
         desc { "optimization level used by backend" }
     }
 
-    query output_filenames(_: ()) -> Arc<OutputFilenames> {
+    /// Return the filenames where output artefacts shall be stored.
+    ///
+    /// This query returns an `&Arc` because codegen backends need the value even after the `TyCtxt`
+    /// has been destroyed.
+    query output_filenames(_: ()) -> &'tcx Arc<OutputFilenames> {
         eval_always
         desc { "output_filenames" }
     }
     /// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine,
     /// because the `ty::Ty`-based wfcheck is always run.
     query diagnostic_hir_wf_check(key: (ty::Predicate<'tcx>, traits::WellFormedLoc)) -> Option<traits::ObligationCause<'tcx>> {
+        storage(ArenaCacheSelector<'tcx>)
         eval_always
         no_hash
         desc { "performing HIR wf-checking for predicate {:?} at item {:?}", key.0, key.1 }
index 11dc69ab71566f2289391e5c4671532d3305903a..04bc0c8b52114dccded115a8b98fa0c9a1ac94f1 100644 (file)
@@ -17,6 +17,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_middle::infer::canonical::Canonical;
 use rustc_middle::middle::region;
+use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::mir::{
     BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
 };
@@ -368,12 +369,12 @@ pub enum ExprKind<'tcx> {
     },
     /// An inline `const` block, e.g. `const {}`.
     ConstBlock {
-        value: &'tcx Const<'tcx>,
+        value: Const<'tcx>,
     },
     /// An array literal constructed from one repeated element, e.g. `[1; 5]`.
     Repeat {
         value: ExprId,
-        count: &'tcx Const<'tcx>,
+        count: Const<'tcx>,
     },
     /// An array, e.g. `[a, b, c, d]`.
     Array {
@@ -407,7 +408,7 @@ pub enum ExprKind<'tcx> {
     },
     /// A literal.
     Literal {
-        literal: &'tcx Const<'tcx>,
+        literal: Const<'tcx>,
         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
         /// The `DefId` of the `const` item this literal
         /// was produced from, if this is not a user-written
@@ -419,7 +420,8 @@ pub enum ExprKind<'tcx> {
     /// This is only distinguished from `Literal` so that we can register some
     /// info for diagnostics.
     StaticRef {
-        literal: &'tcx Const<'tcx>,
+        alloc_id: AllocId,
+        ty: Ty<'tcx>,
         def_id: DefId,
     },
     /// Inline assembly, i.e. `asm!()`.
@@ -501,7 +503,7 @@ pub enum InlineAsmOperand<'tcx> {
         out_expr: Option<ExprId>,
     },
     Const {
-        value: &'tcx Const<'tcx>,
+        value: Const<'tcx>,
         span: Span,
     },
     SymFn {
@@ -640,7 +642,7 @@ pub enum PatKind<'tcx> {
     /// * Opaque constants, that must not be matched structurally. So anything that does not derive
     ///   `PartialEq` and `Eq`.
     Constant {
-        value: &'tcx ty::Const<'tcx>,
+        value: ty::Const<'tcx>,
     },
 
     Range(PatRange<'tcx>),
@@ -670,8 +672,8 @@ pub enum PatKind<'tcx> {
 
 #[derive(Copy, Clone, Debug, PartialEq, HashStable)]
 pub struct PatRange<'tcx> {
-    pub lo: &'tcx ty::Const<'tcx>,
-    pub hi: &'tcx ty::Const<'tcx>,
+    pub lo: ty::Const<'tcx>,
+    pub hi: ty::Const<'tcx>,
     pub end: RangeEnd,
 }
 
index f80beadd6e5515e40d9f956d63301432ecb88782..e3d004ed133e100e8ada645c6e1a60934a3f6de3 100644 (file)
@@ -22,7 +22,7 @@ pub enum CastKind {
 /// A node of an `AbstractConst`.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 pub enum Node<'tcx> {
-    Leaf(&'tcx ty::Const<'tcx>),
+    Leaf(ty::Const<'tcx>),
     Binop(mir::BinOp, NodeId, NodeId),
     UnaryOp(mir::UnOp, NodeId),
     FunctionCall(NodeId, &'tcx [NodeId]),
index 9f9947341c5c1a6079fa9cad8dc83d3ec908e6e3..b3e2cb132a273b90d9984f7c61a9a3fdbab73386 100644 (file)
@@ -26,7 +26,7 @@ fn visit_pat(&mut self, pat: &Pat<'tcx>) {
         walk_pat(self, pat);
     }
 
-    fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {}
+    fn visit_const(&mut self, _cnst: Const<'tcx>) {}
 }
 
 pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
@@ -123,7 +123,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
         }
         Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
         Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
-        StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
+        StaticRef { .. } => {}
         InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
             for op in &**operands {
                 use InlineAsmOperand::*;
@@ -209,7 +209,7 @@ pub fn walk_pat<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, pat: &Pat<'
                 visitor.visit_pat(&subpattern.pattern);
             }
         }
-        Constant { value } => visitor.visit_const(value),
+        Constant { value } => visitor.visit_const(*value),
         Range(range) => {
             visitor.visit_const(range.lo);
             visitor.visit_const(range.hi);
index 1123cab807651b29a4024f5b86c31c3bb01697d1..b54418e5201715797757fb8253ddbafdb6149b40 100644 (file)
@@ -285,6 +285,12 @@ pub enum ObligationCauseCode<'tcx> {
         trait_item_def_id: DefId,
     },
 
+    /// Checking that the bounds of a trait's associated type hold for a given impl
+    CheckAssociatedTypeBounds {
+        impl_item_def_id: DefId,
+        trait_item_def_id: DefId,
+    },
+
     /// Checking that this expression can be assigned where it needs to be
     // FIXME(eddyb) #11161 is the original Expr required?
     ExprAssignable,
index cb35a4005f8c29accb8d6a4264fea71468b71010..07cfe83b0143867fc6dd07b7fb8abc6dd2c6a1ec 100644 (file)
@@ -11,7 +11,6 @@
 use crate::ty::{self, Ty, TyCtxt};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_span::source_map::Span;
@@ -97,7 +96,7 @@ pub fn new(value: T) -> Self {
 pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
     Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>;
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Copy, Clone, Debug, HashStable)]
 pub struct NoSolution;
 
 pub type Fallible<T> = Result<T, NoSolution>;
@@ -191,12 +190,12 @@ pub struct CandidateStep<'tcx> {
     pub unsize: bool,
 }
 
-#[derive(Clone, Debug, HashStable)]
+#[derive(Copy, Clone, Debug, HashStable)]
 pub struct MethodAutoderefStepsResult<'tcx> {
     /// The valid autoderef steps that could be find.
-    pub steps: Lrc<Vec<CandidateStep<'tcx>>>,
+    pub steps: &'tcx [CandidateStep<'tcx>],
     /// If Some(T), a type autoderef reported an error on.
-    pub opt_bad_ty: Option<Lrc<MethodAutoderefBadTy<'tcx>>>,
+    pub opt_bad_ty: Option<&'tcx MethodAutoderefBadTy<'tcx>>,
     /// If `true`, `steps` has been truncated due to reaching the
     /// recursion limit.
     pub reached_recursion_limit: bool,
index e0e3febe6b3109b0c23cefe3b98f3cccffc95ca0..738c48dbb5c59c6a336e36a84ddfeea9aaa7c1dc 100644 (file)
@@ -77,7 +77,7 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
             ) => Ok(a),
 
             (&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
-                Err(TypeError::Sorts(relate::expected_found(self, &a, &b)))
+                Err(TypeError::Sorts(relate::expected_found(self, a, b)))
             }
 
             (&ty::Error(_), _) | (_, &ty::Error(_)) => Ok(self.tcx().ty_error()),
@@ -88,21 +88,21 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
 
     fn consts(
         &mut self,
-        a: &'tcx ty::Const<'tcx>,
-        b: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         debug!("{}.consts({:?}, {:?})", self.tag(), a, b);
         if a == b {
             return Ok(a);
         }
 
-        match (a.val, b.val) {
+        match (a.val(), b.val()) {
             (_, ty::ConstKind::Infer(InferConst::Fresh(_))) => {
                 return Ok(a);
             }
 
             (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
-                return Err(TypeError::ConstMismatch(relate::expected_found(self, &a, &b)));
+                return Err(TypeError::ConstMismatch(relate::expected_found(self, a, b)));
             }
 
             _ => {}
index 6cec75d36e2c2f2063ff543c34dce6f9aca9b178..40fbea7c3d91fc7e643799b48c03347dae2fba31 100644 (file)
@@ -26,7 +26,7 @@
     Destructor, FieldDef, GenericPredicates, ReprOptions, Ty, TyCtxt, VariantDef, VariantDiscr,
 };
 
-#[derive(Clone, HashStable, Debug)]
+#[derive(Copy, Clone, HashStable, Debug)]
 pub struct AdtSizedConstraint<'tcx>(pub &'tcx [Ty<'tcx>]);
 
 bitflags! {
@@ -395,7 +395,7 @@ pub fn variant_of_res(&self, res: Res) -> &VariantDef {
             | Res::Def(DefKind::Union, _)
             | Res::Def(DefKind::TyAlias, _)
             | Res::Def(DefKind::AssocTy, _)
-            | Res::SelfTy(..)
+            | Res::SelfTy { .. }
             | Res::SelfCtor(..) => self.non_enum_variant(),
             _ => bug!("unexpected res {:?} in variant_of_res", res),
         }
index c23d4eae1a400eac98a716bedca65c160bc6fcb7..49f846562a3cc5cf8fdab2e1150bd3f5f21652f9 100644 (file)
@@ -160,12 +160,11 @@ pub fn find_by_name_and_kinds(
         &self,
         tcx: TyCtxt<'_>,
         ident: Ident,
+        // Sorted in order of what kinds to look at
         kinds: &[AssocKind],
         parent_def_id: DefId,
     ) -> Option<&ty::AssocItem> {
-        self.filter_by_name_unhygienic(ident.name)
-            .filter(|item| kinds.contains(&item.kind))
-            .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
+        kinds.iter().find_map(|kind| self.find_by_name_and_kind(tcx, ident, *kind, parent_def_id))
     }
 
     /// Returns the associated item with the given name in the given `Namespace`, if one exists.
index 0ac2ea4db5e77c38cfc53e2dbf7bbf0d1c42d817..8ba6c1f67c94cc79046ec17e7005d1995081b4b5 100644 (file)
@@ -116,7 +116,7 @@ pub fn extends(self, other: ty::ClosureKind) -> bool {
     }
 
     /// Returns the representative scalar type for this closure kind.
-    /// See `TyS::to_opt_closure_kind` for more details.
+    /// See `Ty::to_opt_closure_kind` for more details.
     pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match self {
             ty::ClosureKind::Fn => tcx.types.i8,
index 65b91eedf8a27e066998e779c373b69d6c6d8990..ecd30ba441ff4c6afd892603087f4039c8ffb2f2 100644 (file)
@@ -13,6 +13,7 @@
     interpret::{AllocId, Allocation},
 };
 use crate::thir;
+use crate::traits;
 use crate::ty::subst::SubstsRef;
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
@@ -137,6 +138,18 @@ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
     }
 }
 
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Region<'tcx> {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+        self.kind().encode(e)
+    }
+}
+
+impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for ty::Const<'tcx> {
+    fn encode(&self, e: &mut E) -> Result<(), E::Error> {
+        self.0.0.encode(e)
+    }
+}
+
 impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for AllocId {
     fn encode(&self, e: &mut E) -> Result<(), E::Error> {
         e.encode_alloc_id(self)
@@ -155,7 +168,7 @@ fn encode(&self, e: &mut E) -> Result<(), E::Error> {
 
 encodable_via_deref! {
     &'tcx ty::TypeckResults<'tcx>,
-    ty::Region<'tcx>,
+    &'tcx traits::ImplSource<'tcx, ()>,
     &'tcx mir::Body<'tcx>,
     &'tcx mir::UnsafetyCheckResult,
     &'tcx mir::BorrowCheckResult<'tcx>,
@@ -328,8 +341,8 @@ fn decode(decoder: &mut D) -> &'tcx Self {
     }
 }
 
-impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::Const<'tcx> {
-    fn decode(decoder: &mut D) -> &'tcx Self {
+impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Const<'tcx> {
+    fn decode(decoder: &mut D) -> Self {
         decoder.tcx().mk_const(Decodable::decode(decoder))
     }
 }
@@ -385,6 +398,7 @@ fn decode(decoder: &mut D) -> &'tcx Self {
     &'tcx ty::TypeckResults<'tcx>,
     &'tcx ty::List<Ty<'tcx>>,
     &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+    &'tcx traits::ImplSource<'tcx, ()>,
     &'tcx Allocation,
     &'tcx mir::Body<'tcx>,
     &'tcx mir::UnsafetyCheckResult,
index 19a73732fcac3aaba32925a705fb4b9dd471385c..a794a8c0e0874f3c5c0b4e8b7a340a2509e72782 100644 (file)
@@ -4,10 +4,12 @@
     self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
     TyCtxt, TypeFoldable,
 };
+use rustc_data_structures::intern::Interned;
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::HashStable;
+use std::fmt;
 
 mod int;
 mod kind;
 pub use kind::*;
 pub use valtree::*;
 
+/// Use this rather than `ConstS`, whenever possible.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Const<'tcx>(pub Interned<'tcx, ConstS<'tcx>>);
+
+impl<'tcx> fmt::Debug for Const<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // This reflects what `Const` looked liked before `Interned` was
+        // introduced. We print it like this to avoid having to update expected
+        // output in a lot of tests.
+        write!(f, "Const {{ ty: {:?}, val: {:?} }}", self.ty(), self.val())
+    }
+}
+
 /// Typed constant value.
-#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
-#[derive(HashStable)]
-pub struct Const<'tcx> {
+#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
+pub struct ConstS<'tcx> {
     pub ty: Ty<'tcx>,
-
     pub val: ConstKind<'tcx>,
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(Const<'_>, 48);
+static_assert_size!(ConstS<'_>, 48);
 
 impl<'tcx> Const<'tcx> {
+    pub fn ty(self) -> Ty<'tcx> {
+        self.0.ty
+    }
+
+    pub fn val(self) -> ConstKind<'tcx> {
+        self.0.val
+    }
+
     /// Literals and const generic parameters are eagerly converted to a constant, everything else
     /// becomes `Unevaluated`.
-    pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+    pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
         Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id))
     }
 
@@ -40,7 +62,7 @@ pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
     pub fn from_opt_const_arg_anon_const(
         tcx: TyCtxt<'tcx>,
         def: ty::WithOptConstParam<LocalDefId>,
-    ) -> &'tcx Self {
+    ) -> Self {
         debug!("Const::from_anon_const(def={:?})", def);
 
         let body_id = match tcx.hir().get_by_def_id(def.did) {
@@ -58,7 +80,7 @@ pub fn from_opt_const_arg_anon_const(
 
         match Self::try_eval_lit_or_param(tcx, ty, expr) {
             Some(v) => v,
-            None => tcx.mk_const(ty::Const {
+            None => tcx.mk_const(ty::ConstS {
                 val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                     def: def.to_global(),
                     substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
@@ -74,7 +96,7 @@ fn try_eval_lit_or_param(
         tcx: TyCtxt<'tcx>,
         ty: Ty<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
-    ) -> Option<&'tcx Self> {
+    ) -> Option<Self> {
         // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
         // currently have to be wrapped in curly brackets, so it's necessary to special-case.
         let expr = match &expr.kind {
@@ -120,7 +142,7 @@ fn try_eval_lit_or_param(
                 let generics = tcx.generics_of(item_def_id.to_def_id());
                 let index = generics.param_def_id_to_index[&def_id];
                 let name = tcx.hir().name(hir_id);
-                Some(tcx.mk_const(ty::Const {
+                Some(tcx.mk_const(ty::ConstS {
                     val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
                     ty,
                 }))
@@ -129,7 +151,7 @@ fn try_eval_lit_or_param(
         }
     }
 
-    pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
+    pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
         debug!("Const::from_inline_const(def_id={:?})", def_id);
 
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
@@ -155,7 +177,7 @@ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
                 let substs =
                     InlineConstSubsts::new(tcx, InlineConstSubstsParts { parent_substs, ty })
                         .substs;
-                tcx.mk_const(ty::Const {
+                tcx.mk_const(ty::ConstS {
                     val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                         def: ty::WithOptConstParam::unknown(def_id).to_global(),
                         substs,
@@ -171,19 +193,19 @@ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
 
     /// Interns the given value as a constant.
     #[inline]
-    pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
-        tcx.mk_const(Self { val: ConstKind::Value(val), ty })
+    pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self {
+        tcx.mk_const(ConstS { val: ConstKind::Value(val), ty })
     }
 
     #[inline]
     /// Interns the given scalar as a constant.
-    pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> &'tcx Self {
+    pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> Self {
         Self::from_value(tcx, ConstValue::Scalar(val), ty)
     }
 
     #[inline]
     /// Creates a constant with the given integer value and interns it.
-    pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> &'tcx Self {
+    pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>) -> Self {
         let size = tcx
             .layout_of(ty)
             .unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
@@ -193,19 +215,19 @@ pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>)
 
     #[inline]
     /// Creates an interned zst constant.
-    pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
+    pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
         Self::from_scalar(tcx, Scalar::ZST, ty)
     }
 
     #[inline]
     /// Creates an interned bool constant.
-    pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> &'tcx Self {
+    pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
         Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool))
     }
 
     #[inline]
     /// Creates an interned usize constant.
-    pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> &'tcx Self {
+    pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
         Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize))
     }
 
@@ -214,35 +236,35 @@ pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> &'tcx Self {
     /// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
     /// contains const generic parameters or pointers).
     pub fn try_eval_bits(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         param_env: ParamEnv<'tcx>,
         ty: Ty<'tcx>,
     ) -> Option<u128> {
-        assert_eq!(self.ty, ty);
+        assert_eq!(self.ty(), ty);
         let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
         // if `ty` does not depend on generic parameters, use an empty param_env
-        self.val.eval(tcx, param_env).try_to_bits(size)
+        self.val().eval(tcx, param_env).try_to_bits(size)
     }
 
     #[inline]
-    pub fn try_eval_bool(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
-        self.val.eval(tcx, param_env).try_to_bool()
+    pub fn try_eval_bool(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<bool> {
+        self.val().eval(tcx, param_env).try_to_bool()
     }
 
     #[inline]
-    pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> {
-        self.val.eval(tcx, param_env).try_to_machine_usize(tcx)
+    pub fn try_eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u64> {
+        self.val().eval(tcx, param_env).try_to_machine_usize(tcx)
     }
 
     #[inline]
     /// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
     /// unevaluated constant.
-    pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx> {
-        if let Some(val) = self.val.try_eval(tcx, param_env) {
+    pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
+        if let Some(val) = self.val().try_eval(tcx, param_env) {
             match val {
-                Ok(val) => Const::from_value(tcx, val, self.ty),
-                Err(ErrorReported) => tcx.const_error(self.ty),
+                Ok(val) => Const::from_value(tcx, val, self.ty()),
+                Err(ErrorReported) => tcx.const_error(self.ty()),
             }
         } else {
             self
@@ -251,20 +273,20 @@ pub fn eval(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> &Const<'tcx>
 
     #[inline]
     /// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
-    pub fn eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
+    pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
         self.try_eval_bits(tcx, param_env, ty)
             .unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
     }
 
     #[inline]
     /// Panics if the value cannot be evaluated or doesn't contain a valid `usize`.
-    pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
+    pub fn eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
         self.try_eval_usize(tcx, param_env)
             .unwrap_or_else(|| bug!("expected usize, got {:#?}", self))
     }
 }
 
-pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Const<'tcx> {
+pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Const<'tcx> {
     let default_def_id = match tcx.hir().get_by_def_id(def_id.expect_local()) {
         hir::Node::GenericParam(hir::GenericParam {
             kind: hir::GenericParamKind::Const { ty: _, default: Some(ac) },
index 5dae4b9e4c9712808aeab34febf4ad5b90ea1abb..41145d250173fe479b3b4afc80071e9d74f21358 100644 (file)
@@ -5,10 +5,12 @@
 use crate::hir::place::Place as HirPlace;
 use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
 use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
-use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetimeDefault};
+use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
 use crate::middle::stability;
 use crate::mir::interpret::{self, Allocation, ConstValue, Scalar};
-use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted};
+use crate::mir::{
+    Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
+};
 use crate::thir::Thir;
 use crate::traits;
 use crate::ty::query::{self, TyCtxtAt};
 use crate::ty::TyKind::*;
 use crate::ty::{
     self, AdtDef, AdtKind, Binder, BindingMode, BoundVar, CanonicalPolyFnSig,
-    ClosureSizeProfileData, Const, ConstVid, DefIdTree, ExistentialPredicate, FloatTy, FloatVar,
-    FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List, ParamConst,
-    ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind, ProjectionTy, Region, RegionKind,
-    ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy,
+    ClosureSizeProfileData, Const, ConstS, ConstVid, DefIdTree, ExistentialPredicate, FloatTy,
+    FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy, IntTy, IntVar, IntVid, List,
+    ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, PredicateS, ProjectionTy, Region,
+    RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut, UintTy,
 };
 use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::intern::Interned;
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
@@ -89,7 +92,7 @@ fn new_empty(source_map: &'tcx SourceMap) -> Self
 #[derive(TyEncodable, TyDecodable, HashStable)]
 pub struct DelaySpanBugEmitted(());
 
-type InternedSet<'tcx, T> = ShardedHashMap<Interned<'tcx, T>, ()>;
+type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
 
 pub struct CtxtInterners<'tcx> {
     /// The arena that types, regions, etc. are allocated from.
@@ -104,11 +107,11 @@ pub struct CtxtInterners<'tcx> {
     region: InternedSet<'tcx, RegionKind>,
     poly_existential_predicates:
         InternedSet<'tcx, List<ty::Binder<'tcx, ExistentialPredicate<'tcx>>>>,
-    predicate: InternedSet<'tcx, PredicateInner<'tcx>>,
+    predicate: InternedSet<'tcx, PredicateS<'tcx>>,
     predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
     projs: InternedSet<'tcx, List<ProjectionKind>>,
     place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
-    const_: InternedSet<'tcx, Const<'tcx>>,
+    const_: InternedSet<'tcx, ConstS<'tcx>>,
     const_allocation: InternedSet<'tcx, Allocation>,
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
     layout: InternedSet<'tcx, Layout>,
@@ -149,39 +152,40 @@ fn new(arena: &'tcx WorkerLocal<Arena<'tcx>>) -> CtxtInterners<'tcx> {
     #[allow(rustc::usage_of_ty_tykind)]
     #[inline(never)]
     fn intern_ty(&self, kind: TyKind<'tcx>) -> Ty<'tcx> {
-        self.type_
-            .intern(kind, |kind| {
-                let flags = super::flags::FlagComputation::for_kind(&kind);
-
-                let ty_struct = TyS {
-                    kind,
-                    flags: flags.flags,
-                    outer_exclusive_binder: flags.outer_exclusive_binder,
-                };
+        Ty(Interned::new_unchecked(
+            self.type_
+                .intern(kind, |kind| {
+                    let flags = super::flags::FlagComputation::for_kind(&kind);
+
+                    let ty_struct = TyS {
+                        kind,
+                        flags: flags.flags,
+                        outer_exclusive_binder: flags.outer_exclusive_binder,
+                    };
 
-                Interned(self.arena.alloc(ty_struct))
-            })
-            .0
+                    InternedInSet(self.arena.alloc(ty_struct))
+                })
+                .0,
+        ))
     }
 
     #[inline(never)]
-    fn intern_predicate(
-        &self,
-        kind: Binder<'tcx, PredicateKind<'tcx>>,
-    ) -> &'tcx PredicateInner<'tcx> {
-        self.predicate
-            .intern(kind, |kind| {
-                let flags = super::flags::FlagComputation::for_predicate(kind);
-
-                let predicate_struct = PredicateInner {
-                    kind,
-                    flags: flags.flags,
-                    outer_exclusive_binder: flags.outer_exclusive_binder,
-                };
+    fn intern_predicate(&self, kind: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> {
+        Predicate(Interned::new_unchecked(
+            self.predicate
+                .intern(kind, |kind| {
+                    let flags = super::flags::FlagComputation::for_predicate(kind);
+
+                    let predicate_struct = PredicateS {
+                        kind,
+                        flags: flags.flags,
+                        outer_exclusive_binder: flags.outer_exclusive_binder,
+                    };
 
-                Interned(self.arena.alloc(predicate_struct))
-            })
-            .0
+                    InternedInSet(self.arena.alloc(predicate_struct))
+                })
+                .0,
+        ))
     }
 }
 
@@ -225,7 +229,7 @@ pub struct CommonLifetimes<'tcx> {
 }
 
 pub struct CommonConsts<'tcx> {
-    pub unit: &'tcx Const<'tcx>,
+    pub unit: Const<'tcx>,
 }
 
 pub struct LocalTableInContext<'a, V> {
@@ -856,16 +860,16 @@ pub fn is_identity(&self) -> bool {
                             _ => false,
                         },
 
-                        GenericArgKind::Lifetime(r) => match r {
+                        GenericArgKind::Lifetime(r) => match *r {
                             ty::ReLateBound(debruijn, br) => {
                                 // We only allow a `ty::INNERMOST` index in substitutions.
-                                assert_eq!(*debruijn, ty::INNERMOST);
+                                assert_eq!(debruijn, ty::INNERMOST);
                                 cvar == br.var
                             }
                             _ => false,
                         },
 
-                        GenericArgKind::Const(ct) => match ct.val {
+                        GenericArgKind::Const(ct) => match ct.val() {
                             ty::ConstKind::Bound(debruijn, b) => {
                                 // We only allow a `ty::INNERMOST` index in substitutions.
                                 assert_eq!(debruijn, ty::INNERMOST);
@@ -926,22 +930,30 @@ fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
 
 impl<'tcx> CommonLifetimes<'tcx> {
     fn new(interners: &CtxtInterners<'tcx>) -> CommonLifetimes<'tcx> {
-        let mk = |r| interners.region.intern(r, |r| Interned(interners.arena.alloc(r))).0;
+        let mk = |r| {
+            Region(Interned::new_unchecked(
+                interners.region.intern(r, |r| InternedInSet(interners.arena.alloc(r))).0,
+            ))
+        };
 
         CommonLifetimes {
-            re_root_empty: mk(RegionKind::ReEmpty(ty::UniverseIndex::ROOT)),
-            re_static: mk(RegionKind::ReStatic),
-            re_erased: mk(RegionKind::ReErased),
+            re_root_empty: mk(ty::ReEmpty(ty::UniverseIndex::ROOT)),
+            re_static: mk(ty::ReStatic),
+            re_erased: mk(ty::ReErased),
         }
     }
 }
 
 impl<'tcx> CommonConsts<'tcx> {
     fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonConsts<'tcx> {
-        let mk_const = |c| interners.const_.intern(c, |c| Interned(interners.arena.alloc(c))).0;
+        let mk_const = |c| {
+            Const(Interned::new_unchecked(
+                interners.const_.intern(c, |c| InternedInSet(interners.arena.alloc(c))).0,
+            ))
+        };
 
         CommonConsts {
-            unit: mk_const(ty::Const {
+            unit: mk_const(ty::ConstS {
                 val: ty::ConstKind::Value(ConstValue::Scalar(Scalar::ZST)),
                 ty: types.unit,
             }),
@@ -1061,6 +1073,17 @@ pub fn typeck_opt_const_arg(
         }
     }
 
+    pub fn mir_borrowck_opt_const_arg(
+        self,
+        def: ty::WithOptConstParam<LocalDefId>,
+    ) -> &'tcx BorrowCheckResult<'tcx> {
+        if let Some(param_did) = def.const_param_did {
+            self.mir_borrowck_const_arg((def.did, param_did))
+        } else {
+            self.mir_borrowck(def.did)
+        }
+    }
+
     pub fn alloc_steal_thir(self, thir: Thir<'tcx>) -> &'tcx Steal<Thir<'tcx>> {
         self.arena.alloc(Steal::new(thir))
     }
@@ -1202,7 +1225,7 @@ pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty
 
     /// Like [TyCtxt::ty_error] but for constants.
     #[track_caller]
-    pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
+    pub fn const_error(self, ty: Ty<'tcx>) -> Const<'tcx> {
         self.const_error_with_message(
             ty,
             DUMMY_SP,
@@ -1217,9 +1240,9 @@ pub fn const_error_with_message<S: Into<MultiSpan>>(
         ty: Ty<'tcx>,
         span: S,
         msg: &str,
-    ) -> &'tcx Const<'tcx> {
+    ) -> Const<'tcx> {
         self.sess.delay_span_bug(span, msg);
-        self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty })
+        self.mk_const(ty::ConstS { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty })
     }
 
     pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool {
@@ -1614,12 +1637,28 @@ pub trait Lift<'tcx>: fmt::Debug {
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted>;
 }
 
+// Deprecated: we are in the process of converting all uses to `nop_lift`.
+macro_rules! nop_lift_old {
+    ($set:ident; $ty:ty => $lifted:ty) => {
+        impl<'a, 'tcx> Lift<'tcx> for $ty {
+            type Lifted = $lifted;
+            fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+                if tcx.interners.$set.contains_pointer_to(&InternedInSet(self)) {
+                    Some(unsafe { mem::transmute(self) })
+                } else {
+                    None
+                }
+            }
+        }
+    };
+}
+
 macro_rules! nop_lift {
     ($set:ident; $ty:ty => $lifted:ty) => {
         impl<'a, 'tcx> Lift<'tcx> for $ty {
             type Lifted = $lifted;
             fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-                if tcx.interners.$set.contains_pointer_to(&Interned(self)) {
+                if tcx.interners.$set.contains_pointer_to(&InternedInSet(self.0.0)) {
                     Some(unsafe { mem::transmute(self) })
                 } else {
                     None
@@ -1637,7 +1676,7 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
                 if self.is_empty() {
                     return Some(List::empty());
                 }
-                if tcx.interners.$set.contains_pointer_to(&Interned(self)) {
+                if tcx.interners.$set.contains_pointer_to(&InternedInSet(self)) {
                     Some(unsafe { mem::transmute(self) })
                 } else {
                     None
@@ -1649,9 +1688,9 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
 
 nop_lift! {type_; Ty<'a> => Ty<'tcx>}
 nop_lift! {region; Region<'a> => Region<'tcx>}
-nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
-nop_lift! {const_allocation; &'a Allocation => &'tcx Allocation}
-nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>}
+nop_lift! {const_; Const<'a> => Const<'tcx>}
+nop_lift_old! {const_allocation; &'a Allocation => &'tcx Allocation}
+nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
 
 nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>}
 nop_list_lift! {poly_existential_predicates; ty::Binder<'a, ExistentialPredicate<'a>> => ty::Binder<'tcx, ExistentialPredicate<'tcx>>}
@@ -1668,7 +1707,7 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
 pub mod tls {
     use super::{ptr_eq, GlobalCtxt, TyCtxt};
 
-    use crate::dep_graph::{DepKind, TaskDepsRef};
+    use crate::dep_graph::TaskDepsRef;
     use crate::ty::query;
     use rustc_data_structures::sync::{self, Lock};
     use rustc_data_structures::thin_vec::ThinVec;
@@ -1693,7 +1732,7 @@ pub struct ImplicitCtxt<'a, 'tcx> {
 
         /// The current query job, if any. This is updated by `JobOwner::start` in
         /// `ty::query::plumbing` when executing a query.
-        pub query: Option<query::QueryJobId<DepKind>>,
+        pub query: Option<query::QueryJobId>,
 
         /// Where to store diagnostics for the current query job, if any.
         /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
@@ -1844,7 +1883,7 @@ macro_rules! sty_debug_print {
         #[allow(non_snake_case)]
         mod inner {
             use crate::ty::{self, TyCtxt};
-            use crate::ty::context::Interned;
+            use crate::ty::context::InternedInSet;
 
             #[derive(Copy, Clone)]
             struct DebugStat {
@@ -1867,16 +1906,16 @@ pub fn go(fmt: &mut std::fmt::Formatter<'_>, tcx: TyCtxt<'_>) -> std::fmt::Resul
 
                 let shards = tcx.interners.type_.lock_shards();
                 let types = shards.iter().flat_map(|shard| shard.keys());
-                for &Interned(t) in types {
-                    let variant = match t.kind() {
+                for &InternedInSet(t) in types {
+                    let variant = match t.kind {
                         ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) |
                             ty::Float(..) | ty::Str | ty::Never => continue,
                         ty::Error(_) => /* unimportant */ continue,
                         $(ty::$variant(..) => &mut $variant,)*
                     };
-                    let lt = t.flags().intersects(ty::TypeFlags::HAS_RE_INFER);
-                    let ty = t.flags().intersects(ty::TypeFlags::HAS_TY_INFER);
-                    let ct = t.flags().intersects(ty::TypeFlags::HAS_CT_INFER);
+                    let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER);
+                    let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER);
+                    let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER);
 
                     variant.total += 1;
                     total.total += 1;
@@ -1967,86 +2006,86 @@ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 // this type just holds a pointer to it, but it still effectively owns it. It
 // impls `Borrow` so that it can be looked up using the original
 // (non-arena-memory-owning) types.
-struct Interned<'tcx, T: ?Sized>(&'tcx T);
+struct InternedInSet<'tcx, T: ?Sized>(&'tcx T);
 
-impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> {
+impl<'tcx, T: 'tcx + ?Sized> Clone for InternedInSet<'tcx, T> {
     fn clone(&self) -> Self {
-        Interned(self.0)
+        InternedInSet(self.0)
     }
 }
 
-impl<'tcx, T: 'tcx + ?Sized> Copy for Interned<'tcx, T> {}
+impl<'tcx, T: 'tcx + ?Sized> Copy for InternedInSet<'tcx, T> {}
 
-impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> {
+impl<'tcx, T: 'tcx + ?Sized> IntoPointer for InternedInSet<'tcx, T> {
     fn into_pointer(&self) -> *const () {
         self.0 as *const _ as *const ()
     }
 }
 
 #[allow(rustc::usage_of_ty_tykind)]
-impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
+impl<'tcx> Borrow<TyKind<'tcx>> for InternedInSet<'tcx, TyS<'tcx>> {
     fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
-        &self.0.kind()
+        &self.0.kind
     }
 }
 
-impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> {
-    fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool {
+impl<'tcx> PartialEq for InternedInSet<'tcx, TyS<'tcx>> {
+    fn eq(&self, other: &InternedInSet<'tcx, TyS<'tcx>>) -> bool {
         // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
         // `x == y`.
-        self.0.kind() == other.0.kind()
+        self.0.kind == other.0.kind
     }
 }
 
-impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {}
+impl<'tcx> Eq for InternedInSet<'tcx, TyS<'tcx>> {}
 
-impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> {
+impl<'tcx> Hash for InternedInSet<'tcx, TyS<'tcx>> {
     fn hash<H: Hasher>(&self, s: &mut H) {
         // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
-        self.0.kind().hash(s)
+        self.0.kind.hash(s)
     }
 }
 
-impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
+impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for InternedInSet<'tcx, PredicateS<'tcx>> {
     fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
         &self.0.kind
     }
 }
 
-impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> {
-    fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool {
+impl<'tcx> PartialEq for InternedInSet<'tcx, PredicateS<'tcx>> {
+    fn eq(&self, other: &InternedInSet<'tcx, PredicateS<'tcx>>) -> bool {
         // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
         // `x == y`.
         self.0.kind == other.0.kind
     }
 }
 
-impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {}
+impl<'tcx> Eq for InternedInSet<'tcx, PredicateS<'tcx>> {}
 
-impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> {
+impl<'tcx> Hash for InternedInSet<'tcx, PredicateS<'tcx>> {
     fn hash<H: Hasher>(&self, s: &mut H) {
         // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
         self.0.kind.hash(s)
     }
 }
 
-impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
+impl<'tcx, T> Borrow<[T]> for InternedInSet<'tcx, List<T>> {
     fn borrow<'a>(&'a self) -> &'a [T] {
         &self.0[..]
     }
 }
 
-impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> {
-    fn eq(&self, other: &Interned<'tcx, List<T>>) -> bool {
+impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, List<T>> {
+    fn eq(&self, other: &InternedInSet<'tcx, List<T>>) -> bool {
         // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
         // `x == y`.
         self.0[..] == other.0[..]
     }
 }
 
-impl<'tcx, T: Eq> Eq for Interned<'tcx, List<T>> {}
+impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, List<T>> {}
 
-impl<'tcx, T: Hash> Hash for Interned<'tcx, List<T>> {
+impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, List<T>> {
     fn hash<H: Hasher>(&self, s: &mut H) {
         // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
         self.0[..].hash(s)
@@ -2054,14 +2093,55 @@ fn hash<H: Hasher>(&self, s: &mut H) {
 }
 
 macro_rules! direct_interners {
+    ($($name:ident: $method:ident($ty:ty): $ret_ctor:ident -> $ret_ty:ty,)+) => {
+        $(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> {
+            fn borrow<'a>(&'a self) -> &'a $ty {
+                &self.0
+            }
+        }
+
+        impl<'tcx> PartialEq for InternedInSet<'tcx, $ty> {
+            fn eq(&self, other: &Self) -> bool {
+                // The `Borrow` trait requires that `x.borrow() == y.borrow()`
+                // equals `x == y`.
+                self.0 == other.0
+            }
+        }
+
+        impl<'tcx> Eq for InternedInSet<'tcx, $ty> {}
+
+        impl<'tcx> Hash for InternedInSet<'tcx, $ty> {
+            fn hash<H: Hasher>(&self, s: &mut H) {
+                // The `Borrow` trait requires that `x.borrow().hash(s) ==
+                // x.hash(s)`.
+                self.0.hash(s)
+            }
+        }
+
+        impl<'tcx> TyCtxt<'tcx> {
+            pub fn $method(self, v: $ty) -> $ret_ty {
+                $ret_ctor(Interned::new_unchecked(self.interners.$name.intern(v, |v| {
+                    InternedInSet(self.interners.arena.alloc(v))
+                }).0))
+            }
+        })+
+    }
+}
+
+direct_interners! {
+    region: mk_region(RegionKind): Region -> Region<'tcx>,
+    const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>,
+}
+
+macro_rules! direct_interners_old {
     ($($name:ident: $method:ident($ty:ty),)+) => {
-        $(impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
+        $(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> {
             fn borrow<'a>(&'a self) -> &'a $ty {
                 &self.0
             }
         }
 
-        impl<'tcx> PartialEq for Interned<'tcx, $ty> {
+        impl<'tcx> PartialEq for InternedInSet<'tcx, $ty> {
             fn eq(&self, other: &Self) -> bool {
                 // The `Borrow` trait requires that `x.borrow() == y.borrow()`
                 // equals `x == y`.
@@ -2069,9 +2149,9 @@ fn eq(&self, other: &Self) -> bool {
             }
         }
 
-        impl<'tcx> Eq for Interned<'tcx, $ty> {}
+        impl<'tcx> Eq for InternedInSet<'tcx, $ty> {}
 
-        impl<'tcx> Hash for Interned<'tcx, $ty> {
+        impl<'tcx> Hash for InternedInSet<'tcx, $ty> {
             fn hash<H: Hasher>(&self, s: &mut H) {
                 // The `Borrow` trait requires that `x.borrow().hash(s) ==
                 // x.hash(s)`.
@@ -2082,16 +2162,15 @@ fn hash<H: Hasher>(&self, s: &mut H) {
         impl<'tcx> TyCtxt<'tcx> {
             pub fn $method(self, v: $ty) -> &'tcx $ty {
                 self.interners.$name.intern(v, |v| {
-                    Interned(self.interners.arena.alloc(v))
+                    InternedInSet(self.interners.arena.alloc(v))
                 }).0
             }
         })+
     }
 }
 
-direct_interners! {
-    region: mk_region(RegionKind),
-    const_: mk_const(Const<'tcx>),
+// FIXME: eventually these should all be converted to `direct_interners`.
+direct_interners_old! {
     const_allocation: intern_const_alloc(Allocation),
     layout: intern_layout(Layout),
     adt_def: intern_adt_def(AdtDef),
@@ -2104,7 +2183,7 @@ macro_rules! slice_interners {
         impl<'tcx> TyCtxt<'tcx> {
             $(pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> {
                 self.interners.$field.intern_ref(v, || {
-                    Interned(List::from_arena(&*self.arena, v))
+                    InternedInSet(List::from_arena(&*self.arena, v))
                 }).0
             })+
         }
@@ -2204,8 +2283,7 @@ pub fn mk_ty(self, st: TyKind<'tcx>) -> Ty<'tcx> {
 
     #[inline]
     pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> {
-        let inner = self.interners.intern_predicate(binder);
-        Predicate { inner }
+        self.interners.intern_predicate(binder)
     }
 
     #[inline]
@@ -2416,8 +2494,8 @@ pub fn mk_ty_var(self, v: TyVid) -> Ty<'tcx> {
     }
 
     #[inline]
-    pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
-        self.mk_const(ty::Const { val: ty::ConstKind::Infer(InferConst::Var(v)), ty })
+    pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
+        self.mk_const(ty::ConstS { val: ty::ConstKind::Infer(InferConst::Var(v)), ty })
     }
 
     #[inline]
@@ -2436,8 +2514,8 @@ pub fn mk_ty_infer(self, it: InferTy) -> Ty<'tcx> {
     }
 
     #[inline]
-    pub fn mk_const_infer(self, ic: InferConst<'tcx>, ty: Ty<'tcx>) -> &'tcx ty::Const<'tcx> {
-        self.mk_const(ty::Const { val: ty::ConstKind::Infer(ic), ty })
+    pub fn mk_const_infer(self, ic: InferConst<'tcx>, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+        self.mk_const(ty::ConstS { val: ty::ConstKind::Infer(ic), ty })
     }
 
     #[inline]
@@ -2446,8 +2524,8 @@ pub fn mk_ty_param(self, index: u32, name: Symbol) -> Ty<'tcx> {
     }
 
     #[inline]
-    pub fn mk_const_param(self, index: u32, name: Symbol, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
-        self.mk_const(ty::Const { val: ty::ConstKind::Param(ParamConst { index, name }), ty })
+    pub fn mk_const_param(self, index: u32, name: Symbol, ty: Ty<'tcx>) -> Const<'tcx> {
+        self.mk_const(ty::ConstS { val: ty::ConstKind::Param(ParamConst { index, name }), ty })
     }
 
     pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
@@ -2708,10 +2786,6 @@ pub fn is_late_bound(self, id: HirId) -> bool {
             .map_or(false, |(owner, set)| owner == id.owner && set.contains(&id.local_id))
     }
 
-    pub fn object_lifetime_defaults(self, id: HirId) -> Option<Vec<ObjectLifetimeDefault>> {
-        self.object_lifetime_defaults_map(id.owner)
-    }
-
     pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
         self.mk_bound_variable_kinds(
             self.late_bound_vars_map(id.owner)
@@ -2723,8 +2797,8 @@ pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
         )
     }
 
-    pub fn lifetime_scope(self, id: HirId) -> Option<LifetimeScopeForPath> {
-        self.lifetime_scope_map(id.owner).and_then(|mut map| map.remove(&id.local_id))
+    pub fn lifetime_scope(self, id: HirId) -> Option<&'tcx LifetimeScopeForPath> {
+        self.lifetime_scope_map(id.owner).as_ref().and_then(|map| map.get(&id.local_id))
     }
 
     /// Whether the `def_id` counts as const fn in the current crate, considering all active
@@ -2897,7 +2971,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
         |tcx, id| tcx.stability().local_deprecation_entry(id.expect_local());
     providers.extern_mod_stmt_cnum =
         |tcx, id| tcx.resolutions(()).extern_crate_map.get(&id).cloned();
-    providers.output_filenames = |tcx, ()| tcx.output_filenames.clone();
+    providers.output_filenames = |tcx, ()| &tcx.output_filenames;
     providers.features_query = |tcx, ()| tcx.sess.features_untracked();
     providers.is_panic_runtime = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
index d68c5514821a9b3904d57c1250501ea43093fb19..64b2edd2c3f392edf5e0d7af6b65b2404155e81f 100644 (file)
@@ -1,10 +1,10 @@
-//! Diagnostics related methods for `TyS`.
+//! Diagnostics related methods for `Ty`.
 
 use crate::ty::subst::{GenericArg, GenericArgKind};
 use crate::ty::TyKind::*;
 use crate::ty::{
     ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
-    ProjectionTy, Term, TyCtxt, TyS, TypeAndMut,
+    ProjectionTy, Term, Ty, TyCtxt, TypeAndMut,
 };
 
 use rustc_errors::{Applicability, DiagnosticBuilder};
@@ -13,9 +13,9 @@
 use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate};
 use rustc_span::Span;
 
-impl<'tcx> TyS<'tcx> {
-    /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive.
-    pub fn is_primitive_ty(&self) -> bool {
+impl<'tcx> Ty<'tcx> {
+    /// Similar to `Ty::is_primitive`, but also considers inferred numeric values to be primitive.
+    pub fn is_primitive_ty(self) -> bool {
         matches!(
             self.kind(),
             Bool | Char
@@ -34,7 +34,7 @@ pub fn is_primitive_ty(&self) -> bool {
 
     /// Whether the type is succinctly representable as a type instead of just referred to with a
     /// description in error messages. This is used in the main error message.
-    pub fn is_simple_ty(&self) -> bool {
+    pub fn is_simple_ty(self) -> bool {
         match self.kind() {
             Bool
             | Char
@@ -58,7 +58,7 @@ pub fn is_simple_ty(&self) -> bool {
     /// description in error messages. This is used in the primary span label. Beyond what
     /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to
     /// ADTs with no type arguments.
-    pub fn is_simple_text(&self) -> bool {
+    pub fn is_simple_text(self) -> bool {
         match self.kind() {
             Adt(_, substs) => substs.non_erasable_generics().next().is_none(),
             Ref(_, ty, _) => ty.is_simple_text(),
@@ -67,11 +67,11 @@ pub fn is_simple_text(&self) -> bool {
     }
 
     /// Whether the type can be safely suggested during error recovery.
-    pub fn is_suggestable(&self) -> bool {
+    pub fn is_suggestable(self) -> bool {
         fn generic_arg_is_suggestible(arg: GenericArg<'_>) -> bool {
             match arg.unpack() {
                 GenericArgKind::Type(ty) => ty.is_suggestable(),
-                GenericArgKind::Const(c) => const_is_suggestable(c.val),
+                GenericArgKind::Const(c) => const_is_suggestable(c.val()),
                 _ => true,
             }
         }
@@ -110,7 +110,7 @@ fn const_is_suggestable(kind: ConstKind<'_>) -> bool {
                 }) => {
                     let term_is_suggestable = match term {
                         Term::Ty(ty) => ty.is_suggestable(),
-                        Term::Const(c) => const_is_suggestable(c.val),
+                        Term::Const(c) => const_is_suggestable(c.val()),
                     };
                     term_is_suggestable && substs.iter().all(generic_arg_is_suggestible)
                 }
@@ -120,7 +120,7 @@ fn const_is_suggestable(kind: ConstKind<'_>) -> bool {
                 args.iter().all(generic_arg_is_suggestible)
             }
             Slice(ty) | RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => ty.is_suggestable(),
-            Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val),
+            Array(ty, c) => ty.is_suggestable() && const_is_suggestable(c.val()),
             _ => true,
         }
     }
index 5c4a4cdde25131fda76b141c83dfcc99cc3dcf2e..2ccfeba2b665d13a64ae5135ff52fe36907aa569 100644 (file)
@@ -60,13 +60,13 @@ pub enum TypeError<'tcx> {
     /// created a cycle (because it appears somewhere within that
     /// type).
     CyclicTy(Ty<'tcx>),
-    CyclicConst(&'tcx ty::Const<'tcx>),
+    CyclicConst(ty::Const<'tcx>),
     ProjectionMismatched(ExpectedFound<DefId>),
     ExistentialMismatch(
         ExpectedFound<&'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>>,
     ),
     ObjectUnsafeCoercion(DefId),
-    ConstMismatch(ExpectedFound<&'tcx ty::Const<'tcx>>),
+    ConstMismatch(ExpectedFound<ty::Const<'tcx>>),
 
     IntrinsicCast,
     /// Safe `#[target_feature]` functions are not assignable to safe function pointers.
@@ -239,8 +239,8 @@ pub fn must_include_note(&self) -> bool {
     }
 }
 
-impl<'tcx> ty::TyS<'tcx> {
-    pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
+impl<'tcx> Ty<'tcx> {
+    pub fn sort_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
         match *self.kind() {
             ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => {
                 format!("`{}`", self).into()
@@ -255,7 +255,7 @@ pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
                 }
 
                 let n = tcx.lift(n).unwrap();
-                if let ty::ConstKind::Value(v) = n.val {
+                if let ty::ConstKind::Value(v) = n.val() {
                     if let Some(n) = v.try_to_machine_usize(tcx) {
                         return format!("array of {} element{}", n, pluralize!(n)).into();
                     }
@@ -306,7 +306,7 @@ pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
         }
     }
 
-    pub fn prefix_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
+    pub fn prefix_string(self, tcx: TyCtxt<'_>) -> Cow<'static, str> {
         match *self.kind() {
             ty::Infer(_)
             | ty::Error(_)
index daf9156a15f347f047500450a608ca88dec54013..983057bff95d6f0abb14e414f85c0bfaedad7c44 100644 (file)
@@ -54,12 +54,6 @@ pub enum SimplifyParams {
     No,
 }
 
-#[derive(PartialEq, Eq, Debug, Clone, Copy)]
-pub enum StripReferences {
-    Yes,
-    No,
-}
-
 /// Tries to simplify a type by only returning the outermost injective¹ layer, if one exists.
 ///
 /// The idea is to get something simple that we can use to quickly decide if two types could unify,
@@ -73,8 +67,6 @@ pub enum StripReferences {
 /// When using `SimplifyParams::Yes`, we still return a simplified type for params and projections²,
 /// the reasoning for this can be seen at the places doing this.
 ///
-/// For diagnostics we strip references with `StripReferences::Yes`. This is currently the best
-/// way to skip some unhelpful suggestions.
 ///
 /// ¹ meaning that if two outermost layers are different, then the whole types are also different.
 /// ² FIXME(@lcnr): this seems like it can actually end up being unsound with the way it's used during
@@ -87,7 +79,6 @@ pub fn simplify_type(
     tcx: TyCtxt<'_>,
     ty: Ty<'_>,
     can_simplify_params: SimplifyParams,
-    strip_references: StripReferences,
 ) -> Option<SimplifiedType> {
     match *ty.kind() {
         ty::Bool => Some(BoolSimplifiedType),
@@ -106,16 +97,7 @@ pub fn simplify_type(
             }
             _ => Some(MarkerTraitObjectSimplifiedType),
         },
-        ty::Ref(_, ty, mutbl) => {
-            if strip_references == StripReferences::Yes {
-                // For diagnostics, when recommending similar impls we want to
-                // recommend impls even when there is a reference mismatch,
-                // so we treat &T and T equivalently in that case.
-                simplify_type(tcx, ty, can_simplify_params, strip_references)
-            } else {
-                Some(RefSimplifiedType(mutbl))
-            }
-        }
+        ty::Ref(_, _, mutbl) => Some(RefSimplifiedType(mutbl)),
         ty::FnDef(def_id, _) | ty::Closure(def_id, _) => Some(ClosureSimplifiedType(def_id)),
         ty::Generator(def_id, _, _) => Some(GeneratorSimplifiedType(def_id)),
         ty::GeneratorWitness(ref tys) => {
index f06a1b09cd82ab236553403b81ba572fd2d65dc6..948a48c082644b2deabc5732240e836df35c259c 100644 (file)
@@ -6,7 +6,7 @@
 pub struct FlagComputation {
     pub flags: TypeFlags,
 
-    // see `TyS::outer_exclusive_binder` for details
+    // see `Ty::outer_exclusive_binder` for details
     pub outer_exclusive_binder: ty::DebruijnIndex,
 }
 
@@ -28,7 +28,7 @@ pub fn for_predicate<'tcx>(binder: ty::Binder<'tcx, ty::PredicateKind<'_>>) -> F
         result
     }
 
-    pub fn for_const(c: &ty::Const<'_>) -> TypeFlags {
+    pub fn for_const(c: ty::Const<'_>) -> TypeFlags {
         let mut result = FlagComputation::new();
         result.add_const(c);
         result.flags
@@ -270,7 +270,7 @@ fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
 
     fn add_ty(&mut self, ty: Ty<'_>) {
         self.add_flags(ty.flags());
-        self.add_exclusive_binder(ty.outer_exclusive_binder);
+        self.add_exclusive_binder(ty.outer_exclusive_binder());
     }
 
     fn add_tys(&mut self, tys: &[Ty<'_>]) {
@@ -286,9 +286,9 @@ fn add_region(&mut self, r: ty::Region<'_>) {
         }
     }
 
-    fn add_const(&mut self, c: &ty::Const<'_>) {
-        self.add_ty(c.ty);
-        match c.val {
+    fn add_const(&mut self, c: ty::Const<'_>) {
+        self.add_ty(c.ty());
+        match c.val() {
             ty::ConstKind::Unevaluated(unevaluated) => self.add_unevaluated_const(unevaluated),
             ty::ConstKind::Infer(infer) => {
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
index 3133cdfdd7a7211222a0e9336aa4240a798e0121..4922d07ae1c5da22d649fddf7c546381db0ebfc8 100644 (file)
@@ -1,38 +1,56 @@
-//! Generalized type folding mechanism. The setup is a bit convoluted
-//! but allows for convenient usage. Let T be an instance of some
-//! "foldable type" (one which implements `TypeFoldable`) and F be an
-//! instance of a "folder" (a type which implements `TypeFolder`). Then
-//! the setup is intended to be:
+//! A generalized traversal mechanism for complex data structures that contain
+//! type information.
 //!
-//!     T.fold_with(F) --calls--> F.fold_T(T) --calls--> T.super_fold_with(F)
+//! There are two types of traversal.
+//! - Folding. This is a modifying traversal. It consumes the data structure,
+//!   producing a (possibly) modified version of it. Both fallible and
+//!   infallible versions are available. The name is potentially
+//!   confusing, because this traversal is more like `Iterator::map` than
+//!   `Iterator::fold`.
+//! - Visiting. This is a read-only traversal of the data structure.
 //!
-//! This way, when you define a new folder F, you can override
-//! `fold_T()` to customize the behavior, and invoke `T.super_fold_with()`
-//! to get the original behavior. Meanwhile, to actually fold
-//! something, you can just write `T.fold_with(F)`, which is
-//! convenient. (Note that `fold_with` will also transparently handle
-//! things like a `Vec<T>` where T is foldable and so on.)
+//! These traversals have limited flexibility. Only a small number of "types of
+//! interest" within the complex data structures can receive custom
+//! modification (when folding) or custom visitation (when visiting). These are
+//! the ones containing the most important type-related information, such as
+//! `Ty`, `Predicate`, `Region`, and `Const`.
 //!
-//! In this ideal setup, the only function that actually *does*
-//! anything is `T.super_fold_with()`, which traverses the type `T`.
-//! Moreover, `T.super_fold_with()` should only ever call `T.fold_with()`.
+//! There are two traits involved in each traversal type.
+//! - The first trait is `TypeFoldable`, which is implemented once for many
+//!   types. This includes both (a) types of interest, and (b) all other
+//!   relevant types, including generic containers like `Vec` and `Option`. It
+//!   defines a "skeleton" of how they should be traversed, for both folding
+//!   and visiting.
+//! - The second trait is `TypeFolder`/`FallibleTypeFolder` (for
+//!   infallible/fallible folding traversals) or `TypeVisitor` (for visiting
+//!   traversals). One of these is implemented for each folder/visitor. This
+//!   defines how types of interest are handled.
 //!
-//! In some cases, we follow a degenerate pattern where we do not have
-//! a `fold_T` method. Instead, `T.fold_with` traverses the structure directly.
-//! This is suboptimal because the behavior cannot be overridden, but it's
-//! much less work to implement. If you ever *do* need an override that
-//! doesn't exist, it's not hard to convert the degenerate pattern into the
-//! proper thing.
+//! This means each traversal is a mixture of (a) generic traversal operations,
+//! and (b) custom fold/visit operations that are specific to the
+//! folder/visitor.
+//! - The `TypeFoldable` impls handle most of the traversal, and call into
+//!   `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` when they encounter a
+//!   type of interest.
+//! - A `TypeFolder`/`FallibleTypeFolder`/`TypeVisitor` may also call back into
+//!   a `TypeFoldable` impl, because (a) the types of interest are recursive
+//!   and can contain other types of interest, and (b) each folder/visitor
+//!   might provide custom handling only for some types of interest, or only
+//!   for some variants of each type of interest, and then use default
+//!   traversal for the remaining cases.
 //!
-//! A `TypeFoldable` T can also be visited by a `TypeVisitor` V using similar setup:
-//!
-//!     T.visit_with(V) --calls--> V.visit_T(T) --calls--> T.super_visit_with(V).
-//!
-//! These methods return true to indicate that the visitor has found what it is
-//! looking for, and does not need to visit anything else.
+//! For example, if you have `struct S(Ty, U)` where `S: TypeFoldable` and `U:
+//! TypeFoldable`, and an instance `S(ty, u)`, it would be visited like so:
+//! ```
+//! s.visit_with(visitor) calls
+//! - s.super_visit_with(visitor) calls
+//!   - ty.visit_with(visitor) calls
+//!     - visitor.visit_ty(ty) may call
+//!       - ty.super_visit_with(visitor)
+//!   - u.visit_with(visitor)
+//! ```
 use crate::mir;
 use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
-use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 
 use rustc_data_structures::fx::FxHashSet;
 use std::fmt;
 use std::ops::ControlFlow;
 
-/// This trait is implemented for every type that can be folded.
-/// Basically, every type that has a corresponding method in `TypeFolder`.
+/// This trait is implemented for every type that can be folded/visited,
+/// providing the skeleton of the traversal.
 ///
-/// To implement this conveniently, use the derive macro located in `rustc_macros`.
+/// To implement this conveniently, use the derive macro located in
+/// `rustc_macros`.
 pub trait TypeFoldable<'tcx>: fmt::Debug + Clone {
-    /// Consumers may find this more convenient to use with infallible folders than
-    /// [`try_super_fold_with`][`TypeFoldable::try_super_fold_with`], to which the
-    /// provided default definition delegates.  Implementors **should not** override
-    /// this provided default definition, to ensure that the two methods are coherent
-    /// (provide a definition of `try_super_fold_with` instead).
-    fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
-        self.try_super_fold_with(folder).into_ok()
+    /// The main entry point for folding. To fold a value `t` with a folder `f`
+    /// call: `t.try_fold_with(f)`.
+    ///
+    /// For types of interest (such as `Ty`), this default is overridden with a
+    /// method that calls a folder method specifically for that type (such as
+    /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
+    /// to `TypeFolder`.
+    ///
+    /// For other types, this default is used.
+    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        self.try_super_fold_with(folder)
     }
-    /// Consumers may find this more convenient to use with infallible folders than
-    /// [`try_fold_with`][`TypeFoldable::try_fold_with`], to which the provided
-    /// default definition delegates.  Implementors **should not** override this
-    /// provided default definition, to ensure that the two methods are coherent
-    /// (provide a definition of `try_fold_with` instead).
+
+    /// A convenient alternative to `try_fold_with` for use with infallible
+    /// folders. Do not override this method, to ensure coherence with
+    /// `try_fold_with`.
     fn fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
         self.try_fold_with(folder).into_ok()
     }
 
+    /// Traverses the type in question, typically by calling `try_fold_with` on
+    /// each field/element. This is true even for types of interest such as
+    /// `Ty`. This should only be called within `TypeFolder` methods, when
+    /// non-custom traversals are desired for types of interest.
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error>;
 
-    fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        self.try_super_fold_with(folder)
+    /// A convenient alternative to `try_super_fold_with` for use with
+    /// infallible folders. Do not override this method, to ensure coherence
+    /// with `try_super_fold_with`.
+    fn super_fold_with<F: TypeFolder<'tcx, Error = !>>(self, folder: &mut F) -> Self {
+        self.try_super_fold_with(folder).into_ok()
     }
 
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+    /// The entry point for visiting. To visit a value `t` with a visitor `v`
+    /// call: `t.visit_with(v)`.
+    ///
+    /// For types of interest (such as `Ty`), this default is overridden with a
+    /// method that calls a visitor method specifically for that type (such as
+    /// `V::visit_ty`). This is where control transfers from `TypeFoldable` to
+    /// `TypeVisitor`.
+    ///
+    /// For other types, this default is used.
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
         self.super_visit_with(visitor)
     }
 
+    /// Traverses the type in question, typically by calling `visit_with` on
+    /// each field/element. This is true even for types of interest such as
+    /// `Ty`. This should only be called within `TypeVisitor` methods, when
+    /// non-custom traversals are desired for types of interest.
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
+
     /// Returns `true` if `self` has any late-bound regions that are either
     /// bound by `binder` or bound by some binder outside of `binder`.
     /// If `binder` is `ty::INNERMOST`, this indicates whether
@@ -168,24 +211,13 @@ fn still_further_specializable(&self) -> bool {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for hir::Constness {
-    fn try_super_fold_with<F: TypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
-        Ok(self)
-    }
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
-        ControlFlow::CONTINUE
-    }
-}
-
-/// The `TypeFolder` trait defines the actual *folding*. There is a
-/// method defined for every foldable type. Each of these has a
-/// default implementation that does an "identity" fold. Within each
-/// identity fold, it should invoke `foo.fold_with(self)` to fold each
-/// sub-item.
+/// This trait is implemented for every folding traversal. There is a fold
+/// method defined for every type of interest. Each such method has a default
+/// that does an "identity" fold.
 ///
 /// If this folder is fallible (and therefore its [`Error`][`TypeFolder::Error`]
-/// associated type is something other than the default, never),
-/// [`FallibleTypeFolder`] should be implemented manually; otherwise,
+/// associated type is something other than the default `!`) then
+/// [`FallibleTypeFolder`] should be implemented manually. Otherwise,
 /// a blanket implementation of [`FallibleTypeFolder`] will defer to
 /// the infallible methods of this trait to ensure that the two APIs
 /// are coherent.
@@ -216,7 +248,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx>
         r.super_fold_with(self)
     }
 
-    fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>
+    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx>
     where
         Self: TypeFolder<'tcx, Error = !>,
     {
@@ -238,11 +270,9 @@ fn fold_mir_const(&mut self, c: mir::ConstantKind<'tcx>) -> mir::ConstantKind<'t
     }
 }
 
-/// The `FallibleTypeFolder` trait defines the actual *folding*. There is a
-/// method defined for every foldable type. Each of these has a
-/// default implementation that does an "identity" fold. Within each
-/// identity fold, it should invoke `foo.try_fold_with(self)` to fold each
-/// sub-item.
+/// This trait is implemented for every folding traversal. There is a fold
+/// method defined for every type of interest. Each such method has a default
+/// that does an "identity" fold.
 ///
 /// A blanket implementation of this trait (that defers to the relevant
 /// method of [`TypeFolder`]) is provided for all infallible folders in
@@ -263,10 +293,7 @@ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, S
         r.try_super_fold_with(self)
     }
 
-    fn try_fold_const(
-        &mut self,
-        c: &'tcx ty::Const<'tcx>,
-    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
         c.try_super_fold_with(self)
     }
 
@@ -285,8 +312,8 @@ fn try_fold_mir_const(
     }
 }
 
-// Blanket implementation of fallible trait for infallible folders
-// delegates to infallible methods to prevent incoherence
+// This blanket implementation of the fallible trait for infallible folders
+// delegates to infallible methods to ensure coherence.
 impl<'tcx, F> FallibleTypeFolder<'tcx> for F
 where
     F: TypeFolder<'tcx, Error = !>,
@@ -306,10 +333,7 @@ fn try_fold_region(&mut self, r: ty::Region<'tcx>) -> Result<ty::Region<'tcx>, S
         Ok(self.fold_region(r))
     }
 
-    fn try_fold_const(
-        &mut self,
-        c: &'tcx ty::Const<'tcx>,
-    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
         Ok(self.fold_const(c))
     }
 
@@ -328,6 +352,9 @@ fn try_fold_mir_const(
     }
 }
 
+/// This trait is implemented for every visiting traversal. There is a visit
+/// method defined for every type of interest. Each such method has a default
+/// that recurses into the type's fields in a non-custom fashion.
 pub trait TypeVisitor<'tcx>: Sized {
     type BreakTy = !;
 
@@ -346,7 +373,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         r.super_visit_with(self)
     }
 
-    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         c.super_visit_with(self)
     }
 
@@ -366,7 +393,7 @@ pub struct BottomUpFolder<'tcx, F, G, H>
 where
     F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
     G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
-    H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>,
+    H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>,
 {
     pub tcx: TyCtxt<'tcx>,
     pub ty_op: F,
@@ -378,7 +405,7 @@ impl<'tcx, F, G, H> TypeFolder<'tcx> for BottomUpFolder<'tcx, F, G, H>
 where
     F: FnMut(Ty<'tcx>) -> Ty<'tcx>,
     G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>,
-    H: FnMut(&'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx>,
+    H: FnMut(ty::Const<'tcx>) -> ty::Const<'tcx>,
 {
     fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         self.tcx
@@ -394,7 +421,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         (self.lt_op)(r)
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         let ct = ct.super_fold_with(self);
         (self.ct_op)(ct)
     }
@@ -593,7 +620,7 @@ struct BoundVarReplacer<'a, 'tcx> {
 
     fld_r: Option<&'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a)>,
     fld_t: Option<&'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a)>,
-    fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx> + 'a)>,
+    fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a)>,
 }
 
 impl<'a, 'tcx> BoundVarReplacer<'a, 'tcx> {
@@ -601,7 +628,7 @@ fn new(
         tcx: TyCtxt<'tcx>,
         fld_r: Option<&'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a)>,
         fld_t: Option<&'a mut (dyn FnMut(ty::BoundTy) -> Ty<'tcx> + 'a)>,
-        fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx> + 'a)>,
+        fld_c: Option<&'a mut (dyn FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx> + 'a)>,
     ) -> Self {
         BoundVarReplacer { tcx, current_index: ty::INNERMOST, fld_r, fld_t, fld_c }
     }
@@ -627,7 +654,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
             ty::Bound(debruijn, bound_ty) if debruijn == self.current_index => {
                 if let Some(fld_t) = self.fld_t.as_mut() {
                     let ty = fld_t(bound_ty);
-                    return ty::fold::shift_vars(self.tcx, &ty, self.current_index.as_u32());
+                    return ty::fold::shift_vars(self.tcx, ty, self.current_index.as_u32());
                 }
             }
             _ if t.has_vars_bound_at_or_above(self.current_index) => {
@@ -660,14 +687,12 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         r
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        match *ct {
-            ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty }
-                if debruijn == self.current_index =>
-            {
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        match ct.val() {
+            ty::ConstKind::Bound(debruijn, bound_const) if debruijn == self.current_index => {
                 if let Some(fld_c) = self.fld_c.as_mut() {
-                    let ct = fld_c(bound_const, ty);
-                    return ty::fold::shift_vars(self.tcx, &ct, self.current_index.as_u32());
+                    let ct = fld_c(bound_const, ct.ty());
+                    return ty::fold::shift_vars(self.tcx, ct, self.current_index.as_u32());
                 }
             }
             _ if ct.has_vars_bound_at_or_above(self.current_index) => {
@@ -726,7 +751,7 @@ pub fn replace_escaping_bound_vars<T, F, G, H>(
     where
         F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
         G: FnMut(ty::BoundTy) -> Ty<'tcx>,
-        H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>,
+        H: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>,
         T: TypeFoldable<'tcx>,
     {
         if !value.has_escaping_bound_vars() {
@@ -751,7 +776,7 @@ pub fn replace_bound_vars<T, F, G, H>(
     where
         F: FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
         G: FnMut(ty::BoundTy) -> Ty<'tcx>,
-        H: FnMut(ty::BoundVar, Ty<'tcx>) -> &'tcx ty::Const<'tcx>,
+        H: FnMut(ty::BoundVar, Ty<'tcx>) -> ty::Const<'tcx>,
         T: TypeFoldable<'tcx>,
     {
         let mut region_map = BTreeMap::new();
@@ -804,7 +829,7 @@ pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T
                 ))
             },
             |c, ty| {
-                self.mk_const(ty::Const {
+                self.mk_const(ty::ConstS {
                     val: ty::ConstKind::Bound(
                         ty::INNERMOST,
                         ty::BoundVar::from_usize(c.as_usize() + bound_vars),
@@ -926,7 +951,7 @@ fn visit_binder<T: TypeFoldable<'tcx>>(
     }
 
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if t.outer_exclusive_binder < self.binder_index
+        if t.outer_exclusive_binder() < self.binder_index
             || !self.visited.insert((self.binder_index, t))
         {
             return ControlFlow::BREAK;
@@ -960,10 +985,10 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
     }
 
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match r {
-            ty::ReLateBound(index, br) if *index == self.binder_index => {
+        match *r {
+            ty::ReLateBound(index, br) if index == self.binder_index => {
                 if self.bound_vars.len() <= br.var.as_usize() {
-                    bug!("Not enough bound vars: {:?} not found in {:?}", *br, self.bound_vars);
+                    bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars);
                 }
                 let list_var = self.bound_vars[br.var.as_usize()];
                 match list_var {
@@ -1057,13 +1082,16 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if let ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty } = *ct {
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        if let ty::ConstKind::Bound(debruijn, bound_ct) = ct.val() {
             if self.amount == 0 || debruijn < self.current_index {
                 ct
             } else {
                 let debruijn = debruijn.shifted_in(self.amount);
-                self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty })
+                self.tcx.mk_const(ty::ConstS {
+                    val: ty::ConstKind::Bound(debruijn, bound_ct),
+                    ty: ct.ty(),
+                })
             }
         } else {
             ct.super_fold_with(self)
@@ -1076,9 +1104,9 @@ pub fn shift_region<'tcx>(
     region: ty::Region<'tcx>,
     amount: u32,
 ) -> ty::Region<'tcx> {
-    match region {
+    match *region {
         ty::ReLateBound(debruijn, br) if amount > 0 => {
-            tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), *br))
+            tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), br))
         }
         _ => region,
     }
@@ -1146,7 +1174,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         // bound at `outer_index` or above (because
         // `outer_exclusive_binder` is always 1 higher than the
         // content in `t`). Therefore, `t` has some escaping vars.
-        if t.outer_exclusive_binder > self.outer_index {
+        if t.outer_exclusive_binder() > self.outer_index {
             ControlFlow::Break(FoundEscapingVars)
         } else {
             ControlFlow::CONTINUE
@@ -1165,13 +1193,13 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         }
     }
 
-    fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         // we don't have a `visit_infer_const` callback, so we have to
         // hook in here to catch this case (annoying...), but
         // otherwise we do want to remember to visit the rest of the
         // const, as it has types/regions embedded in a lot of other
         // places.
-        match ct.val {
+        match ct.val() {
             ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
                 ControlFlow::Break(FoundEscapingVars)
             }
@@ -1181,7 +1209,7 @@ fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakT
 
     #[inline]
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if predicate.inner.outer_exclusive_binder > self.outer_index {
+        if predicate.outer_exclusive_binder() > self.outer_index {
             ControlFlow::Break(FoundEscapingVars)
         } else {
             ControlFlow::CONTINUE
@@ -1236,7 +1264,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
 
     #[inline]
     #[instrument(level = "trace")]
-    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         let flags = FlagComputation::for_const(c);
         trace!(r.flags=?flags);
         if flags.intersects(self.flags) {
@@ -1263,9 +1291,11 @@ fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
         debug!(
             "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
-            predicate, predicate.inner.flags, self.flags
+            predicate,
+            predicate.flags(),
+            self.flags
         );
-        if predicate.inner.flags.intersects(self.flags) {
+        if predicate.flags().intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
             ControlFlow::CONTINUE
@@ -1323,12 +1353,12 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         t.super_visit_with(self)
     }
 
-    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         // if we are only looking for "constrained" region, we have to
         // ignore the inputs of an unevaluated const, as they may not appear
         // in the normalized form
         if self.just_constrained {
-            if let ty::ConstKind::Unevaluated(..) = c.val {
+            if let ty::ConstKind::Unevaluated(..) = c.val() {
                 return ControlFlow::CONTINUE;
             }
         }
index 55807874705f6253e603e4362e9712f01c3d5c9d..c4ad698ba763531896eb8d5e1a633c2c4afb0228 100644 (file)
@@ -3,7 +3,6 @@
 use rustc_span::def_id::CRATE_DEF_ID;
 use smallvec::SmallVec;
 use std::mem;
-use std::sync::Arc;
 
 use DefIdForest::*;
 
 /// We store the minimal set of `DefId`s required to represent the whole set. If A and B are
 /// `DefId`s in the `DefIdForest`, and A is a parent of B, then only A will be stored. When this is
 /// used with `type_uninhabited_from`, there will very rarely be more than one `DefId` stored.
-#[derive(Clone, HashStable, Debug)]
-pub enum DefIdForest {
+#[derive(Copy, Clone, HashStable, Debug)]
+pub enum DefIdForest<'a> {
     Empty,
     Single(DefId),
     /// This variant is very rare.
     /// Invariant: >1 elements
-    /// We use `Arc` because this is used in the output of a query.
-    Multiple(Arc<[DefId]>),
+    Multiple(&'a [DefId]),
 }
 
 /// Tests whether a slice of roots contains a given DefId.
@@ -34,21 +32,21 @@ fn slice_contains<'tcx>(tcx: TyCtxt<'tcx>, slice: &[DefId], id: DefId) -> bool {
     slice.iter().any(|root_id| tcx.is_descendant_of(id, *root_id))
 }
 
-impl<'tcx> DefIdForest {
+impl<'tcx> DefIdForest<'tcx> {
     /// Creates an empty forest.
-    pub fn empty() -> DefIdForest {
+    pub fn empty() -> DefIdForest<'tcx> {
         DefIdForest::Empty
     }
 
     /// Creates a forest consisting of a single tree representing the entire
     /// crate.
     #[inline]
-    pub fn full() -> DefIdForest {
+    pub fn full() -> DefIdForest<'tcx> {
         DefIdForest::from_id(CRATE_DEF_ID.to_def_id())
     }
 
     /// Creates a forest containing a `DefId` and all its descendants.
-    pub fn from_id(id: DefId) -> DefIdForest {
+    pub fn from_id(id: DefId) -> DefIdForest<'tcx> {
         DefIdForest::Single(id)
     }
 
@@ -61,11 +59,11 @@ fn as_slice(&self) -> &[DefId] {
     }
 
     // Only allocates in the rare `Multiple` case.
-    fn from_slice(root_ids: &[DefId]) -> DefIdForest {
-        match root_ids {
+    fn from_vec(tcx: TyCtxt<'tcx>, root_ids: SmallVec<[DefId; 1]>) -> DefIdForest<'tcx> {
+        match &root_ids[..] {
             [] => Empty,
             [id] => Single(*id),
-            _ => DefIdForest::Multiple(root_ids.into()),
+            _ => DefIdForest::Multiple(tcx.arena.alloc_from_iter(root_ids)),
         }
     }
 
@@ -88,9 +86,9 @@ pub fn contains(&self, tcx: TyCtxt<'tcx>, id: DefId) -> bool {
     }
 
     /// Calculate the intersection of a collection of forests.
-    pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
+    pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
     where
-        I: IntoIterator<Item = DefIdForest>,
+        I: IntoIterator<Item = DefIdForest<'tcx>>,
     {
         let mut iter = iter.into_iter();
         let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() {
@@ -114,13 +112,13 @@ pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
             mem::swap(&mut next_ret, &mut ret);
             next_ret.clear();
         }
-        DefIdForest::from_slice(&ret)
+        DefIdForest::from_vec(tcx, ret)
     }
 
     /// Calculate the union of a collection of forests.
-    pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
+    pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest<'tcx>
     where
-        I: IntoIterator<Item = DefIdForest>,
+        I: IntoIterator<Item = DefIdForest<'tcx>>,
     {
         let mut ret: SmallVec<[_; 1]> = SmallVec::new();
         let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
@@ -142,6 +140,6 @@ pub fn union<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
             mem::swap(&mut next_ret, &mut ret);
             next_ret.clear();
         }
-        DefIdForest::from_slice(&ret)
+        DefIdForest::from_vec(tcx, ret)
     }
 }
index 167a54e42a0156bdd1b9e08c0fb128624325ee14..f2682b8bcd838178a28f0f87510b950c5394b839 100644 (file)
@@ -3,7 +3,7 @@
 use crate::ty;
 use crate::ty::context::TyCtxt;
 use crate::ty::TyKind::*;
-use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef};
+use crate::ty::{AdtDef, FieldDef, Ty, VariantDef};
 use crate::ty::{AdtKind, Visibility};
 use crate::ty::{DefId, SubstsRef};
 
@@ -112,7 +112,7 @@ fn uninhabited_from(
         tcx: TyCtxt<'tcx>,
         substs: SubstsRef<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest {
+    ) -> DefIdForest<'tcx> {
         // Non-exhaustive ADTs from other crates are always considered inhabited.
         if self.is_variant_list_non_exhaustive() && !self.did.is_local() {
             DefIdForest::empty()
@@ -135,7 +135,7 @@ pub fn uninhabited_from(
         substs: SubstsRef<'tcx>,
         adt_kind: AdtKind,
         param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest {
+    ) -> DefIdForest<'tcx> {
         let is_enum = match adt_kind {
             // For now, `union`s are never considered uninhabited.
             // The precise semantics of inhabitedness with respect to unions is currently undecided.
@@ -163,7 +163,7 @@ fn uninhabited_from(
         substs: SubstsRef<'tcx>,
         is_enum: bool,
         param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest {
+    ) -> DefIdForest<'tcx> {
         let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env);
         // FIXME(canndrew): Currently enum fields are (incorrectly) stored with
         // `Visibility::Invisible` so we need to override `self.vis` if we're
@@ -184,14 +184,14 @@ fn uninhabited_from(
     }
 }
 
-impl<'tcx> TyS<'tcx> {
+impl<'tcx> Ty<'tcx> {
     /// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
     fn uninhabited_from(
-        &'tcx self,
+        self,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-    ) -> DefIdForest {
-        tcx.type_uninhabited_from(param_env.and(self))
+    ) -> DefIdForest<'tcx> {
+        tcx.type_uninhabited_from(param_env.and(self)).clone()
     }
 }
 
@@ -199,7 +199,7 @@ fn uninhabited_from(
 pub(crate) fn type_uninhabited_from<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-) -> DefIdForest {
+) -> DefIdForest<'tcx> {
     let ty = key.value;
     let param_env = key.param_env;
     match *ty.kind() {
index eaa7ee84b7b8d994a791a263f0282bb2d9d3f1af..99c595fcdf18507072f3c5b530ce3357903a8f96 100644 (file)
@@ -101,7 +101,7 @@ impl<'tcx> Instance<'tcx> {
     /// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
     pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
         let ty = tcx.type_of(self.def.def_id());
-        tcx.subst_and_normalize_erasing_regions(self.substs, param_env, &ty)
+        tcx.subst_and_normalize_erasing_regions(self.substs, param_env, ty)
     }
 
     /// Finds a crate that contains a monomorphization of this instance that
@@ -642,7 +642,7 @@ fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
 
         fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             debug!("fold_ty: ty={:?}", ty);
-            match ty.kind {
+            match *ty.kind() {
                 ty::Closure(def_id, substs) => {
                     let polymorphized_substs = polymorphize(
                         self.tcx,
index caf33fa5d213b49559068fd8070e9ced4c50a42a..6d4178c3e753f4da570abf69ba9831ca533c6801 100644 (file)
@@ -1310,7 +1310,10 @@ fn layout_of_uncached(&self, ty: Ty<'tcx>) -> Result<&'tcx Layout, LayoutError<'
                     },
                 };
                 let mut abi = Abi::Aggregate { sized: true };
-                if tag.value.size(dl) == size {
+
+                // Without latter check aligned enums with custom discriminant values
+                // Would result in ICE see the issue #92464 for more info
+                if tag.value.size(dl) == size || variants.iter().all(|layout| layout.is_empty()) {
                     abi = Abi::Scalar(tag);
                 } else {
                     // Try to use a ScalarPair for all tagged enums.
@@ -2773,17 +2776,20 @@ pub fn fn_can_unwind<'tcx>(
     // [rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2945-c-unwind-abi.md
     use SpecAbi::*;
     match abi {
-        C { unwind } | Stdcall { unwind } | System { unwind } | Thiscall { unwind } => {
+        C { unwind }
+        | System { unwind }
+        | Cdecl { unwind }
+        | Stdcall { unwind }
+        | Fastcall { unwind }
+        | Vectorcall { unwind }
+        | Thiscall { unwind }
+        | Aapcs { unwind }
+        | Win64 { unwind }
+        | SysV64 { unwind } => {
             unwind
                 || (!tcx.features().c_unwind && tcx.sess.panic_strategy() == PanicStrategy::Unwind)
         }
-        Cdecl
-        | Fastcall
-        | Vectorcall
-        | Aapcs
-        | Win64
-        | SysV64
-        | PtxKernel
+        PtxKernel
         | Msp430Interrupt
         | X86Interrupt
         | AmdGpuKernel
@@ -2810,14 +2816,14 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
         EfiApi => bug!("eficall abi should be selected elsewhere"),
 
         Stdcall { .. } => Conv::X86Stdcall,
-        Fastcall => Conv::X86Fastcall,
-        Vectorcall => Conv::X86VectorCall,
+        Fastcall { .. } => Conv::X86Fastcall,
+        Vectorcall { .. } => Conv::X86VectorCall,
         Thiscall { .. } => Conv::X86ThisCall,
         C { .. } => Conv::C,
         Unadjusted => Conv::C,
-        Win64 => Conv::X86_64Win64,
-        SysV64 => Conv::X86_64SysV,
-        Aapcs => Conv::ArmAapcs,
+        Win64 { .. } => Conv::X86_64Win64,
+        SysV64 { .. } => Conv::X86_64SysV,
+        Aapcs { .. } => Conv::ArmAapcs,
         CCmseNonSecureCall => Conv::CCmseNonSecureCall,
         PtxKernel => Conv::PtxKernel,
         Msp430Interrupt => Conv::Msp430Intr,
@@ -2828,12 +2834,12 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
         Wasm => Conv::C,
 
         // These API constants ought to be more specific...
-        Cdecl => Conv::C,
+        Cdecl { .. } => Conv::C,
     }
 }
 
 /// Error produced by attempting to compute or adjust a `FnAbi`.
-#[derive(Clone, Debug, HashStable)]
+#[derive(Copy, Clone, Debug, HashStable)]
 pub enum FnAbiError<'tcx> {
     /// Error produced by a `layout_of` call, while computing `FnAbi` initially.
     Layout(LayoutError<'tcx>),
@@ -3045,9 +3051,10 @@ fn fn_abi_new_uncached(
                                       layout: TyAndLayout<'tcx>,
                                       offset: Size,
                                       is_return: bool| {
-            // Booleans are always an i1 that needs to be zero-extended.
+            // Booleans are always a noundef i1 that needs to be zero-extended.
             if scalar.is_bool() {
                 attrs.ext(ArgExtension::Zext);
+                attrs.set(ArgAttribute::NoUndef);
                 return;
             }
 
@@ -3072,6 +3079,11 @@ fn fn_abi_new_uncached(
                         _ => pointee.size,
                     };
 
+                    // `Box`, `&T`, and `&mut T` cannot be undef.
+                    // Note that this only applies to the value of the pointer itself;
+                    // this attribute doesn't make it UB for the pointed-to data to be undef.
+                    attrs.set(ArgAttribute::NoUndef);
+
                     // `Box` pointer parameters never alias because ownership is transferred
                     // `&mut` pointer parameters never alias other parameters,
                     // or mutable global data
index 8eb2793cc34e3b7fe6f636d6a64af2ed2897c6f4..f0b7f2a653f45e761b1e7cca71c1af64d99f0139 100644 (file)
@@ -29,6 +29,7 @@
 use rustc_ast as ast;
 use rustc_attr as attr;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
 use rustc_hir as hir;
 use rustc_span::{sym, Span};
 use rustc_target::abi::Align;
 
-use std::cmp::Ordering;
-use std::hash::{Hash, Hasher};
+use std::hash::Hash;
 use std::ops::ControlFlow;
-use std::{fmt, ptr, str};
+use std::{fmt, str};
 
 pub use crate::ty::diagnostics::*;
 pub use rustc_type_ir::InferTy::*;
@@ -59,7 +59,9 @@
     RootVariableMinCaptureList, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, UpvarPath,
     CAPTURE_STRUCT_LOCAL,
 };
-pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, Unevaluated, ValTree};
+pub use self::consts::{
+    Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValTree,
+};
 pub use self::context::{
     tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
     CtxtInterners, DelaySpanBugEmitted, FreeRegionInfo, GeneratorInteriorTypeCause, GlobalCtxt,
@@ -380,21 +382,25 @@ pub struct CReaderCacheKey {
 
 /// Represents a type.
 ///
-/// IMPORTANT: Every `TyS` is *required* to have unique contents. The type's
-/// correctness relies on this, *but it does not enforce it*. Therefore, any
-/// code that creates a `TyS` must ensure uniqueness itself. In practice this
-/// is achieved by interning.
+/// IMPORTANT:
+/// - This is a very "dumb" struct (with no derives and no `impls`).
+/// - Values of this type are always interned and thus unique, and are stored
+///   as an `Interned<TyS>`.
+/// - `Ty` (which contains a reference to a `Interned<TyS>`) or `Interned<TyS>`
+///   should be used everywhere instead of `TyS`. In particular, `Ty` has most
+///   of the relevant methods.
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
 #[allow(rustc::usage_of_ty_tykind)]
-pub struct TyS<'tcx> {
+crate struct TyS<'tcx> {
     /// This field shouldn't be used directly and may be removed in the future.
-    /// Use `TyS::kind()` instead.
+    /// Use `Ty::kind()` instead.
     kind: TyKind<'tcx>,
 
     /// This field provides fast access to information that is also contained
     /// in `kind`.
     ///
     /// This field shouldn't be used directly and may be removed in the future.
-    /// Use `TyS::flags()` instead.
+    /// Use `Ty::flags()` instead.
     flags: TypeFlags,
 
     /// This field provides fast access to information that is also contained
@@ -420,55 +426,27 @@ pub struct TyS<'tcx> {
     outer_exclusive_binder: ty::DebruijnIndex,
 }
 
-impl<'tcx> TyS<'tcx> {
-    /// A constructor used only for internal testing.
-    #[allow(rustc::usage_of_ty_tykind)]
-    pub fn make_for_test(
-        kind: TyKind<'tcx>,
-        flags: TypeFlags,
-        outer_exclusive_binder: ty::DebruijnIndex,
-    ) -> TyS<'tcx> {
-        TyS { kind, flags, outer_exclusive_binder }
-    }
-}
-
 // `TyS` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 static_assert_size!(TyS<'_>, 40);
 
-impl<'tcx> Ord for TyS<'tcx> {
-    fn cmp(&self, other: &TyS<'tcx>) -> Ordering {
-        self.kind().cmp(other.kind())
-    }
-}
-
-impl<'tcx> PartialOrd for TyS<'tcx> {
-    fn partial_cmp(&self, other: &TyS<'tcx>) -> Option<Ordering> {
-        Some(self.kind().cmp(other.kind()))
-    }
-}
-
-impl<'tcx> PartialEq for TyS<'tcx> {
-    #[inline]
-    fn eq(&self, other: &TyS<'tcx>) -> bool {
-        // Pointer equality implies equality (due to the unique contents
-        // assumption).
-        ptr::eq(self, other)
-    }
-}
-impl<'tcx> Eq for TyS<'tcx> {}
-
-impl<'tcx> Hash for TyS<'tcx> {
-    fn hash<H: Hasher>(&self, s: &mut H) {
-        // Pointer hashing is sufficient (due to the unique contents
-        // assumption).
-        (self as *const TyS<'_>).hash(s)
-    }
-}
+/// Use this rather than `TyS`, whenever possible.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[rustc_diagnostic_item = "Ty"]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Ty<'tcx>(Interned<'tcx, TyS<'tcx>>);
+
+// Statics only used for internal testing.
+pub static BOOL_TY: Ty<'static> = Ty(Interned::new_unchecked(&BOOL_TYS));
+static BOOL_TYS: TyS<'static> = TyS {
+    kind: ty::Bool,
+    flags: TypeFlags::empty(),
+    outer_exclusive_binder: DebruijnIndex::from_usize(0),
+};
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
+impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Ty<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let ty::TyS {
+        let TyS {
             ref kind,
 
             // The other fields just provide fast access to information that is
@@ -476,16 +454,12 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
             flags: _,
 
             outer_exclusive_binder: _,
-        } = *self;
+        } = self.0.0;
 
         kind.hash_stable(hcx, hasher);
     }
 }
 
-#[rustc_diagnostic_item = "Ty"]
-#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
-pub type Ty<'tcx> = &'tcx TyS<'tcx>;
-
 impl ty::EarlyBoundRegion {
     /// Does this early bound region have a name? Early bound regions normally
     /// always have names except when using anonymous lifetimes (`'_`).
@@ -494,51 +468,50 @@ pub fn has_name(&self) -> bool {
     }
 }
 
+/// Represents a predicate.
+///
+/// See comments on `TyS`, which apply here too (albeit for
+/// `PredicateS`/`Predicate` rather than `TyS`/`Ty`).
 #[derive(Debug)]
-crate struct PredicateInner<'tcx> {
+crate struct PredicateS<'tcx> {
     kind: Binder<'tcx, PredicateKind<'tcx>>,
     flags: TypeFlags,
     /// See the comment for the corresponding field of [TyS].
     outer_exclusive_binder: ty::DebruijnIndex,
 }
 
+// This type is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(PredicateInner<'_>, 56);
-
-#[derive(Clone, Copy, Lift)]
-pub struct Predicate<'tcx> {
-    inner: &'tcx PredicateInner<'tcx>,
-}
+static_assert_size!(PredicateS<'_>, 56);
 
-impl<'tcx> PartialEq for Predicate<'tcx> {
-    fn eq(&self, other: &Self) -> bool {
-        // `self.kind` is always interned.
-        ptr::eq(self.inner, other.inner)
-    }
-}
-
-impl Hash for Predicate<'_> {
-    fn hash<H: Hasher>(&self, s: &mut H) {
-        (self.inner as *const PredicateInner<'_>).hash(s)
-    }
-}
-
-impl<'tcx> Eq for Predicate<'tcx> {}
+/// Use this rather than `PredicateS`, whenever possible.
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Predicate<'tcx>(Interned<'tcx, PredicateS<'tcx>>);
 
 impl<'tcx> Predicate<'tcx> {
     /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`.
     #[inline]
     pub fn kind(self) -> Binder<'tcx, PredicateKind<'tcx>> {
-        self.inner.kind
+        self.0.kind
+    }
+
+    #[inline(always)]
+    pub fn flags(self) -> TypeFlags {
+        self.0.flags
+    }
+
+    #[inline(always)]
+    pub fn outer_exclusive_binder(self) -> DebruijnIndex {
+        self.0.outer_exclusive_binder
     }
 
     /// Flips the polarity of a Predicate.
     ///
     /// Given `T: Trait` predicate it returns `T: !Trait` and given `T: !Trait` returns `T: Trait`.
-    pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> {
+    pub fn flip_polarity(self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> {
         let kind = self
-            .inner
-            .kind
+            .kind()
             .map_bound(|kind| match kind {
                 PredicateKind::Trait(TraitPredicate { trait_ref, constness, polarity }) => {
                     Some(PredicateKind::Trait(TraitPredicate {
@@ -558,14 +531,14 @@ pub fn flip_polarity(&self, tcx: TyCtxt<'tcx>) -> Option<Predicate<'tcx>> {
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let PredicateInner {
+        let PredicateS {
             ref kind,
 
             // The other fields just provide fast access to information that is
             // also contained in `kind`, so no need to hash them.
             flags: _,
             outer_exclusive_binder: _,
-        } = self.inner;
+        } = self.0.0;
 
         kind.hash_stable(hcx, hasher);
     }
@@ -621,7 +594,7 @@ pub enum PredicateKind<'tcx> {
     ConstEvaluatable(ty::Unevaluated<'tcx, ()>),
 
     /// Constants must be equal. The first component is the const that is expected.
-    ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>),
+    ConstEquate(Const<'tcx>, Const<'tcx>),
 
     /// Represents a type found in the environment that we can use for implied bounds.
     ///
@@ -847,7 +820,7 @@ pub struct CoercePredicate<'tcx> {
 #[derive(HashStable, TypeFoldable)]
 pub enum Term<'tcx> {
     Ty(Ty<'tcx>),
-    Const(&'tcx Const<'tcx>),
+    Const(Const<'tcx>),
 }
 
 impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
@@ -856,18 +829,18 @@ fn from(ty: Ty<'tcx>) -> Self {
     }
 }
 
-impl<'tcx> From<&'tcx Const<'tcx>> for Term<'tcx> {
-    fn from(c: &'tcx Const<'tcx>) -> Self {
+impl<'tcx> From<Const<'tcx>> for Term<'tcx> {
+    fn from(c: Const<'tcx>) -> Self {
         Term::Const(c)
     }
 }
 
 impl<'tcx> Term<'tcx> {
     pub fn ty(&self) -> Option<Ty<'tcx>> {
-        if let Term::Ty(ty) = self { Some(ty) } else { None }
+        if let Term::Ty(ty) = self { Some(*ty) } else { None }
     }
-    pub fn ct(&self) -> Option<&'tcx Const<'tcx>> {
-        if let Term::Const(c) = self { Some(c) } else { None }
+    pub fn ct(&self) -> Option<Const<'tcx>> {
+        if let Term::Const(c) = self { Some(*c) } else { None }
     }
 }
 
index b3b2bb4459f7df376a5aeb6c07b2f8332956e879..808be446b2af66920b70c439e15329ad18549863 100644 (file)
@@ -192,7 +192,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         self.normalize_generic_arg_after_erasing_regions(ty.into()).expect_ty()
     }
 
-    fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
         self.normalize_generic_arg_after_erasing_regions(c.into()).expect_const()
     }
 
@@ -244,13 +244,10 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         }
     }
 
-    fn try_fold_const(
-        &mut self,
-        c: &'tcx ty::Const<'tcx>,
-    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+    fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
         match self.try_normalize_generic_arg_after_erasing_regions(c.into()) {
             Ok(t) => Ok(t.expect_const()),
-            Err(_) => Err(NormalizationError::Const(*c)),
+            Err(_) => Err(NormalizationError::Const(c)),
         }
     }
 
index 7b5905fddc9e53329e7c81b9f016c61e24b68bf3..94cea505c32a058d049f925a5d7fcabbd3a7e413 100644 (file)
@@ -66,7 +66,7 @@ fn print_dyn_existential(
         predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
     ) -> Result<Self::DynExistential, Self::Error>;
 
-    fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error>;
+    fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error>;
 
     fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error>;
 
@@ -188,11 +188,6 @@ fn generic_args_to_print(
             own_params.start = 1;
         }
 
-        // If we're in verbose mode, then print default-equal args too
-        if self.tcx().sess.verbose() {
-            return &substs[own_params];
-        }
-
         // Don't print args that are the defaults of their respective parameters.
         own_params.end -= generics
             .params
@@ -326,19 +321,11 @@ pub fn characteristic_def_id_of_type(ty: Ty<'_>) -> Option<DefId> {
     characteristic_def_id_of_type_cached(ty, &mut SsoHashSet::new())
 }
 
-impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::RegionKind {
-    type Output = P::Region;
-    type Error = P::Error;
-    fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
-        cx.print_region(self)
-    }
-}
-
 impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Region<'_> {
     type Output = P::Region;
     type Error = P::Error;
     fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
-        cx.print_region(self)
+        cx.print_region(*self)
     }
 }
 
@@ -346,7 +333,7 @@ impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> {
     type Output = P::Type;
     type Error = P::Error;
     fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
-        cx.print_type(self)
+        cx.print_type(*self)
     }
 }
 
@@ -360,10 +347,10 @@ fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
     }
 }
 
-impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for &'tcx ty::Const<'tcx> {
+impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for ty::Const<'tcx> {
     type Output = P::Const;
     type Error = P::Error;
     fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
-        cx.print_const(self)
+        cx.print_const(*self)
     }
 }
index ddcc8680d835269bd4f34257bccb79f01db361c6..ae838a461574b2df1dee5d0a317423c33c28975f 100644 (file)
@@ -3,6 +3,7 @@
 use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable};
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, DefKind, Namespace};
@@ -130,11 +131,13 @@ pub fn with_no_visible_paths<F: FnOnce() -> R, R>(f: F) -> R {
 ///
 /// Regions not selected by the region highlight mode are presently
 /// unaffected.
-#[derive(Copy, Clone, Default)]
-pub struct RegionHighlightMode {
+#[derive(Copy, Clone)]
+pub struct RegionHighlightMode<'tcx> {
+    tcx: TyCtxt<'tcx>,
+
     /// If enabled, when we see the selected region, use "`'N`"
     /// instead of the ordinary behavior.
-    highlight_regions: [Option<(ty::RegionKind, usize)>; 3],
+    highlight_regions: [Option<(ty::Region<'tcx>, usize)>; 3],
 
     /// If enabled, when printing a "free region" that originated from
     /// the given `ty::BoundRegionKind`, print it as "`'1`". Free regions that would ordinarily
@@ -146,12 +149,20 @@ pub struct RegionHighlightMode {
     highlight_bound_region: Option<(ty::BoundRegionKind, usize)>,
 }
 
-impl RegionHighlightMode {
+impl<'tcx> RegionHighlightMode<'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
+        Self {
+            tcx,
+            highlight_regions: Default::default(),
+            highlight_bound_region: Default::default(),
+        }
+    }
+
     /// If `region` and `number` are both `Some`, invokes
     /// `highlighting_region`.
     pub fn maybe_highlighting_region(
         &mut self,
-        region: Option<ty::Region<'_>>,
+        region: Option<ty::Region<'tcx>>,
         number: Option<usize>,
     ) {
         if let Some(k) = region {
@@ -162,24 +173,24 @@ pub fn maybe_highlighting_region(
     }
 
     /// Highlights the region inference variable `vid` as `'N`.
-    pub fn highlighting_region(&mut self, region: ty::Region<'_>, number: usize) {
+    pub fn highlighting_region(&mut self, region: ty::Region<'tcx>, number: usize) {
         let num_slots = self.highlight_regions.len();
         let first_avail_slot =
             self.highlight_regions.iter_mut().find(|s| s.is_none()).unwrap_or_else(|| {
                 bug!("can only highlight {} placeholders at a time", num_slots,)
             });
-        *first_avail_slot = Some((*region, number));
+        *first_avail_slot = Some((region, number));
     }
 
     /// Convenience wrapper for `highlighting_region`.
     pub fn highlighting_region_vid(&mut self, vid: ty::RegionVid, number: usize) {
-        self.highlighting_region(&ty::ReVar(vid), number)
+        self.highlighting_region(self.tcx.mk_region(ty::ReVar(vid)), number)
     }
 
     /// Returns `Some(n)` with the number to use for the given region, if any.
     fn region_highlighted(&self, region: ty::Region<'_>) -> Option<usize> {
         self.highlight_regions.iter().find_map(|h| match h {
-            Some((r, n)) if r == region => Some(*n),
+            Some((r, n)) if *r == region => Some(*n),
             _ => None,
         })
     }
@@ -743,14 +754,14 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                 p!("[", print(ty), "; ");
                 if self.tcx().sess.verbose() {
                     p!(write("{:?}", sz));
-                } else if let ty::ConstKind::Unevaluated(..) = sz.val {
+                } else if let ty::ConstKind::Unevaluated(..) = sz.val() {
                     // Do not try to evaluate unevaluated constants. If we are const evaluating an
                     // array length anon const, rustc will (with debug assertions) print the
                     // constant's path. Which will end up here again.
                     p!("_");
-                } else if let Some(n) = sz.val.try_to_bits(self.tcx().data_layout.pointer_size) {
+                } else if let Some(n) = sz.val().try_to_bits(self.tcx().data_layout.pointer_size) {
                     p!(write("{}", n));
-                } else if let ty::ConstKind::Param(param) = sz.val {
+                } else if let ty::ConstKind::Param(param) = sz.val() {
                     p!(write("{}", param));
                 } else {
                     p!("_");
@@ -1053,7 +1064,7 @@ fn pretty_print_dyn_existential(
 
                     // Don't print `'_` if there's no unerased regions.
                     let print_regions = args.iter().any(|arg| match arg.unpack() {
-                        GenericArgKind::Lifetime(r) => *r != ty::ReErased,
+                        GenericArgKind::Lifetime(r) => !r.is_erased(),
                         _ => false,
                     });
                     let mut args = args.iter().cloned().filter(|arg| match arg.unpack() {
@@ -1137,13 +1148,13 @@ fn pretty_fn_sig(
 
     fn pretty_print_const(
         mut self,
-        ct: &'tcx ty::Const<'tcx>,
+        ct: ty::Const<'tcx>,
         print_ty: bool,
     ) -> Result<Self::Const, Self::Error> {
         define_scoped_cx!(self);
 
         if self.tcx().sess.verbose() {
-            p!(write("Const({:?}: {:?})", ct.val, ct.ty));
+            p!(write("Const({:?}: {:?})", ct.val(), ct.ty()));
             return Ok(self);
         }
 
@@ -1155,7 +1166,7 @@ macro_rules! print_underscore {
                             write!(this, "_")?;
                             Ok(this)
                         },
-                        |this| this.print_type(ct.ty),
+                        |this| this.print_type(ct.ty()),
                         ": ",
                     )?;
                 } else {
@@ -1164,7 +1175,7 @@ macro_rules! print_underscore {
             }};
         }
 
-        match ct.val {
+        match ct.val() {
             ty::ConstKind::Unevaluated(ty::Unevaluated {
                 def,
                 substs,
@@ -1195,7 +1206,7 @@ macro_rules! print_underscore {
             ty::ConstKind::Infer(..) => print_underscore!(),
             ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
             ty::ConstKind::Value(value) => {
-                return self.pretty_print_const_value(value, ct.ty, print_ty);
+                return self.pretty_print_const_value(value, ct.ty(), print_ty);
             }
 
             ty::ConstKind::Bound(debruijn, bound_var) => {
@@ -1232,16 +1243,23 @@ fn pretty_print_const_scalar_ptr(
             // Byte strings (&[u8; N])
             ty::Ref(
                 _,
-                ty::TyS {
-                    kind:
-                        ty::Array(
-                            ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. },
-                            ty::Const {
-                                val: ty::ConstKind::Value(ConstValue::Scalar(int)), ..
-                            },
-                        ),
-                    ..
-                },
+                Ty(Interned(
+                    ty::TyS {
+                        kind:
+                            ty::Array(
+                                Ty(Interned(ty::TyS { kind: ty::Uint(ty::UintTy::U8), .. }, _)),
+                                ty::Const(Interned(
+                                    ty::ConstS {
+                                        val: ty::ConstKind::Value(ConstValue::Scalar(int)),
+                                        ..
+                                    },
+                                    _,
+                                )),
+                            ),
+                        ..
+                    },
+                    _,
+                )),
                 _,
             ) => match self.tcx().get_global_alloc(alloc_id) {
                 Some(GlobalAlloc::Memory(alloc)) => {
@@ -1399,7 +1417,7 @@ fn pretty_print_const_value(
             // Byte/string slices, printed as (byte) string literals.
             (
                 ConstValue::Slice { data, start, end },
-                ty::Ref(_, ty::TyS { kind: ty::Slice(t), .. }, _),
+                ty::Ref(_, Ty(Interned(ty::TyS { kind: ty::Slice(t), .. }, _)), _),
             ) if *t == u8_type => {
                 // The `inspect` here is okay since we checked the bounds, and there are
                 // no relocations (we have an active slice reference here). We don't use
@@ -1409,7 +1427,7 @@ fn pretty_print_const_value(
             }
             (
                 ConstValue::Slice { data, start, end },
-                ty::Ref(_, ty::TyS { kind: ty::Str, .. }, _),
+                ty::Ref(_, Ty(Interned(ty::TyS { kind: ty::Str, .. }, _)), _),
             ) => {
                 // The `inspect` here is okay since we checked the bounds, and there are no
                 // relocations (we have an active `str` reference here). We don't use this
@@ -1420,7 +1438,7 @@ fn pretty_print_const_value(
                 Ok(self)
             }
             (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
-                let n = n.val.try_to_bits(self.tcx().data_layout.pointer_size).unwrap();
+                let n = n.val().try_to_bits(self.tcx().data_layout.pointer_size).unwrap();
                 // cast is ok because we already checked for pointer size (32 or 64 bit) above
                 let range = AllocRange { start: offset, size: Size::from_bytes(n) };
 
@@ -1441,10 +1459,18 @@ fn pretty_print_const_value(
             // FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
             // correct `ty::ParamEnv` to allow printing *all* constant values.
             (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
-                let contents = self.tcx().destructure_const(
+                let Some(contents) = self.tcx().try_destructure_const(
                     ty::ParamEnv::reveal_all()
-                        .and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })),
-                );
+                        .and(self.tcx().mk_const(ty::ConstS { val: ty::ConstKind::Value(ct), ty })),
+                ) else {
+                    // Fall back to debug pretty printing for invalid constants.
+                    p!(write("{:?}", ct));
+                    if print_ty {
+                        p!(": ", print(ty));
+                    }
+                    return Ok(self);
+                };
+
                 let fields = contents.fields.iter().copied();
 
                 match *ty.kind() {
@@ -1531,7 +1557,7 @@ pub struct FmtPrinterData<'a, 'tcx, F> {
     binder_depth: usize,
     printed_type_count: usize,
 
-    pub region_highlight_mode: RegionHighlightMode,
+    pub region_highlight_mode: RegionHighlightMode<'tcx>,
 
     pub name_resolver: Option<Box<&'a dyn Fn(ty::TyVid) -> Option<String>>>,
 }
@@ -1561,7 +1587,7 @@ pub fn new(tcx: TyCtxt<'tcx>, fmt: F, ns: Namespace) -> Self {
             region_index: 0,
             binder_depth: 0,
             printed_type_count: 0,
-            region_highlight_mode: RegionHighlightMode::default(),
+            region_highlight_mode: RegionHighlightMode::new(tcx),
             name_resolver: None,
         }))
     }
@@ -1702,7 +1728,7 @@ fn print_dyn_existential(
         self.pretty_print_dyn_existential(predicates)
     }
 
-    fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+    fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
         self.pretty_print_const(ct, true)
     }
 
@@ -1797,7 +1823,7 @@ fn path_generic_args(
         // Don't print `'_` if there's no unerased regions.
         let print_regions = self.tcx.sess.verbose()
             || args.iter().any(|arg| match arg.unpack() {
-                GenericArgKind::Lifetime(r) => *r != ty::ReErased,
+                GenericArgKind::Lifetime(r) => !r.is_erased(),
                 _ => false,
             });
         let args = args.iter().cloned().filter(|arg| match arg.unpack() {
@@ -2056,7 +2082,7 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         let name = &mut self.name;
         let region = match *r {
-            ty::ReLateBound(_, br) => self.region_map.entry(br).or_insert_with(|| name(br)),
+            ty::ReLateBound(_, br) => *self.region_map.entry(br).or_insert_with(|| name(br)),
             ty::RePlaceholder(ty::PlaceholderRegion { name: kind, .. }) => {
                 // If this is an anonymous placeholder, don't rename. Otherwise, in some
                 // async fns, we get a `for<'r> Send` bound
@@ -2065,7 +2091,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
                     _ => {
                         // Index doesn't matter, since this is just for naming and these never get bound
                         let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
-                        self.region_map.entry(br).or_insert_with(|| name(br))
+                        *self.region_map.entry(br).or_insert_with(|| name(br))
                     }
                 }
             }
@@ -2267,7 +2293,7 @@ impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx
 
             #[instrument(skip(self), level = "trace")]
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-                trace!("address: {:p}", r);
+                trace!("address: {:p}", r.0.0);
                 if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
                     self.used_region_names.insert(name);
                 } else if let ty::RePlaceholder(ty::PlaceholderRegion {
@@ -2364,7 +2390,7 @@ fn print(&$self, $cx: P) -> Result<Self::Output, Self::Error> {
 }
 
 // HACK(eddyb) this is separate because `ty::RegionKind` doesn't need lifting.
-impl fmt::Display for ty::RegionKind {
+impl<'tcx> fmt::Display for ty::Region<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         ty::tls::with(|tcx| {
             self.print(FmtPrinter::new(tcx, f, Namespace::TypeNS))?;
@@ -2439,7 +2465,7 @@ pub fn print_modifiers_and_trait_path(
 forward_display_to_print! {
     Ty<'tcx>,
     &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
-    &'tcx ty::Const<'tcx>,
+    ty::Const<'tcx>,
 
     // HACK(eddyb) these are exhaustive instead of generic,
     // because `for<'tcx>` isn't possible yet.
index 040e642b7b6d6f102a7467b4748b8ff0935ca0fe..1688e59cdd12fe89fd7ba6858a9706691e2dc1f9 100644 (file)
@@ -106,6 +106,12 @@ pub fn try_mark_green(self, dep_node: &dep_graph::DepNode) -> bool {
 #[inline(always)]
 fn noop<T>(_: &T) {}
 
+/// Helper to ensure that queries only return `Copy` types.
+#[inline(always)]
+fn copy<T: Copy>(x: &T) -> T {
+    *x
+}
+
 macro_rules! query_helper_param_ty {
     (DefId) => { impl IntoQueryParam<DefId> };
     ($K:ty) => { $K };
@@ -243,7 +249,7 @@ pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> query_stored::$name<$
                 let key = key.into_query_param();
                 opt_remap_env_constness!([$($modifiers)*][key]);
 
-                let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, Clone::clone);
+                let cached = try_get_cached(self.tcx, &self.tcx.query_caches.$name, &key, copy);
 
                 let lookup = match cached {
                     Ok(value) => return value,
@@ -347,6 +353,13 @@ fn into_query_param(self) -> P {
         }
     }
 
+    impl<'a, P: Copy> IntoQueryParam<P> for &'a P {
+        #[inline(always)]
+        fn into_query_param(self) -> P {
+            *self
+        }
+    }
+
     impl IntoQueryParam<DefId> for LocalDefId {
         #[inline(always)]
         fn into_query_param(self) -> DefId {
index bb040acd2703d6e91db73855a38224eaa14b6eef..b59fb6afe6fe70eb23cc43729993ce8c28915a41 100644 (file)
@@ -89,9 +89,9 @@ fn regions(
 
     fn consts(
         &mut self,
-        a: &'tcx ty::Const<'tcx>,
-        b: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>>;
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>>;
 
     fn binders<T>(
         &mut self,
@@ -149,8 +149,8 @@ pub fn relate_substs<'tcx, R: TypeRelation<'tcx>>(
             Some((ty_def_id, variances)) => {
                 let variance = variances[i];
                 let variance_info = if variance == ty::Invariant {
-                    let ty =
-                        cached_ty.get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
+                    let ty = *cached_ty
+                        .get_or_insert_with(|| tcx.type_of(ty_def_id).subst(tcx, a_subst));
                     ty::VarianceDiagInfo::Invariant { ty, param_index: i.try_into().unwrap() }
                 } else {
                     ty::VarianceDiagInfo::default()
@@ -545,16 +545,16 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
 /// it.
 pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
     relation: &mut R,
-    a: &'tcx ty::Const<'tcx>,
-    b: &'tcx ty::Const<'tcx>,
-) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+    a: ty::Const<'tcx>,
+    b: ty::Const<'tcx>,
+) -> RelateResult<'tcx, ty::Const<'tcx>> {
     debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
     let tcx = relation.tcx();
 
     // FIXME(oli-obk): once const generics can have generic types, this assertion
     // will likely get triggered. Move to `normalize_erasing_regions` at that point.
-    let a_ty = tcx.erase_regions(a.ty);
-    let b_ty = tcx.erase_regions(b.ty);
+    let a_ty = tcx.erase_regions(a.ty());
+    let b_ty = tcx.erase_regions(b.ty());
     if a_ty != b_ty {
         relation.tcx().sess.delay_span_bug(
             DUMMY_SP,
@@ -562,14 +562,14 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
         );
     }
 
-    let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env());
+    let eagerly_eval = |x: ty::Const<'tcx>| x.eval(tcx, relation.param_env());
     let a = eagerly_eval(a);
     let b = eagerly_eval(b);
 
     // Currently, the values that can be unified are primitive types,
     // and those that derive both `PartialEq` and `Eq`, corresponding
     // to structural-match types.
-    let is_match = match (a.val, b.val) {
+    let is_match = match (a.val(), b.val()) {
         (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
             // The caller should handle these cases!
             bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
@@ -602,13 +602,13 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
                 au.substs,
                 bu.substs,
             )?;
-            return Ok(tcx.mk_const(ty::Const {
+            return Ok(tcx.mk_const(ty::ConstS {
                 val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                     def: au.def,
                     substs,
                     promoted: au.promoted,
                 }),
-                ty: a.ty,
+                ty: a.ty(),
             }));
         }
         _ => false,
@@ -621,8 +621,8 @@ fn check_const_value_eq<'tcx, R: TypeRelation<'tcx>>(
     a_val: ConstValue<'tcx>,
     b_val: ConstValue<'tcx>,
     // FIXME(oli-obk): these arguments should go away with valtrees
-    a: &'tcx ty::Const<'tcx>,
-    b: &'tcx ty::Const<'tcx>,
+    a: ty::Const<'tcx>,
+    b: ty::Const<'tcx>,
     // FIXME(oli-obk): this should just be `bool` with valtrees
 ) -> RelateResult<'tcx, bool> {
     let tcx = relation.tcx();
@@ -648,9 +648,9 @@ fn check_const_value_eq<'tcx, R: TypeRelation<'tcx>>(
         }
 
         (ConstValue::ByRef { alloc: alloc_a, .. }, ConstValue::ByRef { alloc: alloc_b, .. })
-            if a.ty.is_ref() || b.ty.is_ref() =>
+            if a.ty().is_ref() || b.ty().is_ref() =>
         {
-            if a.ty.is_ref() && b.ty.is_ref() {
+            if a.ty().is_ref() && b.ty().is_ref() {
                 alloc_a == alloc_b
             } else {
                 false
@@ -663,7 +663,7 @@ fn check_const_value_eq<'tcx, R: TypeRelation<'tcx>>(
             // Both the variant and each field have to be equal.
             if a_destructured.variant == b_destructured.variant {
                 for (a_field, b_field) in iter::zip(a_destructured.fields, b_destructured.fields) {
-                    relation.consts(a_field, b_field)?;
+                    relation.consts(*a_field, *b_field)?;
                 }
 
                 true
@@ -756,12 +756,12 @@ fn relate<R: TypeRelation<'tcx>>(
     }
 }
 
-impl<'tcx> Relate<'tcx> for &'tcx ty::Const<'tcx> {
+impl<'tcx> Relate<'tcx> for ty::Const<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
-        a: &'tcx ty::Const<'tcx>,
-        b: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         relation.consts(a, b)
     }
 }
index 1c5bc7860db2de7280f0446399e3f3ec796fa051..e4691dee7793a4a80e0dceca5b40835ab2a7ad77 100644 (file)
@@ -8,6 +8,7 @@
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt};
 use rustc_data_structures::functor::IdFunctor;
+use rustc_hir as hir;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::CRATE_DEF_INDEX;
 use rustc_index::vec::{Idx, IndexVec};
@@ -253,6 +254,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     crate::ty::UniverseIndex,
     crate::ty::Variance,
     ::rustc_span::Span,
+    ::rustc_errors::ErrorReported,
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -662,14 +664,6 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
 
 ///////////////////////////////////////////////////////////////////////////
 // TypeFoldable implementations.
-//
-// Ideally, each type should invoke `folder.fold_foo(self)` and
-// nothing else. In some cases, though, we haven't gotten around to
-// adding methods on the `folder` yet, and thus the folding is
-// hard-coded here. This is less-flexible, because folders cannot
-// override the behavior, but there are a lot of random types and one
-// can easily refactor the folding into the TypeFolder trait as
-// needed.
 
 /// AdtDefs are basically the same as a DefId.
 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::AdtDef {
@@ -1077,7 +1071,7 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
     }
 
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_ty(self)
+        visitor.visit_ty(*self)
     }
 }
 
@@ -1111,12 +1105,12 @@ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        let new = self.inner.kind.try_fold_with(folder)?;
+        let new = self.kind().try_fold_with(folder)?;
         Ok(folder.tcx().reuse_or_mk_predicate(self, new))
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.inner.kind.visit_with(visitor)
+        self.kind().visit_with(visitor)
     }
 
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
@@ -1124,11 +1118,11 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::Br
     }
 
     fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
-        self.inner.outer_exclusive_binder > binder
+        self.outer_exclusive_binder() > binder
     }
 
     fn has_type_flags(&self, flags: ty::TypeFlags) -> bool {
-        self.inner.flags.intersects(flags)
+        self.flags().intersects(flags)
     }
 }
 
@@ -1158,15 +1152,15 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Const<'tcx> {
+impl<'tcx> TypeFoldable<'tcx> for ty::Const<'tcx> {
     fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        let ty = self.ty.try_fold_with(folder)?;
-        let val = self.val.try_fold_with(folder)?;
-        if ty != self.ty || val != self.val {
-            Ok(folder.tcx().mk_const(ty::Const { ty, val }))
+        let ty = self.ty().try_fold_with(folder)?;
+        let val = self.val().try_fold_with(folder)?;
+        if ty != self.ty() || val != self.val() {
+            Ok(folder.tcx().mk_const(ty::ConstS { ty, val }))
         } else {
             Ok(self)
         }
@@ -1177,12 +1171,12 @@ fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Se
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        self.ty.visit_with(visitor)?;
-        self.val.visit_with(visitor)
+        self.ty().visit_with(visitor)?;
+        self.val().visit_with(visitor)
     }
 
     fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        visitor.visit_const(self)
+        visitor.visit_const(*self)
     }
 }
 
@@ -1269,3 +1263,13 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
         self.substs.visit_with(visitor)
     }
 }
+
+impl<'tcx> TypeFoldable<'tcx> for hir::Constness {
+    fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(self, _: &mut F) -> Result<Self, F::Error> {
+        Ok(self)
+    }
+
+    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> ControlFlow<V::BreakTy> {
+        ControlFlow::CONTINUE
+    }
+}
index 7d4af6cfa405257088c8e41bb3c1ed5cc89151b7..9835211a74865f6733e63645f9c28c6335cc476e 100644 (file)
@@ -9,9 +9,10 @@
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::InferTy::{self, *};
 use crate::ty::{self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable};
-use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
+use crate::ty::{DelaySpanBugEmitted, List, ParamEnv};
 use polonius_engine::Atom;
 use rustc_data_structures::captures::Captures;
+use rustc_data_structures::intern::Interned;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_index::vec::Idx;
@@ -21,8 +22,9 @@
 use rustc_target::spec::abi;
 use std::borrow::Cow;
 use std::cmp::Ordering;
+use std::fmt;
 use std::marker::PhantomData;
-use std::ops::Range;
+use std::ops::{Deref, Range};
 use ty::util::IntTypeExt;
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
@@ -74,10 +76,10 @@ pub fn is_named(&self) -> bool {
     }
 }
 
-/// Defines the kinds of types.
+/// Defines the kinds of types used by the type system.
 ///
-/// N.B., if you change this, you'll probably want to change the corresponding
-/// AST structure in `rustc_ast/src/ast.rs` as well.
+/// Types written by the user start out as [hir::TyKind](rustc_hir::TyKind) and get
+/// converted to this representation using `AstConv::ast_ty_to_ty`.
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable, Debug)]
 #[derive(HashStable)]
 #[rustc_diagnostic_item = "TyKind"]
@@ -100,10 +102,11 @@ pub enum TyKind<'tcx> {
 
     /// Algebraic data types (ADT). For example: structures, enumerations and unions.
     ///
-    /// InternalSubsts here, possibly against intuition, *may* contain `Param`s.
-    /// That is, even after substitution it is possible that there are type
-    /// variables. This happens when the `Adt` corresponds to an ADT
-    /// definition and not a concrete use of it.
+    /// For example, the type `List<i32>` would be represented using the `AdtDef`
+    /// for `struct List<T>` and the substs `[i32]`.
+    ///
+    /// Note that generic parameters in fields only get lazily substituted
+    /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, substs))`.
     Adt(&'tcx AdtDef, SubstsRef<'tcx>),
 
     /// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
@@ -112,8 +115,8 @@ pub enum TyKind<'tcx> {
     /// The pointee of a string slice. Written as `str`.
     Str,
 
-    /// An array with the given length. Written as `[T; n]`.
-    Array(Ty<'tcx>, &'tcx ty::Const<'tcx>),
+    /// An array with the given length. Written as `[T; N]`.
+    Array(Ty<'tcx>, ty::Const<'tcx>),
 
     /// The pointee of an array slice. Written as `[T]`.
     Slice(Ty<'tcx>),
@@ -126,11 +129,12 @@ pub enum TyKind<'tcx> {
     Ref(Region<'tcx>, Ty<'tcx>, hir::Mutability),
 
     /// The anonymous type of a function declaration/definition. Each
-    /// function has a unique type, which is output (for a function
-    /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
+    /// function has a unique type.
     ///
-    /// For example the type of `bar` here:
+    /// For the function `fn foo() -> i32 { 3 }` this type would be
+    /// shown to the user as `fn() -> i32 {foo}`.
     ///
+    /// For example the type of `bar` here:
     /// ```rust
     /// fn foo() -> i32 { 1 }
     /// let bar = foo; // bar: fn() -> i32 {foo}
@@ -139,6 +143,9 @@ pub enum TyKind<'tcx> {
 
     /// A pointer to a function. Written as `fn() -> i32`.
     ///
+    /// Note that both functions and closures start out as either
+    /// [FnDef] or [Closure] which can be then be coerced to this variant.
+    ///
     /// For example the type of `bar` here:
     ///
     /// ```rust
@@ -150,23 +157,48 @@ pub enum TyKind<'tcx> {
     /// A trait object. Written as `dyn for<'b> Trait<'b, Assoc = u32> + Send + 'a`.
     Dynamic(&'tcx List<Binder<'tcx, ExistentialPredicate<'tcx>>>, ty::Region<'tcx>),
 
-    /// The anonymous type of a closure. Used to represent the type of
-    /// `|a| a`.
+    /// The anonymous type of a closure. Used to represent the type of `|a| a`.
+    ///
+    /// Closure substs contain both the - potentially substituted - generic parameters
+    /// of its parent and some synthetic parameters. See the documentation for
+    /// [ClosureSubsts] for more details.
     Closure(DefId, SubstsRef<'tcx>),
 
     /// The anonymous type of a generator. Used to represent the type of
     /// `|a| yield a`.
+    ///
+    /// For more info about generator substs, visit the documentation for
+    /// [GeneratorSubsts].
     Generator(DefId, SubstsRef<'tcx>, hir::Movability),
 
     /// A type representing the types stored inside a generator.
-    /// This should only appear in GeneratorInteriors.
+    /// This should only appear as part of the [GeneratorSubsts].
+    ///
+    /// Note that the captured variables for generators are stored separately
+    /// using a tuple in the same way as for closures.
+    ///
+    /// Unlike upvars, the witness can reference lifetimes from
+    /// inside of the generator itself. To deal with them in
+    /// the type of the generator, we convert them to higher ranked
+    /// lifetimes bound by the witness itself.
+    ///
+    /// Looking at the following example, the witness for this generator
+    /// may end up as something like `for<'a> [Vec<i32>, &'a Vec<i32>]`:
+    ///
+    /// ```rust
+    /// |a| {
+    ///     let x = &vec![3];
+    ///     yield a;
+    ///     yield x[0];
+    /// }
+    /// ```
     GeneratorWitness(Binder<'tcx, &'tcx List<Ty<'tcx>>>),
 
     /// The never type `!`.
     Never,
 
     /// A tuple type. For example, `(i32, bool)`.
-    /// Use `TyS::tuple_fields` to iterate over the field types.
+    /// Use `Ty::tuple_fields` to iterate over the field types.
     Tuple(SubstsRef<'tcx>),
 
     /// The projection of an associated type. For example,
@@ -174,23 +206,44 @@ pub enum TyKind<'tcx> {
     Projection(ProjectionTy<'tcx>),
 
     /// Opaque (`impl Trait`) type found in a return type.
+    ///
     /// The `DefId` comes either from
     /// * the `impl Trait` ast::Ty node,
     /// * or the `type Foo = impl Trait` declaration
-    /// The substitutions are for the generics of the function in question.
-    /// After typeck, the concrete type can be found in the `types` map.
+    ///
+    /// For RPIT the substitutions are for the generics of the function,
+    /// while for TAIT it is used for the generic parameters of the alias.
+    ///
+    /// During codegen, `tcx.type_of(def_id)` can be used to get the underlying type.
     Opaque(DefId, SubstsRef<'tcx>),
 
     /// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
     Param(ParamTy),
 
-    /// Bound type variable, used only when preparing a trait query.
+    /// Bound type variable, used to represent the `'a` in `for<'a> fn(&'a ())`.
+    ///
+    /// For canonical queries, we replace inference variables with bound variables,
+    /// so e.g. when checking whether `&'_ (): Trait<_>` holds, we canonicalize that to
+    /// `for<'a, T> &'a (): Trait<T>` and then convert the introduced bound variables
+    /// back to inference variables in a new inference context when inside of the query.
+    ///
+    /// See the `rustc-dev-guide` for more details about
+    /// [higher-ranked trait bounds][1] and [canonical queries][2].
+    ///
+    /// [1]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
+    /// [2]: https://rustc-dev-guide.rust-lang.org/traits/canonical-queries.html
     Bound(ty::DebruijnIndex, BoundTy),
 
-    /// A placeholder type - universally quantified higher-ranked type.
+    /// A placeholder type, used during higher ranked subtyping to instantiate
+    /// bound variables.
     Placeholder(ty::PlaceholderType),
 
     /// A type variable used during type checking.
+    ///
+    /// Similar to placeholders, inference variables also live in a universe to
+    /// correctly deal with higher ranked types. Though unlike placeholders,
+    /// that universe is stored in the `InferCtxt` instead of directly
+    /// inside of the type.
     Infer(InferTy),
 
     /// A placeholder for a type which could not be computed; this is
@@ -231,7 +284,7 @@ pub fn article(&self) -> &'static str {
 ///   in scope on the function that defined the closure,
 /// - CK represents the *closure kind* (Fn vs FnMut vs FnOnce). This
 ///   is rather hackily encoded via a scalar type. See
-///   `TyS::to_opt_closure_kind` for details.
+///   `Ty::to_opt_closure_kind` for details.
 /// - CS represents the *closure signature*, representing as a `fn()`
 ///   type. For example, `fn(u32, u32) -> u32` would mean that the closure
 ///   implements `CK<(u32, u32), Output = u32>`, where `CK` is the trait
@@ -1340,7 +1393,24 @@ pub fn for_def(def: &ty::GenericParamDef) -> ParamConst {
     }
 }
 
-pub type Region<'tcx> = &'tcx RegionKind;
+/// Use this rather than `TyKind`, whenever possible.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, HashStable)]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
+pub struct Region<'tcx>(pub Interned<'tcx, RegionKind>);
+
+impl<'tcx> Deref for Region<'tcx> {
+    type Target = RegionKind;
+
+    fn deref(&self) -> &RegionKind {
+        &self.0.0
+    }
+}
+
+impl<'tcx> fmt::Debug for Region<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{:?}", self.kind())
+    }
+}
 
 /// Representation of regions. Note that the NLL checker uses a distinct
 /// representation of regions. For this reason, it internally replaces all the
@@ -1348,6 +1418,9 @@ pub fn for_def(def: &ty::GenericParamDef) -> ParamConst {
 /// to index into internal NLL data structures. See `rustc_const_eval::borrow_check`
 /// module for more information.
 ///
+/// Note: operations are on the wrapper `Region` type, which is interned,
+/// rather than this type.
+///
 /// ## The Region lattice within a given function
 ///
 /// In general, the region lattice looks like
@@ -1604,40 +1677,59 @@ pub fn item_def_id(&self) -> DefId {
 }
 
 /// Region utilities
-impl RegionKind {
+impl<'tcx> Region<'tcx> {
+    pub fn kind(self) -> RegionKind {
+        *self.0.0
+    }
+
     /// Is this region named by the user?
-    pub fn has_name(&self) -> bool {
+    pub fn has_name(self) -> bool {
         match *self {
-            RegionKind::ReEarlyBound(ebr) => ebr.has_name(),
-            RegionKind::ReLateBound(_, br) => br.kind.is_named(),
-            RegionKind::ReFree(fr) => fr.bound_region.is_named(),
-            RegionKind::ReStatic => true,
-            RegionKind::ReVar(..) => false,
-            RegionKind::RePlaceholder(placeholder) => placeholder.name.is_named(),
-            RegionKind::ReEmpty(_) => false,
-            RegionKind::ReErased => false,
+            ty::ReEarlyBound(ebr) => ebr.has_name(),
+            ty::ReLateBound(_, br) => br.kind.is_named(),
+            ty::ReFree(fr) => fr.bound_region.is_named(),
+            ty::ReStatic => true,
+            ty::ReVar(..) => false,
+            ty::RePlaceholder(placeholder) => placeholder.name.is_named(),
+            ty::ReEmpty(_) => false,
+            ty::ReErased => false,
         }
     }
 
     #[inline]
-    pub fn is_late_bound(&self) -> bool {
+    pub fn is_static(self) -> bool {
+        matches!(*self, ty::ReStatic)
+    }
+
+    #[inline]
+    pub fn is_erased(self) -> bool {
+        matches!(*self, ty::ReErased)
+    }
+
+    #[inline]
+    pub fn is_late_bound(self) -> bool {
         matches!(*self, ty::ReLateBound(..))
     }
 
     #[inline]
-    pub fn is_placeholder(&self) -> bool {
+    pub fn is_placeholder(self) -> bool {
         matches!(*self, ty::RePlaceholder(..))
     }
 
     #[inline]
-    pub fn bound_at_or_above_binder(&self, index: ty::DebruijnIndex) -> bool {
+    pub fn is_empty(self) -> bool {
+        matches!(*self, ty::ReEmpty(..))
+    }
+
+    #[inline]
+    pub fn bound_at_or_above_binder(self, index: ty::DebruijnIndex) -> bool {
         match *self {
             ty::ReLateBound(debruijn, _) => debruijn >= index,
             _ => false,
         }
     }
 
-    pub fn type_flags(&self) -> TypeFlags {
+    pub fn type_flags(self) -> TypeFlags {
         let mut flags = TypeFlags::empty();
 
         match *self {
@@ -1695,8 +1787,8 @@ pub fn type_flags(&self) -> TypeFlags {
     /// of the impl, and for all the other highlighted regions, it
     /// would return the `DefId` of the function. In other cases (not shown), this
     /// function might return the `DefId` of a closure.
-    pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_>) -> DefId {
-        match self {
+    pub fn free_region_binding_scope(self, tcx: TyCtxt<'_>) -> DefId {
+        match *self {
             ty::ReEarlyBound(br) => tcx.parent(br.def_id).unwrap(),
             ty::ReFree(fr) => fr.scope,
             _ => bug!("free_region_binding_scope invoked on inappropriate region: {:?}", self),
@@ -1705,19 +1797,19 @@ pub fn free_region_binding_scope(&self, tcx: TyCtxt<'_>) -> DefId {
 }
 
 /// Type utilities
-impl<'tcx> TyS<'tcx> {
+impl<'tcx> Ty<'tcx> {
     #[inline(always)]
-    pub fn kind(&self) -> &TyKind<'tcx> {
-        &self.kind
+    pub fn kind(self) -> &'tcx TyKind<'tcx> {
+        &self.0.0.kind
     }
 
     #[inline(always)]
-    pub fn flags(&self) -> TypeFlags {
-        self.flags
+    pub fn flags(self) -> TypeFlags {
+        self.0.0.flags
     }
 
     #[inline]
-    pub fn is_unit(&self) -> bool {
+    pub fn is_unit(self) -> bool {
         match self.kind() {
             Tuple(ref tys) => tys.is_empty(),
             _ => false,
@@ -1725,32 +1817,32 @@ pub fn is_unit(&self) -> bool {
     }
 
     #[inline]
-    pub fn is_never(&self) -> bool {
+    pub fn is_never(self) -> bool {
         matches!(self.kind(), Never)
     }
 
     #[inline]
-    pub fn is_primitive(&self) -> bool {
+    pub fn is_primitive(self) -> bool {
         self.kind().is_primitive()
     }
 
     #[inline]
-    pub fn is_adt(&self) -> bool {
+    pub fn is_adt(self) -> bool {
         matches!(self.kind(), Adt(..))
     }
 
     #[inline]
-    pub fn is_ref(&self) -> bool {
+    pub fn is_ref(self) -> bool {
         matches!(self.kind(), Ref(..))
     }
 
     #[inline]
-    pub fn is_ty_var(&self) -> bool {
+    pub fn is_ty_var(self) -> bool {
         matches!(self.kind(), Infer(TyVar(_)))
     }
 
     #[inline]
-    pub fn ty_vid(&self) -> Option<ty::TyVid> {
+    pub fn ty_vid(self) -> Option<ty::TyVid> {
         match self.kind() {
             &Infer(TyVar(vid)) => Some(vid),
             _ => None,
@@ -1758,28 +1850,28 @@ pub fn ty_vid(&self) -> Option<ty::TyVid> {
     }
 
     #[inline]
-    pub fn is_ty_infer(&self) -> bool {
+    pub fn is_ty_infer(self) -> bool {
         matches!(self.kind(), Infer(_))
     }
 
     #[inline]
-    pub fn is_phantom_data(&self) -> bool {
+    pub fn is_phantom_data(self) -> bool {
         if let Adt(def, _) = self.kind() { def.is_phantom_data() } else { false }
     }
 
     #[inline]
-    pub fn is_bool(&self) -> bool {
+    pub fn is_bool(self) -> bool {
         *self.kind() == Bool
     }
 
     /// Returns `true` if this type is a `str`.
     #[inline]
-    pub fn is_str(&self) -> bool {
+    pub fn is_str(self) -> bool {
         *self.kind() == Str
     }
 
     #[inline]
-    pub fn is_param(&self, index: u32) -> bool {
+    pub fn is_param(self, index: u32) -> bool {
         match self.kind() {
             ty::Param(ref data) => data.index == index,
             _ => false,
@@ -1787,7 +1879,7 @@ pub fn is_param(&self, index: u32) -> bool {
     }
 
     #[inline]
-    pub fn is_slice(&self) -> bool {
+    pub fn is_slice(self) -> bool {
         match self.kind() {
             RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_) | Str),
             _ => false,
@@ -1795,27 +1887,27 @@ pub fn is_slice(&self) -> bool {
     }
 
     #[inline]
-    pub fn is_array(&self) -> bool {
+    pub fn is_array(self) -> bool {
         matches!(self.kind(), Array(..))
     }
 
     #[inline]
-    pub fn is_simd(&self) -> bool {
+    pub fn is_simd(self) -> bool {
         match self.kind() {
             Adt(def, _) => def.repr.simd(),
             _ => false,
         }
     }
 
-    pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+    pub fn sequence_element_type(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match self.kind() {
-            Array(ty, _) | Slice(ty) => ty,
+            Array(ty, _) | Slice(ty) => *ty,
             Str => tcx.types.u8,
             _ => bug!("`sequence_element_type` called on non-sequence value: {}", self),
         }
     }
 
-    pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
+    pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
         match self.kind() {
             Adt(def, substs) => {
                 assert!(def.repr.simd(), "`simd_size_and_type` called on non-SIMD type");
@@ -1830,7 +1922,7 @@ pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
                         // The way we evaluate the `N` in `[T; N]` here only works since we use
                         // `simd_size_and_type` post-monomorphization. It will probably start to ICE
                         // if we use it in generic code. See the `simd-array-trait` ui test.
-                        (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, f0_elem_ty)
+                        (f0_len.eval_usize(tcx, ParamEnv::empty()) as u64, *f0_elem_ty)
                     }
                     // Otherwise, the fields of this Adt are the SIMD components (and we assume they
                     // all have the same type).
@@ -1842,12 +1934,12 @@ pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) {
     }
 
     #[inline]
-    pub fn is_region_ptr(&self) -> bool {
+    pub fn is_region_ptr(self) -> bool {
         matches!(self.kind(), Ref(..))
     }
 
     #[inline]
-    pub fn is_mutable_ptr(&self) -> bool {
+    pub fn is_mutable_ptr(self) -> bool {
         matches!(
             self.kind(),
             RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. })
@@ -1857,7 +1949,7 @@ pub fn is_mutable_ptr(&self) -> bool {
 
     /// Get the mutability of the reference or `None` when not a reference
     #[inline]
-    pub fn ref_mutability(&self) -> Option<hir::Mutability> {
+    pub fn ref_mutability(self) -> Option<hir::Mutability> {
         match self.kind() {
             Ref(_, _, mutability) => Some(*mutability),
             _ => None,
@@ -1865,18 +1957,18 @@ pub fn ref_mutability(&self) -> Option<hir::Mutability> {
     }
 
     #[inline]
-    pub fn is_unsafe_ptr(&self) -> bool {
+    pub fn is_unsafe_ptr(self) -> bool {
         matches!(self.kind(), RawPtr(_))
     }
 
     /// Tests if this is any kind of primitive pointer type (reference, raw pointer, fn pointer).
     #[inline]
-    pub fn is_any_ptr(&self) -> bool {
+    pub fn is_any_ptr(self) -> bool {
         self.is_region_ptr() || self.is_unsafe_ptr() || self.is_fn_ptr()
     }
 
     #[inline]
-    pub fn is_box(&self) -> bool {
+    pub fn is_box(self) -> bool {
         match self.kind() {
             Adt(def, _) => def.is_box(),
             _ => false,
@@ -1884,7 +1976,7 @@ pub fn is_box(&self) -> bool {
     }
 
     /// Panics if called on any type other than `Box<T>`.
-    pub fn boxed_ty(&self) -> Ty<'tcx> {
+    pub fn boxed_ty(self) -> Ty<'tcx> {
         match self.kind() {
             Adt(def, substs) if def.is_box() => substs.type_at(0),
             _ => bug!("`boxed_ty` is called on non-box type {:?}", self),
@@ -1895,7 +1987,7 @@ pub fn boxed_ty(&self) -> Ty<'tcx> {
     /// (A RawPtr is scalar because it represents a non-managed pointer, so its
     /// contents are abstract to rustc.)
     #[inline]
-    pub fn is_scalar(&self) -> bool {
+    pub fn is_scalar(self) -> bool {
         matches!(
             self.kind(),
             Bool | Char
@@ -1911,72 +2003,72 @@ pub fn is_scalar(&self) -> bool {
 
     /// Returns `true` if this type is a floating point type.
     #[inline]
-    pub fn is_floating_point(&self) -> bool {
+    pub fn is_floating_point(self) -> bool {
         matches!(self.kind(), Float(_) | Infer(FloatVar(_)))
     }
 
     #[inline]
-    pub fn is_trait(&self) -> bool {
+    pub fn is_trait(self) -> bool {
         matches!(self.kind(), Dynamic(..))
     }
 
     #[inline]
-    pub fn is_enum(&self) -> bool {
+    pub fn is_enum(self) -> bool {
         matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum())
     }
 
     #[inline]
-    pub fn is_union(&self) -> bool {
+    pub fn is_union(self) -> bool {
         matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union())
     }
 
     #[inline]
-    pub fn is_closure(&self) -> bool {
+    pub fn is_closure(self) -> bool {
         matches!(self.kind(), Closure(..))
     }
 
     #[inline]
-    pub fn is_generator(&self) -> bool {
+    pub fn is_generator(self) -> bool {
         matches!(self.kind(), Generator(..))
     }
 
     #[inline]
-    pub fn is_integral(&self) -> bool {
+    pub fn is_integral(self) -> bool {
         matches!(self.kind(), Infer(IntVar(_)) | Int(_) | Uint(_))
     }
 
     #[inline]
-    pub fn is_fresh_ty(&self) -> bool {
+    pub fn is_fresh_ty(self) -> bool {
         matches!(self.kind(), Infer(FreshTy(_)))
     }
 
     #[inline]
-    pub fn is_fresh(&self) -> bool {
+    pub fn is_fresh(self) -> bool {
         matches!(self.kind(), Infer(FreshTy(_) | FreshIntTy(_) | FreshFloatTy(_)))
     }
 
     #[inline]
-    pub fn is_char(&self) -> bool {
+    pub fn is_char(self) -> bool {
         matches!(self.kind(), Char)
     }
 
     #[inline]
-    pub fn is_numeric(&self) -> bool {
+    pub fn is_numeric(self) -> bool {
         self.is_integral() || self.is_floating_point()
     }
 
     #[inline]
-    pub fn is_signed(&self) -> bool {
+    pub fn is_signed(self) -> bool {
         matches!(self.kind(), Int(_))
     }
 
     #[inline]
-    pub fn is_ptr_sized_integral(&self) -> bool {
+    pub fn is_ptr_sized_integral(self) -> bool {
         matches!(self.kind(), Int(ty::IntTy::Isize) | Uint(ty::UintTy::Usize))
     }
 
     #[inline]
-    pub fn has_concrete_skeleton(&self) -> bool {
+    pub fn has_concrete_skeleton(self) -> bool {
         !matches!(self.kind(), Param(_) | Infer(_) | Error(_))
     }
 
@@ -1984,26 +2076,26 @@ pub fn has_concrete_skeleton(&self) -> bool {
     ///
     /// The parameter `explicit` indicates if this is an *explicit* dereference.
     /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly.
-    pub fn builtin_deref(&self, explicit: bool) -> Option<TypeAndMut<'tcx>> {
+    pub fn builtin_deref(self, explicit: bool) -> Option<TypeAndMut<'tcx>> {
         match self.kind() {
             Adt(def, _) if def.is_box() => {
                 Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not })
             }
-            Ref(_, ty, mutbl) => Some(TypeAndMut { ty, mutbl: *mutbl }),
+            Ref(_, ty, mutbl) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
             RawPtr(mt) if explicit => Some(*mt),
             _ => None,
         }
     }
 
     /// Returns the type of `ty[i]`.
-    pub fn builtin_index(&self) -> Option<Ty<'tcx>> {
+    pub fn builtin_index(self) -> Option<Ty<'tcx>> {
         match self.kind() {
-            Array(ty, _) | Slice(ty) => Some(ty),
+            Array(ty, _) | Slice(ty) => Some(*ty),
             _ => None,
         }
     }
 
-    pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
+    pub fn fn_sig(self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
         match self.kind() {
             FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs),
             FnPtr(f) => *f,
@@ -2019,22 +2111,22 @@ pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> {
     }
 
     #[inline]
-    pub fn is_fn(&self) -> bool {
+    pub fn is_fn(self) -> bool {
         matches!(self.kind(), FnDef(..) | FnPtr(_))
     }
 
     #[inline]
-    pub fn is_fn_ptr(&self) -> bool {
+    pub fn is_fn_ptr(self) -> bool {
         matches!(self.kind(), FnPtr(_))
     }
 
     #[inline]
-    pub fn is_impl_trait(&self) -> bool {
+    pub fn is_impl_trait(self) -> bool {
         matches!(self.kind(), Opaque(..))
     }
 
     #[inline]
-    pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> {
+    pub fn ty_adt_def(self) -> Option<&'tcx AdtDef> {
         match self.kind() {
             Adt(adt, _) => Some(adt),
             _ => None,
@@ -2043,7 +2135,7 @@ pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> {
 
     /// Iterates over tuple fields.
     /// Panics when called on anything but a tuple.
-    pub fn tuple_fields(&self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> {
+    pub fn tuple_fields(self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> {
         match self.kind() {
             Tuple(substs) => substs.iter().map(|field| field.expect_ty()),
             _ => bug!("tuple_fields called on non-tuple"),
@@ -2052,7 +2144,7 @@ pub fn tuple_fields(&self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> {
 
     /// Get the `i`-th element of a tuple.
     /// Panics when called on anything but a tuple.
-    pub fn tuple_element_ty(&self, i: usize) -> Option<Ty<'tcx>> {
+    pub fn tuple_element_ty(self, i: usize) -> Option<Ty<'tcx>> {
         match self.kind() {
             Tuple(substs) => substs.iter().nth(i).map(|field| field.expect_ty()),
             _ => bug!("tuple_fields called on non-tuple"),
@@ -2063,7 +2155,7 @@ pub fn tuple_element_ty(&self, i: usize) -> Option<Ty<'tcx>> {
     //
     // FIXME: This requires the optimized MIR in the case of generators.
     #[inline]
-    pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> {
+    pub fn variant_range(self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> {
         match self.kind() {
             TyKind::Adt(adt, _) => Some(adt.variant_range()),
             TyKind::Generator(def_id, substs, _) => {
@@ -2079,7 +2171,7 @@ pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option<Range<VariantIdx>> {
     // FIXME: This requires the optimized MIR in the case of generators.
     #[inline]
     pub fn discriminant_for_variant(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         variant_index: VariantIdx,
     ) -> Option<Discr<'tcx>> {
@@ -2100,7 +2192,7 @@ pub fn discriminant_for_variant(
     }
 
     /// Returns the type of the discriminant of this type.
-    pub fn discriminant_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+    pub fn discriminant_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match self.kind() {
             ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx),
             ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx),
@@ -2144,7 +2236,7 @@ pub fn discriminant_ty(&'tcx self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
 
     /// Returns the type of metadata for (potentially fat) pointers to this type.
     pub fn ptr_metadata_ty(
-        &'tcx self,
+        self,
         tcx: TyCtxt<'tcx>,
         normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
     ) -> Ty<'tcx> {
@@ -2205,7 +2297,7 @@ pub fn ptr_metadata_ty(
     /// to represent the closure kind, because it has not yet been
     /// inferred. Once upvar inference (in `rustc_typeck/src/check/upvar.rs`)
     /// is complete, that type variable will be unified.
-    pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
+    pub fn to_opt_closure_kind(self) -> Option<ty::ClosureKind> {
         match self.kind() {
             Int(int_ty) => match int_ty {
                 ty::IntTy::I8 => Some(ty::ClosureKind::Fn),
@@ -2234,7 +2326,7 @@ pub fn to_opt_closure_kind(&self) -> Option<ty::ClosureKind> {
     /// bound such as `[_]: Copy`. A function with such a bound obviously never
     /// can be called, but that doesn't mean it shouldn't typecheck. This is why
     /// this method doesn't return `Option<bool>`.
-    pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool {
+    pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
         match self.kind() {
             ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
             | ty::Uint(_)
index cf97344f18e76fd63ca42fdcf3bbd610985d7f9e..7dccef5e3ef0fa466388620c67057bab11e1eeff 100644 (file)
@@ -6,6 +6,7 @@
 use crate::ty::sty::{ClosureSubsts, GeneratorSubsts, InlineConstSubsts};
 use crate::ty::{self, Lift, List, ParamConst, Ty, TyCtxt};
 
+use rustc_data_structures::intern::Interned;
 use rustc_hir::def_id::DefId;
 use rustc_macros::HashStable;
 use rustc_serialize::{self, Decodable, Encodable};
 /// To reduce memory usage, a `GenericArg` is an interned pointer,
 /// with the lowest 2 bits being reserved for a tag to
 /// indicate the type (`Ty`, `Region`, or `Const`) it points to.
+///
+/// Note: the `PartialEq`, `Eq` and `Hash` derives are only valid because `Ty`,
+/// `Region` and `Const` are all interned.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 pub struct GenericArg<'tcx> {
     ptr: NonZeroUsize,
-    marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, &'tcx ty::Const<'tcx>)>,
+    marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>,
 }
 
 const TAG_MASK: usize = 0b11;
@@ -40,26 +44,27 @@ pub struct GenericArg<'tcx> {
 pub enum GenericArgKind<'tcx> {
     Lifetime(ty::Region<'tcx>),
     Type(Ty<'tcx>),
-    Const(&'tcx ty::Const<'tcx>),
+    Const(ty::Const<'tcx>),
 }
 
 impl<'tcx> GenericArgKind<'tcx> {
+    #[inline]
     fn pack(self) -> GenericArg<'tcx> {
         let (tag, ptr) = match self {
             GenericArgKind::Lifetime(lt) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(lt) & TAG_MASK, 0);
-                (REGION_TAG, lt as *const _ as usize)
+                assert_eq!(mem::align_of_val(lt.0.0) & TAG_MASK, 0);
+                (REGION_TAG, lt.0.0 as *const ty::RegionKind as usize)
             }
             GenericArgKind::Type(ty) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(ty) & TAG_MASK, 0);
-                (TYPE_TAG, ty as *const _ as usize)
+                assert_eq!(mem::align_of_val(ty.0.0) & TAG_MASK, 0);
+                (TYPE_TAG, ty.0.0 as *const ty::TyS<'tcx> as usize)
             }
             GenericArgKind::Const(ct) => {
                 // Ensure we can use the tag bits.
-                assert_eq!(mem::align_of_val(ct) & TAG_MASK, 0);
-                (CONST_TAG, ct as *const _ as usize)
+                assert_eq!(mem::align_of_val(ct.0.0) & TAG_MASK, 0);
+                (CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize)
             }
         };
 
@@ -90,19 +95,22 @@ fn partial_cmp(&self, other: &GenericArg<'_>) -> Option<Ordering> {
 }
 
 impl<'tcx> From<ty::Region<'tcx>> for GenericArg<'tcx> {
+    #[inline]
     fn from(r: ty::Region<'tcx>) -> GenericArg<'tcx> {
         GenericArgKind::Lifetime(r).pack()
     }
 }
 
 impl<'tcx> From<Ty<'tcx>> for GenericArg<'tcx> {
+    #[inline]
     fn from(ty: Ty<'tcx>) -> GenericArg<'tcx> {
         GenericArgKind::Type(ty).pack()
     }
 }
 
-impl<'tcx> From<&'tcx ty::Const<'tcx>> for GenericArg<'tcx> {
-    fn from(c: &'tcx ty::Const<'tcx>) -> GenericArg<'tcx> {
+impl<'tcx> From<ty::Const<'tcx>> for GenericArg<'tcx> {
+    #[inline]
+    fn from(c: ty::Const<'tcx>) -> GenericArg<'tcx> {
         GenericArgKind::Const(c).pack()
     }
 }
@@ -111,11 +119,20 @@ impl<'tcx> GenericArg<'tcx> {
     #[inline]
     pub fn unpack(self) -> GenericArgKind<'tcx> {
         let ptr = self.ptr.get();
+        // SAFETY: use of `Interned::new_unchecked` here is ok because these
+        // pointers were originally created from `Interned` types in `pack()`,
+        // and this is just going in the other direction.
         unsafe {
             match ptr & TAG_MASK {
-                REGION_TAG => GenericArgKind::Lifetime(&*((ptr & !TAG_MASK) as *const _)),
-                TYPE_TAG => GenericArgKind::Type(&*((ptr & !TAG_MASK) as *const _)),
-                CONST_TAG => GenericArgKind::Const(&*((ptr & !TAG_MASK) as *const _)),
+                REGION_TAG => GenericArgKind::Lifetime(ty::Region(Interned::new_unchecked(
+                    &*((ptr & !TAG_MASK) as *const ty::RegionKind),
+                ))),
+                TYPE_TAG => GenericArgKind::Type(Ty(Interned::new_unchecked(
+                    &*((ptr & !TAG_MASK) as *const ty::TyS<'tcx>),
+                ))),
+                CONST_TAG => GenericArgKind::Const(ty::Const(Interned::new_unchecked(
+                    &*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
+                ))),
                 _ => intrinsics::unreachable(),
             }
         }
@@ -132,7 +149,7 @@ pub fn expect_ty(self) -> Ty<'tcx> {
     }
 
     /// Unpack the `GenericArg` as a const when it is known certainly to be a const.
-    pub fn expect_const(self) -> &'tcx ty::Const<'tcx> {
+    pub fn expect_const(self) -> ty::Const<'tcx> {
         match self.unpack() {
             GenericArgKind::Const(c) => c,
             _ => bug!("expected a const, but found another kind"),
@@ -289,7 +306,7 @@ pub fn regions(&'a self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> +
     }
 
     #[inline]
-    pub fn consts(&'a self) -> impl DoubleEndedIterator<Item = &'tcx ty::Const<'tcx>> + 'a {
+    pub fn consts(&'a self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> + 'a {
         self.iter().filter_map(|k| {
             if let GenericArgKind::Const(ct) = k.unpack() { Some(ct) } else { None }
         })
@@ -324,7 +341,7 @@ pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
     }
 
     #[inline]
-    pub fn const_at(&self, i: usize) -> &'tcx ty::Const<'tcx> {
+    pub fn const_at(&self, i: usize) -> ty::Const<'tcx> {
         if let GenericArgKind::Const(ct) = self[i].unpack() {
             ct
         } else {
@@ -396,15 +413,7 @@ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
                 }
             }
             0 => Ok(self),
-            _ => {
-                let params: SmallVec<[_; 8]> =
-                    self.iter().map(|k| k.try_fold_with(folder)).collect::<Result<_, _>>()?;
-                if params[..] == self[..] {
-                    Ok(self)
-                } else {
-                    Ok(folder.tcx().intern_substs(&params))
-                }
-            }
+            _ => ty::util::fold_list(self, folder, |tcx, v| tcx.intern_substs(v)),
         }
     }
 
@@ -511,8 +520,8 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if let ty::ConstKind::Param(p) = c.val {
+    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        if let ty::ConstKind::Param(p) = c.val() {
             self.const_for_param(p, c)
         } else {
             c.super_fold_with(self)
@@ -561,11 +570,7 @@ fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
         self.shift_vars_through_binders(ty)
     }
 
-    fn const_for_param(
-        &self,
-        p: ParamConst,
-        source_ct: &'tcx ty::Const<'tcx>,
-    ) -> &'tcx ty::Const<'tcx> {
+    fn const_for_param(&self, p: ParamConst, source_ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         // Look up the const in the substitutions. It really should be in there.
         let opt_ct = self.substs.get(p.index as usize).map(|k| k.unpack());
         let ct = match opt_ct {
index 9e32c0162e6178e45a92ed6925585140916519f7..597f7dd95a211eb7f5eee85d603955ddb89986cf 100644 (file)
@@ -1,5 +1,5 @@
 use crate::traits::specialization_graph;
-use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
+use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
 use crate::ty::fold::TypeFoldable;
 use crate::ty::{Ident, Ty, TyCtxt};
 use rustc_hir as hir;
@@ -150,9 +150,7 @@ pub fn non_blanket_impls_for_ty(
         self_ty: Ty<'tcx>,
     ) -> impl Iterator<Item = DefId> + 'tcx {
         let impls = self.trait_impls_of(def_id);
-        if let Some(simp) =
-            fast_reject::simplify_type(self, self_ty, SimplifyParams::No, StripReferences::No)
-        {
+        if let Some(simp) = fast_reject::simplify_type(self, self_ty, SimplifyParams::No) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 return impls.iter().copied();
             }
@@ -189,9 +187,7 @@ pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>(
         // whose outer level is not a parameter or projection. Especially for things like
         // `T: Clone` this is incredibly useful as we would otherwise look at all the impls
         // of `Clone` for `Option<T>`, `Vec<T>`, `ConcreteType` and so on.
-        if let Some(simp) =
-            fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes, StripReferences::No)
-        {
+        if let Some(simp) = fast_reject::simplify_type(self, self_ty, SimplifyParams::Yes) {
             if let Some(impls) = impls.non_blanket_impls.get(&simp) {
                 for &impl_def_id in impls {
                     if let result @ Some(_) = f(impl_def_id) {
@@ -251,7 +247,7 @@ pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> Trait
         }
 
         if let Some(simplified_self_ty) =
-            fast_reject::simplify_type(tcx, impl_self_ty, SimplifyParams::No, StripReferences::No)
+            fast_reject::simplify_type(tcx, impl_self_ty, SimplifyParams::No)
         {
             impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id);
         } else {
index 3e3473bea0ed2e5f70b6f0b8f7e5921a9cc338d6..c2a4cea2b1ae66f09c132941ce0891e39f29a9f3 100644 (file)
@@ -5,12 +5,15 @@
 use crate::ty::layout::IntegerExt;
 use crate::ty::query::TyCtxtAt;
 use crate::ty::subst::{GenericArgKind, Subst, SubstsRef};
-use crate::ty::TyKind::*;
-use crate::ty::{self, DebruijnIndex, DefIdTree, List, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{
+    self, Const, DebruijnIndex, DefIdTree, List, ReEarlyBound, Region, Ty, TyCtxt, TyKind::*,
+    TypeFoldable,
+};
 use rustc_apfloat::Float as _;
 use rustc_ast as ast;
 use rustc_attr::{self as attr, SignedInt, UnsignedInt};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
@@ -389,15 +392,17 @@ pub fn destructor_constraints(self, def: &'tcx ty::AdtDef) -> Vec<ty::subst::Gen
         let result = iter::zip(item_substs, impl_substs)
             .filter(|&(_, k)| {
                 match k.unpack() {
-                    GenericArgKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => {
+                    GenericArgKind::Lifetime(Region(Interned(ReEarlyBound(ref ebr), _))) => {
                         !impl_generics.region_param(ebr, self).pure_wrt_drop
                     }
-                    GenericArgKind::Type(&ty::TyS { kind: ty::Param(ref pt), .. }) => {
-                        !impl_generics.type_param(pt, self).pure_wrt_drop
-                    }
-                    GenericArgKind::Const(&ty::Const {
-                        val: ty::ConstKind::Param(ref pc), ..
-                    }) => !impl_generics.const_param(pc, self).pure_wrt_drop,
+                    GenericArgKind::Type(Ty(Interned(
+                        ty::TyS { kind: ty::Param(ref pt), .. },
+                        _,
+                    ))) => !impl_generics.type_param(pt, self).pure_wrt_drop,
+                    GenericArgKind::Const(Const(Interned(
+                        ty::ConstS { val: ty::ConstKind::Param(ref pc), .. },
+                        _,
+                    ))) => !impl_generics.const_param(pc, self).pure_wrt_drop,
                     GenericArgKind::Lifetime(_)
                     | GenericArgKind::Type(_)
                     | GenericArgKind::Const(_) => {
@@ -577,7 +582,7 @@ fn expand_opaque_ty(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) -> Option
         let substs = substs.fold_with(self);
         if !self.check_recursion || self.seen_opaque_tys.insert(def_id) {
             let expanded_ty = match self.expanded_cache.get(&(def_id, substs)) {
-                Some(expanded_ty) => expanded_ty,
+                Some(expanded_ty) => *expanded_ty,
                 None => {
                     let generic_ty = self.tcx.type_of(def_id);
                     let concrete_ty = generic_ty.subst(self.tcx, substs);
@@ -606,7 +611,7 @@ fn tcx(&self) -> TyCtxt<'tcx> {
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if let ty::Opaque(def_id, substs) = t.kind {
+        if let ty::Opaque(def_id, substs) = *t.kind() {
             self.expand_opaque_ty(def_id, substs).unwrap_or(t)
         } else if t.has_opaque_types() {
             t.super_fold_with(self)
@@ -616,10 +621,10 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
     }
 }
 
-impl<'tcx> ty::TyS<'tcx> {
+impl<'tcx> Ty<'tcx> {
     /// Returns the maximum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
-    pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
+    pub fn numeric_max_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
         let val = match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
                 let (size, signed) = int_size_and_signed(tcx, self);
@@ -634,12 +639,12 @@ pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<
             }),
             _ => None,
         };
-        val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+        val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
     }
 
     /// Returns the minimum value for the given numeric type (including `char`s)
     /// or returns `None` if the type is not numeric.
-    pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> {
+    pub fn numeric_min_val(self, tcx: TyCtxt<'tcx>) -> Option<Const<'tcx>> {
         let val = match self.kind() {
             ty::Int(_) | ty::Uint(_) => {
                 let (size, signed) = int_size_and_signed(tcx, self);
@@ -653,7 +658,7 @@ pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<
             }),
             _ => None,
         };
-        val.map(|v| ty::Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
+        val.map(|v| Const::from_bits(tcx, v, ty::ParamEnv::empty().and(self)))
     }
 
     /// Checks whether values of this type `T` are *moved* or *copied*
@@ -664,7 +669,7 @@ pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<
     /// full requirements for the `Copy` trait (cc #29149) -- this
     /// winds up being reported as an error during NLL borrow check.
     pub fn is_copy_modulo_regions(
-        &'tcx self,
+        self,
         tcx_at: TyCtxtAt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) -> bool {
@@ -677,7 +682,7 @@ pub fn is_copy_modulo_regions(
     /// over-approximation in generic contexts, where one can have
     /// strange rules like `<T as Foo<'static>>::Bar: Sized` that
     /// actually carry lifetime requirements.
-    pub fn is_sized(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+    pub fn is_sized(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
         self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self))
     }
 
@@ -688,7 +693,7 @@ pub fn is_sized(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx
     /// optimization as well as the rules around static values. Note
     /// that the `Freeze` trait is not exposed to end users and is
     /// effectively an implementation detail.
-    pub fn is_freeze(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+    pub fn is_freeze(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
         self.is_trivially_freeze() || tcx_at.is_freeze_raw(param_env.and(self))
     }
 
@@ -696,7 +701,7 @@ pub fn is_freeze(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tc
     ///
     /// Returning true means the type is known to be `Freeze`. Returning
     /// `false` means nothing -- could be `Freeze`, might not be.
-    fn is_trivially_freeze(&self) -> bool {
+    fn is_trivially_freeze(self) -> bool {
         match self.kind() {
             ty::Int(_)
             | ty::Uint(_)
@@ -710,7 +715,7 @@ fn is_trivially_freeze(&self) -> bool {
             | ty::FnDef(..)
             | ty::Error(_)
             | ty::FnPtr(_) => true,
-            ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_freeze),
+            ty::Tuple(_) => self.tuple_fields().all(|f| Self::is_trivially_freeze(f)),
             ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(),
             ty::Adt(..)
             | ty::Bound(..)
@@ -728,7 +733,7 @@ fn is_trivially_freeze(&self) -> bool {
     }
 
     /// Checks whether values of this type `T` implement the `Unpin` trait.
-    pub fn is_unpin(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+    pub fn is_unpin(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
         self.is_trivially_unpin() || tcx_at.is_unpin_raw(param_env.and(self))
     }
 
@@ -736,7 +741,7 @@ pub fn is_unpin(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx
     ///
     /// Returning true means the type is known to be `Unpin`. Returning
     /// `false` means nothing -- could be `Unpin`, might not be.
-    fn is_trivially_unpin(&self) -> bool {
+    fn is_trivially_unpin(self) -> bool {
         match self.kind() {
             ty::Int(_)
             | ty::Uint(_)
@@ -750,7 +755,7 @@ fn is_trivially_unpin(&self) -> bool {
             | ty::FnDef(..)
             | ty::Error(_)
             | ty::FnPtr(_) => true,
-            ty::Tuple(_) => self.tuple_fields().all(Self::is_trivially_unpin),
+            ty::Tuple(_) => self.tuple_fields().all(|f| Self::is_trivially_unpin(f)),
             ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_unpin(),
             ty::Adt(..)
             | ty::Bound(..)
@@ -776,7 +781,7 @@ fn is_trivially_unpin(&self) -> bool {
     ///
     /// Note that this method is used to check eligible types in unions.
     #[inline]
-    pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+    pub fn needs_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
         // Avoid querying in simple cases.
         match needs_drop_components(self, &tcx.data_layout) {
             Err(AlwaysRequiresDrop) => true,
@@ -809,11 +814,7 @@ pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>)
     /// Note that this method is used to check for change in drop order for
     /// 2229 drop reorder migration analysis.
     #[inline]
-    pub fn has_significant_drop(
-        &'tcx self,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> bool {
+    pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
         // Avoid querying in simple cases.
         match needs_drop_components(self, &tcx.data_layout) {
             Err(AlwaysRequiresDrop) => true,
@@ -858,7 +859,7 @@ pub fn has_significant_drop(
     /// want to know whether a given call to `PartialEq::eq` will proceed structurally all the way
     /// down, you will need to use a type visitor.
     #[inline]
-    pub fn is_structural_eq_shallow(&'tcx self, tcx: TyCtxt<'tcx>) -> bool {
+    pub fn is_structural_eq_shallow(self, tcx: TyCtxt<'tcx>) -> bool {
         match self.kind() {
             // Look for an impl of both `PartialStructuralEq` and `StructuralEq`.
             Adt(..) => tcx.has_structural_eq_impls(self),
@@ -903,16 +904,16 @@ pub fn is_structural_eq_shallow(&'tcx self, tcx: TyCtxt<'tcx>) -> bool {
     /// - `&'a mut u8` -> `u8`
     /// - `&'a &'b u8` -> `u8`
     /// - `&'a *const &'b u8 -> *const &'b u8`
-    pub fn peel_refs(&'tcx self) -> Ty<'tcx> {
+    pub fn peel_refs(self) -> Ty<'tcx> {
         let mut ty = self;
         while let Ref(_, inner_ty, _) = ty.kind() {
-            ty = inner_ty;
+            ty = *inner_ty;
         }
         ty
     }
 
-    pub fn outer_exclusive_binder(&'tcx self) -> DebruijnIndex {
-        self.outer_exclusive_binder
+    pub fn outer_exclusive_binder(self) -> DebruijnIndex {
+        self.0.outer_exclusive_binder
     }
 }
 
@@ -993,11 +994,11 @@ pub fn needs_drop_components<'tcx>(
 
         ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop),
 
-        ty::Slice(ty) => needs_drop_components(ty, target_layout),
+        ty::Slice(ty) => needs_drop_components(*ty, target_layout),
         ty::Array(elem_ty, size) => {
-            match needs_drop_components(elem_ty, target_layout) {
+            match needs_drop_components(*elem_ty, target_layout) {
                 Ok(v) if v.is_empty() => Ok(v),
-                res => match size.val.try_to_bits(target_layout.pointer_size) {
+                res => match size.val().try_to_bits(target_layout.pointer_size) {
                     // Arrays of size zero don't need drop, even if their element
                     // type does.
                     Some(0) => Ok(SmallVec::new()),
index 38aa76333851f76007966ce0738f9aa323942ca4..ab70c15160ca6e09749f3aab0dfe5e8e6fdfd50e 100644 (file)
@@ -1,8 +1,8 @@
 //! An iterator over the type substructure.
 //! WARNING: this does not keep track of the region depth.
 
-use crate::ty;
 use crate::ty::subst::{GenericArg, GenericArgKind};
+use crate::ty::{self, Ty};
 use rustc_data_structures::sso::SsoHashSet;
 use smallvec::{self, SmallVec};
 
@@ -96,7 +96,7 @@ pub fn walk_shallow(
     }
 }
 
-impl<'tcx> super::TyS<'tcx> {
+impl<'tcx> Ty<'tcx> {
     /// Iterator that walks `self` and any types reachable from
     /// `self`, in depth-first order. Note that just walks the types
     /// that appear in `self`, it does not descend into the fields of
@@ -107,7 +107,7 @@ impl<'tcx> super::TyS<'tcx> {
     /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
     /// [isize] => { [isize], isize }
     /// ```
-    pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
+    pub fn walk(self) -> TypeWalker<'tcx> {
         TypeWalker::new(self.into())
     }
 }
@@ -189,8 +189,8 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
         },
         GenericArgKind::Lifetime(_) => {}
         GenericArgKind::Const(parent_ct) => {
-            stack.push(parent_ct.ty.into());
-            match parent_ct.val {
+            stack.push(parent_ct.ty().into());
+            match parent_ct.val() {
                 ty::ConstKind::Infer(_)
                 | ty::ConstKind::Param(_)
                 | ty::ConstKind::Placeholder(_)
index 5e305ebba2ff46df57b1501d2e78ea6713baf86d..0c0b0f2bd05affc985dad8dd83c21e488da36c4c 100644 (file)
@@ -1,6 +1,7 @@
 //! See docs in build/expr/mod.rs
 
 use crate::build::Builder;
+use rustc_middle::mir::interpret::{ConstValue, Scalar};
 use rustc_middle::mir::*;
 use rustc_middle::thir::*;
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
@@ -23,11 +24,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         inferred_ty: ty,
                     })
                 });
-                assert_eq!(literal.ty, ty);
+                assert_eq!(literal.ty(), ty);
                 Constant { span, user_ty, literal: literal.into() }
             }
-            ExprKind::StaticRef { literal, .. } => {
-                Constant { span, user_ty: None, literal: literal.into() }
+            ExprKind::StaticRef { alloc_id, ty, .. } => {
+                let const_val =
+                    ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &this.tcx));
+                let literal = ConstantKind::Val(const_val, ty);
+
+                Constant { span, user_ty: None, literal }
             }
             ExprKind::ConstBlock { value } => {
                 Constant { span: span, user_ty: None, literal: value.into() }
index da8fbdbf3bce4b2e72434a639a5d03b5a377ff13..c706e6ef1d4664eacb472ce3f01c0a2577d20f9c 100644 (file)
@@ -348,7 +348,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 let place_builder = place_builder.clone();
                                 this.consume_by_copy_or_move(
                                     place_builder
-                                        .field(n, ty)
+                                        .field(n, *ty)
                                         .into_place(this.tcx, this.typeck_results),
                                 )
                             }
index 6329bcee4fa3f1c6eb4e12c4c53d73439f5f71dd..ec8cb30965d75467d0a6a1e2a26f19361ef61c25 100644 (file)
@@ -264,7 +264,7 @@ fn lower_match_tree<'pat>(
         // The set of places that we are creating fake borrows of. If there are
         // no match guards then we don't need any fake borrows, so don't track
         // them.
-        let mut fake_borrows = if match_has_guard { Some(FxHashSet::default()) } else { None };
+        let mut fake_borrows = match_has_guard.then(FxHashSet::default);
 
         let mut otherwise = None;
 
@@ -964,13 +964,13 @@ enum TestKind<'tcx> {
         ///
         /// For `bool` we always generate two edges, one for `true` and one for
         /// `false`.
-        options: FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
+        options: FxIndexMap<ty::Const<'tcx>, u128>,
     },
 
     /// Test for equality with value, possibly after an unsizing coercion to
     /// `ty`,
     Eq {
-        value: &'tcx ty::Const<'tcx>,
+        value: ty::Const<'tcx>,
         // Integer types are handled by `SwitchInt`, and constants with ADT
         // types are converted back into patterns, so this can only be `&str`,
         // `&[T]`, `f32` or `f64`.
index 4ce26cc8dff46a10f4ecde92cba0feb3833425ac..4f9a2c0ce779da4e53ea14d374ce0692ffa4e339 100644 (file)
@@ -210,7 +210,7 @@ fn simplify_match_pair<'pat>(
             }
 
             PatKind::Range(PatRange { lo, hi, end }) => {
-                let (range, bias) = match *lo.ty.kind() {
+                let (range, bias) = match *lo.ty().kind() {
                     ty::Char => {
                         (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0)
                     }
@@ -228,7 +228,9 @@ fn simplify_match_pair<'pat>(
                     _ => (None, 0),
                 };
                 if let Some((min, max, sz)) = range {
-                    if let (Some(lo), Some(hi)) = (lo.val.try_to_bits(sz), hi.val.try_to_bits(sz)) {
+                    if let (Some(lo), Some(hi)) =
+                        (lo.val().try_to_bits(sz), hi.val().try_to_bits(sz))
+                    {
                         // We want to compare ranges numerically, but the order of the bitwise
                         // representation of signed integers does not match their numeric order.
                         // Thus, to correct the ordering, we need to shift the range of signed
index 49cd21c2137b78c32dd3adb88918c2f73d847a8d..ce848773b10cc6c1fb965ed8afa626ea13d0016e 100644 (file)
@@ -59,8 +59,8 @@ pub(super) fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<
             },
 
             PatKind::Range(range) => {
-                assert_eq!(range.lo.ty, match_pair.pattern.ty);
-                assert_eq!(range.hi.ty, match_pair.pattern.ty);
+                assert_eq!(range.lo.ty(), match_pair.pattern.ty);
+                assert_eq!(range.hi.ty(), match_pair.pattern.ty);
                 Test { span: match_pair.pattern.span, kind: TestKind::Range(range) }
             }
 
@@ -86,7 +86,7 @@ pub(super) fn add_cases_to_switch<'pat>(
         test_place: &PlaceBuilder<'tcx>,
         candidate: &Candidate<'pat, 'tcx>,
         switch_ty: Ty<'tcx>,
-        options: &mut FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
+        options: &mut FxIndexMap<ty::Const<'tcx>, u128>,
     ) -> bool {
         let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place) else {
             return false;
@@ -266,7 +266,7 @@ pub(super) fn perform_test(
                         ty,
                     );
                 } else if let [success, fail] = *make_target_blocks(self) {
-                    assert_eq!(value.ty, ty);
+                    assert_eq!(value.ty(), ty);
                     let expect = self.literal_operand(test.span, value);
                     let val = Operand::Copy(place);
                     self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
@@ -275,7 +275,7 @@ pub(super) fn perform_test(
                 }
             }
 
-            TestKind::Range(PatRange { ref lo, ref hi, ref end }) => {
+            TestKind::Range(PatRange { lo, hi, ref end }) => {
                 let lower_bound_success = self.cfg.start_new_block();
                 let target_blocks = make_target_blocks(self);
 
@@ -369,7 +369,7 @@ fn non_scalar_compare(
         block: BasicBlock,
         make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
         source_info: SourceInfo,
-        value: &'tcx ty::Const<'tcx>,
+        value: ty::Const<'tcx>,
         place: Place<'tcx>,
         mut ty: Ty<'tcx>,
     ) {
@@ -390,14 +390,14 @@ fn non_scalar_compare(
             _ => None,
         };
         let opt_ref_ty = unsize(ty);
-        let opt_ref_test_ty = unsize(value.ty);
+        let opt_ref_test_ty = unsize(value.ty());
         match (opt_ref_ty, opt_ref_test_ty) {
             // nothing to do, neither is an array
             (None, None) => {}
             (Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => {
                 let tcx = self.tcx;
                 // make both a slice
-                ty = tcx.mk_imm_ref(region, tcx.mk_slice(elem_ty));
+                ty = tcx.mk_imm_ref(*region, tcx.mk_slice(*elem_ty));
                 if opt_ref_ty.is_some() {
                     let temp = self.temp(ty, source_info.span);
                     self.cfg.push_assign(
@@ -646,7 +646,7 @@ pub(super) fn sort_candidate<'pat>(
 
                     let tcx = self.tcx;
 
-                    let test_ty = test.lo.ty;
+                    let test_ty = test.lo.ty();
                     let lo = compare_const_vals(tcx, test.lo, pat.hi, self.param_env, test_ty)?;
                     let hi = compare_const_vals(tcx, test.hi, pat.lo, self.param_env, test_ty)?;
 
@@ -764,17 +764,13 @@ fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> !
         span_bug!(match_pair.pattern.span, "simplifyable pattern found: {:?}", match_pair.pattern)
     }
 
-    fn const_range_contains(
-        &self,
-        range: PatRange<'tcx>,
-        value: &'tcx ty::Const<'tcx>,
-    ) -> Option<bool> {
+    fn const_range_contains(&self, range: PatRange<'tcx>, value: ty::Const<'tcx>) -> Option<bool> {
         use std::cmp::Ordering::*;
 
         let tcx = self.tcx;
 
-        let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty)?;
-        let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty)?;
+        let a = compare_const_vals(tcx, range.lo, value, self.param_env, range.lo.ty())?;
+        let b = compare_const_vals(tcx, value, range.hi, self.param_env, range.lo.ty())?;
 
         match (b, range.end) {
             (Less, _) | (Equal, RangeEnd::Included) if a != Greater => Some(true),
@@ -785,7 +781,7 @@ fn const_range_contains(
     fn values_not_contained_in_range(
         &self,
         range: PatRange<'tcx>,
-        options: &FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
+        options: &FxIndexMap<ty::Const<'tcx>, u128>,
     ) -> Option<bool> {
         for &val in options.keys() {
             if self.const_range_contains(range, val)? {
@@ -831,7 +827,7 @@ fn trait_method<'tcx>(
     method_name: Symbol,
     self_ty: Ty<'tcx>,
     params: &[GenericArg<'tcx>],
-) -> &'tcx ty::Const<'tcx> {
+) -> ty::Const<'tcx> {
     let substs = tcx.mk_substs_trait(self_ty, params);
 
     // The unhygienic comparison here is acceptable because this is only
index 78047daf0ad00f52770da2254b4d0645c503f4a1..fd5914460140a84044acf8c62b889c51d56a0f07 100644 (file)
@@ -25,11 +25,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     /// Convenience function for creating a literal operand, one
     /// without any user type annotation.
-    crate fn literal_operand(
-        &mut self,
-        span: Span,
-        literal: &'tcx ty::Const<'tcx>,
-    ) -> Operand<'tcx> {
+    crate fn literal_operand(&mut self, span: Span, literal: ty::Const<'tcx>) -> Operand<'tcx> {
         let literal = literal.into();
         let constant = Box::new(Constant { span, user_ty: None, literal });
         Operand::Constant(constant)
index e2a42de71b956701da9f1a490964b6a634b229f7..fb403615e572f51755aab74c341b65a84fbc6d16 100644 (file)
@@ -104,8 +104,8 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
     let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id));
 
     tcx.infer_ctxt().enter(|infcx| {
-        let body = if let Some(ErrorReported) = typeck_results.tainted_by_errors {
-            build::construct_error(&infcx, def, id, body_id, body_owner_kind)
+        let body = if let Some(error_reported) = typeck_results.tainted_by_errors {
+            build::construct_error(&infcx, def, id, body_id, body_owner_kind, error_reported)
         } else if body_owner_kind.is_fn_or_closure() {
             // fetch the fully liberated fn signature (that is, all bound
             // types/lifetimes replaced)
@@ -715,6 +715,7 @@ fn construct_error<'a, 'tcx>(
     hir_id: hir::HirId,
     body_id: hir::BodyId,
     body_owner_kind: hir::BodyOwnerKind,
+    err: ErrorReported,
 ) -> Body<'tcx> {
     let tcx = infcx.tcx;
     let span = tcx.hir().span(hir_id);
@@ -769,6 +770,7 @@ fn construct_error<'a, 'tcx>(
         vec![],
         span,
         generator_kind,
+        Some(err),
     );
     body.generator.as_mut().map(|gen| gen.yield_ty = Some(ty));
     body
@@ -857,6 +859,7 @@ fn finish(self) -> Body<'tcx> {
             self.var_debug_info,
             self.fn_span,
             self.generator_kind,
+            self.typeck_results.tainted_by_errors,
         )
     }
 
@@ -900,7 +903,7 @@ fn args_and_body(
             let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
             if let ty::Ref(_, ty, _) = closure_ty.kind() {
                 closure_env_projs.push(ProjectionElem::Deref);
-                closure_ty = ty;
+                closure_ty = *ty;
             }
             let upvar_substs = match closure_ty.kind() {
                 ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
@@ -935,7 +938,7 @@ fn args_and_body(
                     };
 
                     self.var_debug_info.push(VarDebugInfo {
-                        name: sym,
+                        name: *sym,
                         source_info: SourceInfo::outermost(tcx_hir.span(var_id)),
                         value: VarDebugInfoContents::Place(Place {
                             local: ty::CAPTURE_STRUCT_LOCAL,
index 9b54db0d7de86534a4fe8c12e3072b97d8c54a90..ec2ff3c37ab73526d852ae95dd6e627ec0af8508 100644 (file)
@@ -10,7 +10,7 @@
 crate fn lit_to_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     lit_input: LitToConstInput<'tcx>,
-) -> Result<&'tcx ty::Const<'tcx>, LitToConstError> {
+) -> Result<ty::Const<'tcx>, LitToConstError> {
     let LitToConstInput { lit, ty, neg } = lit_input;
 
     let trunc = |n| {
index 374e6ef87a7402f9ed1679b65ad4427d0dd9b995..829dec74803dd9e0d83bbdd70fde506c750460bf 100644 (file)
@@ -8,7 +8,6 @@
 use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::middle::region;
-use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp};
 use rustc_middle::thir::*;
 use rustc_middle::ty::adjustment::{
@@ -583,7 +582,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                     _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty),
                 };
 
-                ExprKind::Repeat { value: self.mirror_expr(v), count }
+                ExprKind::Repeat { value: self.mirror_expr(v), count: *count }
             }
             hir::ExprKind::Ret(ref v) => {
                 ExprKind::Return { value: v.as_ref().map(|v| self.mirror_expr(v)) }
@@ -708,7 +707,7 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                                 // in case we are offsetting from a computed discriminant
                                 // and not the beginning of discriminants (which is always `0`)
                                 let substs = InternalSubsts::identity_for_item(self.tcx(), did);
-                                let lhs = ty::Const {
+                                let lhs = ty::ConstS {
                                     val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(
                                         ty::WithOptConstParam::unknown(did),
                                         substs,
@@ -890,7 +889,7 @@ fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKi
                 let name = self.tcx.hir().name(hir_id);
                 let val = ty::ConstKind::Param(ty::ParamConst::new(index, name));
                 ExprKind::Literal {
-                    literal: self.tcx.mk_const(ty::Const {
+                    literal: self.tcx.mk_const(ty::ConstS {
                         val,
                         ty: self.typeck_results().node_type(expr.hir_id),
                     }),
@@ -903,7 +902,7 @@ fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKi
                 let user_ty = self.user_substs_applied_to_res(expr.hir_id, res);
                 debug!("convert_path_expr: (const) user_ty={:?}", user_ty);
                 ExprKind::Literal {
-                    literal: self.tcx.mk_const(ty::Const {
+                    literal: self.tcx.mk_const(ty::ConstS {
                         val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(
                             ty::WithOptConstParam::unknown(def_id),
                             substs,
@@ -943,15 +942,8 @@ fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKi
                 let kind = if self.tcx.is_thread_local_static(id) {
                     ExprKind::ThreadLocalRef(id)
                 } else {
-                    let ptr = self.tcx.create_static_alloc(id);
-                    ExprKind::StaticRef {
-                        literal: ty::Const::from_scalar(
-                            self.tcx,
-                            Scalar::from_pointer(ptr.into(), &self.tcx),
-                            ty,
-                        ),
-                        def_id: id,
-                    }
+                    let alloc_id = self.tcx.create_static_alloc(id);
+                    ExprKind::StaticRef { alloc_id, ty, def_id: id }
                 };
                 ExprKind::Deref {
                     arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }),
index 38a4676bd1561c869bbbb79f0ea8f01bf9061eb7..a65a3ed31f638c8536edd79c8188c64ec3e39d8d 100644 (file)
@@ -79,7 +79,7 @@ fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> {
         ty: Ty<'tcx>,
         sp: Span,
         neg: bool,
-    ) -> &'tcx ty::Const<'tcx> {
+    ) -> ty::Const<'tcx> {
         trace!("const_eval_literal: {:#?}, {:?}, {:?}, {:?}", lit, ty, sp, neg);
 
         match self.tcx.at(sp).lit_to_const(LitToConstInput { lit, ty, neg }) {
index 34204c3852ad0842e839fa1bb21368019ecaa780..d357ac6930266914bd84de97c4ef3f63125002b2 100644 (file)
@@ -556,7 +556,7 @@ fn non_exhaustive_match<'p, 'tcx>(
         }
     }
     if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() {
-        if cx.tcx.is_ty_uninhabited_from(cx.module, sub_ty, cx.param_env) {
+        if cx.tcx.is_ty_uninhabited_from(cx.module, *sub_ty, cx.param_env) {
             err.note("references are always considered inhabited");
         }
     }
index d8c9a6fa3fe969d8cbb15a08c71d44f7b4365740..7db71ed598d932ec73ca3c56ffa9dff1554269bd 100644 (file)
@@ -22,7 +22,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     #[instrument(level = "debug", skip(self))]
     pub(super) fn const_to_pat(
         &self,
-        cv: &'tcx ty::Const<'tcx>,
+        cv: ty::Const<'tcx>,
         id: hir::HirId,
         span: Span,
         mir_structural_match_violation: bool,
@@ -152,11 +152,7 @@ fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
         ty.is_structural_eq_shallow(self.infcx.tcx)
     }
 
-    fn to_pat(
-        &mut self,
-        cv: &'tcx ty::Const<'tcx>,
-        mir_structural_match_violation: bool,
-    ) -> Pat<'tcx> {
+    fn to_pat(&mut self, cv: ty::Const<'tcx>, mir_structural_match_violation: bool) -> Pat<'tcx> {
         trace!(self.treat_byte_string_as_slice);
         // This method is just a wrapper handling a validity check; the heavy lifting is
         // performed by the recursive `recur` method, which is not meant to be
@@ -171,10 +167,11 @@ fn to_pat(
             // If we were able to successfully convert the const to some pat,
             // double-check that all types in the const implement `Structural`.
 
-            let structural = self.search_for_structural_match_violation(cv.ty);
+            let structural = self.search_for_structural_match_violation(cv.ty());
             debug!(
                 "search_for_structural_match_violation cv.ty: {:?} returned: {:?}",
-                cv.ty, structural
+                cv.ty(),
+                structural
             );
 
             // This can occur because const qualification treats all associated constants as
@@ -189,7 +186,7 @@ fn to_pat(
             }
 
             if let Some(msg) = structural {
-                if !self.type_may_have_partial_eq_impl(cv.ty) {
+                if !self.type_may_have_partial_eq_impl(cv.ty()) {
                     // span_fatal avoids ICE from resolution of non-existent method (rare case).
                     self.tcx().sess.span_fatal(self.span, &msg);
                 } else if mir_structural_match_violation && !self.saw_const_match_lint.get() {
@@ -247,7 +244,7 @@ fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
 
     fn field_pats(
         &self,
-        vals: impl Iterator<Item = &'tcx ty::Const<'tcx>>,
+        vals: impl Iterator<Item = ty::Const<'tcx>>,
     ) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> {
         vals.enumerate()
             .map(|(idx, val)| {
@@ -260,7 +257,7 @@ fn field_pats(
     // Recursive helper for `to_pat`; invoke that (instead of calling this directly).
     fn recur(
         &self,
-        cv: &'tcx ty::Const<'tcx>,
+        cv: ty::Const<'tcx>,
         mir_structural_match_violation: bool,
     ) -> Result<Pat<'tcx>, FallbackToConstRef> {
         let id = self.id;
@@ -268,7 +265,7 @@ fn recur(
         let tcx = self.tcx();
         let param_env = self.param_env;
 
-        let kind = match cv.ty.kind() {
+        let kind = match cv.ty().kind() {
             ty::Float(_) => {
                 if self.include_lint_checks {
                     tcx.struct_span_lint_hir(
@@ -292,14 +289,14 @@ fn recur(
                 PatKind::Wild
             }
             ty::Adt(..)
-                if !self.type_may_have_partial_eq_impl(cv.ty)
+                if !self.type_may_have_partial_eq_impl(cv.ty())
                     // FIXME(#73448): Find a way to bring const qualification into parity with
                     // `search_for_structural_match_violation` and then remove this condition.
-                    && self.search_for_structural_match_violation(cv.ty).is_some() =>
+                    && self.search_for_structural_match_violation(cv.ty()).is_some() =>
             {
                 // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
                 // could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
-                let msg = self.search_for_structural_match_violation(cv.ty).unwrap();
+                let msg = self.search_for_structural_match_violation(cv.ty()).unwrap();
                 self.saw_const_match_error.set(true);
                 if self.include_lint_checks {
                     tcx.sess.span_err(self.span, &msg);
@@ -317,7 +314,7 @@ fn recur(
             // details.
             // Backwards compatibility hack because we can't cause hard errors on these
             // types, so we compare them via `PartialEq::eq` at runtime.
-            ty::Adt(..) if !self.type_marked_structural(cv.ty) && self.behind_reference.get() => {
+            ty::Adt(..) if !self.type_marked_structural(cv.ty()) && self.behind_reference.get() => {
                 if self.include_lint_checks
                     && !self.saw_const_match_error.get()
                     && !self.saw_const_match_lint.get()
@@ -331,7 +328,8 @@ fn recur(
                             let msg = format!(
                                 "to use a constant of type `{}` in a pattern, \
                                  `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                                cv.ty, cv.ty,
+                                cv.ty(),
+                                cv.ty(),
                             );
                             lint.build(&msg).emit()
                         },
@@ -342,8 +340,12 @@ fn recur(
                 // `PartialEq::eq` on it.
                 return Err(fallback_to_const_ref(self));
             }
-            ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => {
-                debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty);
+            ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty()) => {
+                debug!(
+                    "adt_def {:?} has !type_marked_structural for cv.ty: {:?}",
+                    adt_def,
+                    cv.ty()
+                );
                 let path = tcx.def_path_str(adt_def.did);
                 let msg = format!(
                     "to use a constant of type `{}` in a pattern, \
@@ -378,7 +380,7 @@ fn recur(
                     .destructure_const(param_env.and(cv))
                     .fields
                     .iter()
-                    .map(|val| self.recur(val, false))
+                    .map(|val| self.recur(*val, false))
                     .collect::<Result<_, _>>()?,
                 slice: None,
                 suffix: Vec::new(),
@@ -387,7 +389,7 @@ fn recur(
                 // These are not allowed and will error elsewhere anyway.
                 ty::Dynamic(..) => {
                     self.saw_const_match_error.set(true);
-                    let msg = format!("`{}` cannot be used in patterns", cv.ty);
+                    let msg = format!("`{}` cannot be used in patterns", cv.ty());
                     if self.include_lint_checks {
                         tcx.sess.span_err(span, &msg);
                     } else {
@@ -414,13 +416,13 @@ fn recur(
                                     .destructure_const(param_env.and(array))
                                     .fields
                                     .iter()
-                                    .map(|val| self.recur(val, false))
+                                    .map(|val| self.recur(*val, false))
                                     .collect::<Result<_, _>>()?,
                                 slice: None,
                                 suffix: vec![],
                             }),
                             span,
-                            ty: pointee_ty,
+                            ty: *pointee_ty,
                         },
                     };
                     self.behind_reference.set(old);
@@ -440,7 +442,7 @@ fn recur(
                                     .destructure_const(param_env.and(array))
                                     .fields
                                     .iter()
-                                    .map(|val| self.recur(val, false))
+                                    .map(|val| self.recur(*val, false))
                                     .collect::<Result<_, _>>()?,
                                 slice: None,
                                 suffix: vec![],
@@ -457,7 +459,7 @@ fn recur(
                 // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a
                 // reference. This makes the rest of the matching logic simpler as it doesn't have
                 // to figure out how to get a reference again.
-                ty::Adt(adt_def, _) if !self.type_marked_structural(pointee_ty) => {
+                ty::Adt(adt_def, _) if !self.type_marked_structural(*pointee_ty) => {
                     if self.behind_reference.get() {
                         if self.include_lint_checks
                             && !self.saw_const_match_error.get()
@@ -544,7 +546,7 @@ fn recur(
             }
             _ => {
                 self.saw_const_match_error.set(true);
-                let msg = format!("`{}` cannot be used in patterns", cv.ty);
+                let msg = format!("`{}` cannot be used in patterns", cv.ty());
                 if self.include_lint_checks {
                     tcx.sess.span_err(span, &msg);
                 } else {
@@ -560,12 +562,12 @@ fn recur(
             && mir_structural_match_violation
             // FIXME(#73448): Find a way to bring const qualification into parity with
             // `search_for_structural_match_violation` and then remove this condition.
-            && self.search_for_structural_match_violation(cv.ty).is_some()
+            && self.search_for_structural_match_violation(cv.ty()).is_some()
         {
             self.saw_const_match_lint.set(true);
             // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
             // could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
-            let msg = self.search_for_structural_match_violation(cv.ty).unwrap().replace(
+            let msg = self.search_for_structural_match_violation(cv.ty()).unwrap().replace(
                 "in a pattern,",
                 "in a pattern, the constant's initializer must be trivial or",
             );
@@ -577,6 +579,6 @@ fn recur(
             );
         }
 
-        Ok(Pat { span, ty: cv.ty, kind: Box::new(kind) })
+        Ok(Pat { span, ty: cv.ty(), kind: Box::new(kind) })
     }
 }
index 801c8778bff04c1335b30e2cc7f7db40db0ba06c..e4d9bd9c237e9889cfc7325c031699ce3c585404 100644 (file)
@@ -136,12 +136,12 @@ fn integral_size_and_signed_bias(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<(Size, u
     fn from_const<'tcx>(
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        value: &Const<'tcx>,
+        value: Const<'tcx>,
     ) -> Option<IntRange> {
-        if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, value.ty) {
-            let ty = value.ty;
+        let ty = value.ty();
+        if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) {
             let val = (|| {
-                if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val {
+                if let ty::ConstKind::Value(ConstValue::Scalar(scalar)) = value.val() {
                     // For this specific pattern we can skip a lot of effort and go
                     // straight to the result, after doing a bit of checking. (We
                     // could remove this branch and just fall through, which
@@ -630,9 +630,9 @@ pub(super) enum Constructor<'tcx> {
     /// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
     IntRange(IntRange),
     /// Ranges of floating-point literal values (`2.0..=5.2`).
-    FloatRange(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>, RangeEnd),
+    FloatRange(ty::Const<'tcx>, ty::Const<'tcx>, RangeEnd),
     /// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
-    Str(&'tcx ty::Const<'tcx>),
+    Str(ty::Const<'tcx>),
     /// Array and slice patterns.
     Slice(Slice),
     /// Constants that must not be matched structurally. They are treated as black
@@ -815,8 +815,14 @@ pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self)
                 FloatRange(other_from, other_to, other_end),
             ) => {
                 match (
-                    compare_const_vals(pcx.cx.tcx, self_to, other_to, pcx.cx.param_env, pcx.ty),
-                    compare_const_vals(pcx.cx.tcx, self_from, other_from, pcx.cx.param_env, pcx.ty),
+                    compare_const_vals(pcx.cx.tcx, *self_to, *other_to, pcx.cx.param_env, pcx.ty),
+                    compare_const_vals(
+                        pcx.cx.tcx,
+                        *self_from,
+                        *other_from,
+                        pcx.cx.param_env,
+                        pcx.ty,
+                    ),
                 ) {
                     (Some(to), Some(from)) => {
                         (from == Ordering::Greater || from == Ordering::Equal)
@@ -828,8 +834,13 @@ pub(super) fn is_covered_by<'p>(&self, pcx: PatCtxt<'_, 'p, 'tcx>, other: &Self)
             }
             (Str(self_val), Str(other_val)) => {
                 // FIXME: there's probably a more direct way of comparing for equality
-                match compare_const_vals(pcx.cx.tcx, self_val, other_val, pcx.cx.param_env, pcx.ty)
-                {
+                match compare_const_vals(
+                    pcx.cx.tcx,
+                    *self_val,
+                    *other_val,
+                    pcx.cx.param_env,
+                    pcx.ty,
+                ) {
                     Some(comparison) => comparison == Ordering::Equal,
                     None => false,
                 }
@@ -929,7 +940,7 @@ pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self {
             ty::Bool => smallvec![make_range(0, 1)],
             ty::Array(sub_ty, len) if len.try_eval_usize(cx.tcx, cx.param_env).is_some() => {
                 let len = len.eval_usize(cx.tcx, cx.param_env) as usize;
-                if len != 0 && cx.is_uninhabited(sub_ty) {
+                if len != 0 && cx.is_uninhabited(*sub_ty) {
                     smallvec![]
                 } else {
                     smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))]
@@ -937,7 +948,7 @@ pub(super) fn new<'p>(pcx: PatCtxt<'_, 'p, 'tcx>) -> Self {
             }
             // Treat arrays of a constant but unknown length like slices.
             ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
-                let kind = if cx.is_uninhabited(sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
+                let kind = if cx.is_uninhabited(*sub_ty) { FixedLen(0) } else { VarLen(0, 0) };
                 smallvec![Slice(Slice::new(None, kind))]
             }
             ty::Adt(def, substs) if def.is_enum() => {
@@ -1368,13 +1379,13 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
                 }
             }
             PatKind::Constant { value } => {
-                if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, value) {
+                if let Some(int_range) = IntRange::from_const(cx.tcx, cx.param_env, *value) {
                     ctor = IntRange(int_range);
                     fields = Fields::empty();
                 } else {
                     match pat.ty.kind() {
                         ty::Float(_) => {
-                            ctor = FloatRange(value, value, RangeEnd::Included);
+                            ctor = FloatRange(*value, *value, RangeEnd::Included);
                             fields = Fields::empty();
                         }
                         ty::Ref(_, t, _) if t.is_str() => {
@@ -1386,7 +1397,7 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
                             // fields.
                             // Note: `t` is `str`, not `&str`.
                             let subpattern =
-                                DeconstructedPat::new(Str(value), Fields::empty(), t, pat.span);
+                                DeconstructedPat::new(Str(*value), Fields::empty(), *t, pat.span);
                             ctor = Single;
                             fields = Fields::singleton(cx, subpattern)
                         }
@@ -1401,11 +1412,11 @@ pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
                 }
             }
             &PatKind::Range(PatRange { lo, hi, end }) => {
-                let ty = lo.ty;
+                let ty = lo.ty();
                 ctor = if let Some(int_range) = IntRange::from_range(
                     cx.tcx,
-                    lo.eval_bits(cx.tcx, cx.param_env, lo.ty),
-                    hi.eval_bits(cx.tcx, cx.param_env, hi.ty),
+                    lo.eval_bits(cx.tcx, cx.param_env, lo.ty()),
+                    hi.eval_bits(cx.tcx, cx.param_env, hi.ty()),
                     ty,
                     &end,
                 ) {
index 55cf807172e02fc0b390ccd8653e4abe615a3a33..ddf39fb824cda7cb307f969faf8acdf1554baefe 100644 (file)
@@ -99,7 +99,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
                 Pat {
                     span: pat.span,
-                    ty: ref_ty,
+                    ty: *ref_ty,
                     kind: Box::new(PatKind::Deref { subpattern: pat }),
                 }
             },
@@ -121,13 +121,13 @@ fn lower_range_expr(
     fn lower_pattern_range(
         &mut self,
         ty: Ty<'tcx>,
-        lo: &'tcx ty::Const<'tcx>,
-        hi: &'tcx ty::Const<'tcx>,
+        lo: ty::Const<'tcx>,
+        hi: ty::Const<'tcx>,
         end: RangeEnd,
         span: Span,
     ) -> PatKind<'tcx> {
-        assert_eq!(lo.ty, ty);
-        assert_eq!(hi.ty, ty);
+        assert_eq!(lo.ty(), ty);
+        assert_eq!(hi.ty(), ty);
         let cmp = compare_const_vals(self.tcx, lo, hi, self.param_env, ty);
         match (end, cmp) {
             // `x..y` where `x < y`.
@@ -177,16 +177,16 @@ fn normalize_range_pattern_ends(
         ty: Ty<'tcx>,
         lo: Option<&PatKind<'tcx>>,
         hi: Option<&PatKind<'tcx>>,
-    ) -> Option<(&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>)> {
+    ) -> Option<(ty::Const<'tcx>, ty::Const<'tcx>)> {
         match (lo, hi) {
             (Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
-                Some((lo, hi))
+                Some((*lo, *hi))
             }
             (Some(PatKind::Constant { value: lo }), None) => {
-                Some((lo, ty.numeric_max_val(self.tcx)?))
+                Some((*lo, ty.numeric_max_val(self.tcx)?))
             }
             (None, Some(PatKind::Constant { value: hi })) => {
-                Some((ty.numeric_min_val(self.tcx)?, hi))
+                Some((ty.numeric_min_val(self.tcx)?, *hi))
             }
             _ => None,
         }
@@ -275,7 +275,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Pat<'tcx> {
                 let var_ty = ty;
                 if let ty::BindByReference(_) = bm {
                     if let ty::Ref(_, rty, _) = ty.kind() {
-                        ty = rty;
+                        ty = *rty;
                     } else {
                         bug!("`ref {}` has wrong type {}", ident, ty);
                     }
@@ -417,7 +417,7 @@ fn lower_variant_or_leaf(
                 | DefKind::AssocTy,
                 _,
             )
-            | Res::SelfTy(..)
+            | Res::SelfTy { .. }
             | Res::SelfCtor(..) => PatKind::Leaf { subpatterns },
             _ => {
                 let pattern_error = match res {
@@ -493,7 +493,7 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
                 let const_ =
                     ty::Const::from_value(self.tcx, value, self.typeck_results.node_type(id));
 
-                let pattern = self.const_to_pat(&const_, id, span, mir_structural_match_violation);
+                let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation);
 
                 if !is_associated_const {
                     return pattern;
@@ -514,7 +514,7 @@ fn lower_path(&mut self, qpath: &hir::QPath<'_>, id: hir::HirId, span: Span) ->
                                 user_ty_span: span,
                             },
                         }),
-                        ty: const_.ty,
+                        ty: const_.ty(),
                     }
                 } else {
                     pattern
@@ -546,7 +546,7 @@ fn lower_inline_const(
         // Evaluate early like we do in `lower_path`.
         let value = value.eval(self.tcx, self.param_env);
 
-        match value.val {
+        match value.val() {
             ConstKind::Param(_) => {
                 self.errors.push(PatternError::ConstParamInPattern(span));
                 return PatKind::Wild;
@@ -744,8 +744,8 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
 
 crate fn compare_const_vals<'tcx>(
     tcx: TyCtxt<'tcx>,
-    a: &'tcx ty::Const<'tcx>,
-    b: &'tcx ty::Const<'tcx>,
+    a: ty::Const<'tcx>,
+    b: ty::Const<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     ty: Ty<'tcx>,
 ) -> Option<Ordering> {
@@ -756,13 +756,13 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
     let fallback = || from_bool(a == b);
 
     // Use the fallback if any type differs
-    if a.ty != b.ty || a.ty != ty {
+    if a.ty() != b.ty() || a.ty() != ty {
         return fallback();
     }
 
     // Early return for equal constants (so e.g. references to ZSTs can be compared, even if they
     // are just integer addresses).
-    if a.val == b.val {
+    if a.val() == b.val() {
         return from_bool(true);
     }
 
@@ -797,7 +797,7 @@ fn super_fold_with<F: PatternFolder<'tcx>>(&self, folder: &mut F) -> Self {
         if let (
             ty::ConstKind::Value(a_val @ ConstValue::Slice { .. }),
             ty::ConstKind::Value(b_val @ ConstValue::Slice { .. }),
-        ) = (a.val, b.val)
+        ) = (a.val(), b.val())
         {
             let a_bytes = get_slice_bytes(&tcx, a_val);
             let b_bytes = get_slice_bytes(&tcx, b_val);
index 501bc96401aa50339000a198e8906c3af26a1640..3e1013b0351525841acc9931ffa1baeac10f7561 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_target::abi::VariantIdx;
-use std::fmt;
+use std::{fmt, iter};
 
 /// The value of an inserted drop flag.
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
@@ -329,8 +329,7 @@ fn drop_halfladder(
         mut succ: BasicBlock,
         fields: &[(Place<'tcx>, Option<D::Path>)],
     ) -> Vec<BasicBlock> {
-        Some(succ)
-            .into_iter()
+        iter::once(succ)
             .chain(fields.iter().rev().zip(unwind_ladder).map(|(&(place, path), &unwind_succ)| {
                 succ = self.drop_subpath(place, path, succ, unwind_succ);
                 succ
@@ -881,9 +880,9 @@ fn open_drop(&mut self) -> BasicBlock {
             ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
             ty::Array(ety, size) => {
                 let size = size.try_eval_usize(self.tcx(), self.elaborator.param_env());
-                self.open_drop_for_array(ety, size)
+                self.open_drop_for_array(*ety, size)
             }
-            ty::Slice(ety) => self.open_drop_for_array(ety, None),
+            ty::Slice(ety) => self.open_drop_for_array(*ety, None),
 
             _ => bug!("open drop from non-ADT `{:?}`", ty),
         }
index 98de64cd97c9c49140d806f213359ce64bcb4063..5810ce6edc9643f8925ec8a7ffe64f5b026d65f7 100644 (file)
@@ -145,6 +145,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             Default::default(),
             body.span,
             body.generator_kind(),
+            body.tainted_by_errors,
         );
 
         // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
@@ -483,7 +484,7 @@ fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Opti
                 let err = ConstEvalErr::new(&self.ecx, error, Some(c.span));
                 if let Some(lint_root) = self.lint_root(source_info) {
                     let lint_only = match c.literal {
-                        ConstantKind::Ty(ct) => match ct.val {
+                        ConstantKind::Ty(ct) => match ct.val() {
                             // Promoteds must lint and not error as the user didn't ask for them
                             ConstKind::Unevaluated(ty::Unevaluated {
                                 def: _,
@@ -800,7 +801,7 @@ fn replace_with_const(
     ) {
         if let Rvalue::Use(Operand::Constant(c)) = rval {
             match c.literal {
-                ConstantKind::Ty(c) if matches!(c.val, ConstKind::Unevaluated(..)) => {}
+                ConstantKind::Ty(c) if matches!(c.val(), ConstKind::Unevaluated(..)) => {}
                 _ => {
                     trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
                     return;
@@ -840,7 +841,7 @@ fn replace_with_const(
                     // Found a value represented as a pair. For now only do const-prop if the type
                     // of `rvalue` is also a tuple with two scalars.
                     // FIXME: enable the general case stated above ^.
-                    let ty = &value.layout.ty;
+                    let ty = value.layout.ty;
                     // Only do it for tuples
                     if let ty::Tuple(substs) = ty.kind() {
                         // Only do it if tuple is also a pair with two scalars
@@ -874,7 +875,7 @@ fn replace_with_const(
                                     literal: self
                                         .ecx
                                         .tcx
-                                        .mk_const(ty::Const {
+                                        .mk_const(ty::ConstS {
                                             ty,
                                             val: ty::ConstKind::Value(ConstValue::ByRef {
                                                 alloc,
index ce8b187a744436d4138db17cb6cc7d2270800bbe..62e060c8e0c6c547cbca88dbbc47961e63840a63 100644 (file)
@@ -3,7 +3,7 @@
 //!
 //! To enable coverage, include the rustc command line option:
 //!
-//!   * `-Z instrument-coverage`
+//!   * `-C instrument-coverage`
 //!
 //! MIR Dump Files, with additional `CoverageGraph` graphviz and `CoverageSpan` spanview
 //! ------------------------------------------------------------------------------------
index 62ea2538ff0d8ce8d4346320e911220ddb7410ce..d787443f6aa4e87669522cd1d7fe6ad77720e19e 100644 (file)
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, DebruijnIndex, TyS, TypeFlags};
+use rustc_middle::ty::{self, BOOL_TY};
 use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP};
 
 // All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`.
 const TEMP_BLOCK: BasicBlock = BasicBlock::MAX;
 
-fn dummy_ty() -> &'static TyS<'static> {
-    thread_local! {
-        static DUMMY_TYS: &'static TyS<'static> = Box::leak(Box::new(TyS::make_for_test(
-            ty::Bool,
-            TypeFlags::empty(),
-            DebruijnIndex::from_usize(0),
-        )));
-    }
-
-    &DUMMY_TYS.with(|tys| *tys)
-}
-
 struct MockBlocks<'tcx> {
     blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
     dummy_place: Place<'tcx>,
@@ -166,7 +154,7 @@ fn goto(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
     fn switchint(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
         let switchint_kind = TerminatorKind::SwitchInt {
             discr: Operand::Move(Place::from(self.new_temp())),
-            switch_ty: dummy_ty(),
+            switch_ty: BOOL_TY, // just a dummy value
             targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK),
         };
         self.add_block_from(some_from_block, switchint_kind)
index d469be746414414175e81a914b086d3d32fa383d..237ead591a585913db1f26fdb2b8ccf0c171a10d 100644 (file)
@@ -222,9 +222,11 @@ fn from(l: Local) -> Self {
 
 impl UnifyKey for UnifyLocal {
     type Value = ();
+    #[inline]
     fn index(&self) -> u32 {
         self.0.as_u32()
     }
+    #[inline]
     fn from_index(u: u32) -> Self {
         Self(Local::from_u32(u))
     }
index 9a6b6532ce88f00ef97f99e769b4ee73b9b1fc16..ba234dccaa63e39710000a04f38b008c044bbc97 100644 (file)
@@ -153,7 +153,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             // create temp to store inequality comparison between the two discriminants, `_t` in
             // example above
             let nequal = BinOp::Ne;
-            let comp_res_type = nequal.ty(tcx, parent_ty, opt_data.child_ty);
+            let comp_res_type = nequal.ty(tcx, *parent_ty, opt_data.child_ty);
             let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span);
             patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp));
 
@@ -343,7 +343,7 @@ fn evaluate_candidate<'tcx>(
     Some(OptimizationData {
         destination,
         child_place: *child_place,
-        child_ty,
+        child_ty: *child_ty,
         child_source: child_terminator.source_info,
     })
 }
index 433a1c6ad67cc2694dd6c2d636555d537e7b7ffc..05de52458add2e74dfefcdfaba0ffd03850f2beb 100644 (file)
@@ -1241,9 +1241,7 @@ fn phase_change(&self) -> Option<MirPhase> {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let yield_ty = if let Some(yield_ty) = body.yield_ty() {
-            yield_ty
-        } else {
+        let Some(yield_ty) = body.yield_ty() else {
             // This only applies to generators
             return;
         };
index e1f30fef44f99ebecfda746406e1f2b10af6d570..55ce5910c818b71424f630ef2b19d47d81ed37ec 100644 (file)
@@ -7,6 +7,7 @@
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
+use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
 use rustc_span::{hygiene::ExpnKind, ExpnData, Span};
@@ -75,10 +76,18 @@ fn inline<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
         return false;
     }
 
+    let param_env = tcx.param_env_reveal_all_normalized(def_id);
+    let param_env = rustc_trait_selection::traits::normalize_param_env_or_error(
+        tcx,
+        def_id,
+        param_env,
+        ObligationCause::misc(body.span, hir_id),
+    );
+
     let mut this = Inliner {
         tcx,
-        param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
-        codegen_fn_attrs: tcx.codegen_fn_attrs(body.source.def_id()),
+        param_env,
+        codegen_fn_attrs: tcx.codegen_fn_attrs(def_id),
         hir_id,
         history: Vec::new(),
         changed: false,
@@ -625,7 +634,7 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
                 caller_body.required_consts.extend(
                     callee_body.required_consts.iter().copied().filter(|&ct| {
                         match ct.literal.const_for_ty() {
-                            Some(ct) => matches!(ct.val, ConstKind::Unevaluated(_)),
+                            Some(ct) => matches!(ct.val(), ConstKind::Unevaluated(_)),
                             None => true,
                         }
                     }),
index 129efc2b523794aaf860d725d886fc85d200afbc..e7d5bab8fd9d45e6bce054f0d7c75e8f4e754ee8 100644 (file)
@@ -43,7 +43,8 @@
 mod check_const_item_mutation;
 mod check_packed_ref;
 pub mod check_unsafety;
-mod cleanup_post_borrowck;
+// This pass is public to allow external drivers to perform MIR cleanup
+pub mod cleanup_post_borrowck;
 mod const_debuginfo;
 mod const_goto;
 mod const_prop;
@@ -65,7 +66,8 @@
 mod multiple_return_terminators;
 mod normalize_array_len;
 mod nrvo;
-mod remove_false_edges;
+// This pass is public to allow external drivers to perform MIR cleanup
+pub mod remove_false_edges;
 mod remove_noop_landing_pads;
 mod remove_storage_markers;
 mod remove_uninit_drops;
@@ -75,7 +77,8 @@
 mod reveal_all;
 mod separate_const_switch;
 mod shim;
-mod simplify;
+// This pass is public to allow external drivers to perform MIR cleanup
+pub mod simplify;
 mod simplify_branches;
 mod simplify_comparison_integral;
 mod simplify_try;
@@ -249,8 +252,11 @@ fn mir_promoted<'tcx>(
     // Ensure that we compute the `mir_const_qualif` for constants at
     // this point, before we steal the mir-const result.
     // Also this means promotion can rely on all const checks having been done.
-    let _ = tcx.mir_const_qualif_opt_const_arg(def);
+    let const_qualifs = tcx.mir_const_qualif_opt_const_arg(def);
     let mut body = tcx.mir_const(def).steal();
+    if let Some(error_reported) = const_qualifs.tainted_by_errors {
+        body.tainted_by_errors = Some(error_reported);
+    }
 
     let mut required_consts = Vec::new();
     let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
@@ -355,13 +361,7 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
         return tcx.mir_drops_elaborated_and_const_checked(def);
     }
 
-    // (Mir-)Borrowck uses `mir_promoted`, so we have to force it to
-    // execute before we can steal.
-    if let Some(param_did) = def.const_param_did {
-        tcx.ensure().mir_borrowck_const_arg((def.did, param_did));
-    } else {
-        tcx.ensure().mir_borrowck(def.did);
-    }
+    let mir_borrowck = tcx.mir_borrowck_opt_const_arg(def);
 
     let is_fn_like = tcx.hir().get_by_def_id(def.did).fn_kind().is_some();
     if is_fn_like {
@@ -376,6 +376,9 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
 
     let (body, _) = tcx.mir_promoted(def);
     let mut body = body.steal();
+    if let Some(error_reported) = mir_borrowck.tainted_by_errors {
+        body.tainted_by_errors = Some(error_reported);
+    }
 
     // IMPORTANT
     pm::run_passes(tcx, &mut body, &[&remove_false_edges::RemoveFalseEdges]);
@@ -541,15 +544,13 @@ fn promoted_mir<'tcx>(
         return tcx.arena.alloc(IndexVec::new());
     }
 
-    if let Some(param_did) = def.const_param_did {
-        tcx.ensure().mir_borrowck_const_arg((def.did, param_did));
-    } else {
-        tcx.ensure().mir_borrowck(def.did);
-    }
-    let (_, promoted) = tcx.mir_promoted(def);
-    let mut promoted = promoted.steal();
+    let tainted_by_errors = tcx.mir_borrowck_opt_const_arg(def).tainted_by_errors;
+    let mut promoted = tcx.mir_promoted(def).1.steal();
 
     for body in &mut promoted {
+        if let Some(error_reported) = tainted_by_errors {
+            body.tainted_by_errors = Some(error_reported);
+        }
         run_post_borrowck_cleanup_passes(tcx, body);
     }
 
index e4ac57ac92508bd6d626321541823b127c32f7d2..cdfd49ef478a4875ed80ea4a795c8cd2bff9cdba 100644 (file)
@@ -3,10 +3,11 @@
 
 use crate::MirPass;
 use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::intern::Interned;
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, ReErased, Region, TyCtxt};
 
 const MAX_NUM_BLOCKS: usize = 800;
 const MAX_NUM_LOCALS: usize = 3000;
@@ -211,12 +212,7 @@ fn normalize_array_len_call<'tcx>(
                         let Some(local) = place.as_local() else { return };
                         match operand {
                             Operand::Copy(place) | Operand::Move(place) => {
-                                let operand_local =
-                                    if let Some(local) = place.local_or_deref_local() {
-                                        local
-                                    } else {
-                                        return;
-                                    };
+                                let Some(operand_local) = place.local_or_deref_local() else { return; };
                                 if !interesting_locals.contains(operand_local) {
                                     return;
                                 }
@@ -231,11 +227,15 @@ fn normalize_array_len_call<'tcx>(
                                     // current way of patching doesn't allow to work with `mut`
                                     (
                                         ty::Ref(
-                                            ty::RegionKind::ReErased,
+                                            Region(Interned(ReErased, _)),
                                             operand_ty,
                                             Mutability::Not,
                                         ),
-                                        ty::Ref(ty::RegionKind::ReErased, cast_ty, Mutability::Not),
+                                        ty::Ref(
+                                            Region(Interned(ReErased, _)),
+                                            cast_ty,
+                                            Mutability::Not,
+                                        ),
                                     ) => {
                                         match (operand_ty.kind(), cast_ty.kind()) {
                                             // current way of patching doesn't allow to work with `mut`
index 80c87cafea1016afe42477322df728e3dba090be..1c48efd8b42cb585e1798242b46437f77a5aa1fd 100644 (file)
@@ -15,7 +15,7 @@ pub fn new(required_consts: &'a mut Vec<Constant<'tcx>>) -> Self {
 impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
     fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) {
         if let Some(ct) = constant.literal.const_for_ty() {
-            if let ConstKind::Unevaluated(_) = ct.val {
+            if let ConstKind::Unevaluated(_) = ct.val() {
                 self.required_consts.push(*constant);
             }
         }
index ee661793a44aae74cc7f042cd140f94ad32d1db2..8ea550fa123b6d4196947fefad7f21bcaf4b7e8d 100644 (file)
@@ -39,6 +39,6 @@ fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
         // We have to use `try_normalize_erasing_regions` here, since it's
         // possible that we visit impossible-to-satisfy where clauses here,
         // see #91745
-        *ty = self.tcx.try_normalize_erasing_regions(self.param_env, *ty).unwrap_or(ty);
+        *ty = self.tcx.try_normalize_erasing_regions(self.param_env, *ty).unwrap_or(*ty);
     }
 }
index 919171db39e3160ac15bfe61f13b8cf523c8acf5..b8feeb993e7c8a6a45ebcef69cbb7c7c6b8aa2a4 100644 (file)
@@ -68,7 +68,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
         ty::InstanceDef::DropGlue(def_id, ty) => {
             // FIXME(#91576): Drop shims for generators aren't subject to the MIR passes at the end
             // of this function. Is this intentional?
-            if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(ty::TyS::kind) {
+            if let Some(ty::Generator(gen_def_id, substs, _)) = ty.map(Ty::kind) {
                 let body = tcx.optimized_mir(*gen_def_id).generator_drop().unwrap();
                 let body = body.clone().subst(tcx, substs);
                 debug!("make_shim({:?}) = {:?}", instance, body);
@@ -137,7 +137,7 @@ fn local_decls_for_sig<'tcx>(
     span: Span,
 ) -> IndexVec<Local, LocalDecl<'tcx>> {
     iter::once(LocalDecl::new(sig.output(), span))
-        .chain(sig.inputs().iter().map(|ity| LocalDecl::new(ity, span).immutable()))
+        .chain(sig.inputs().iter().map(|ity| LocalDecl::new(*ity, span).immutable()))
         .collect()
 }
 
@@ -235,6 +235,8 @@ fn new_body<'tcx>(
         vec![],
         span,
         None,
+        // FIXME(compiler-errors): is this correct?
+        None,
     )
 }
 
index 7e0c8e233e9e8cfd94efa213717d79e860f08261..4651e1f4ed059de70a5c4977bcd610972f7fefdf 100644 (file)
@@ -303,7 +303,7 @@ pub fn remove_dead_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 /// evaluation: `if false { ... }`.
 ///
 /// Those statements are bypassed by redirecting paths in the CFG around the
-/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually
+/// `dead blocks`; but with `-C instrument-coverage`, the dead blocks usually
 /// include `Coverage` statements representing the Rust source code regions to
 /// be counted at runtime. Without these `Coverage` statements, the regions are
 /// lost, and the Rust source code will show no coverage information.
index 7f13da5d38f870c6757400306b95ef62d2e4a423..72c1b3fa6e98c0b11cce882b5c1d01880fa59f4d 100644 (file)
@@ -709,7 +709,7 @@ fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location)
         let literal = self.monomorphize(constant.literal);
         let val = match literal {
             mir::ConstantKind::Val(val, _) => val,
-            mir::ConstantKind::Ty(ct) => match ct.val {
+            mir::ConstantKind::Ty(ct) => match ct.val() {
                 ty::ConstKind::Value(val) => val,
                 ty::ConstKind::Unevaluated(ct) => {
                     let param_env = ty::ParamEnv::reveal_all();
@@ -731,13 +731,13 @@ fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location)
         self.visit_ty(literal.ty(), TyContext::Location(location));
     }
 
-    fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, location: Location) {
-        debug!("visiting const {:?} @ {:?}", *constant, location);
+    fn visit_const(&mut self, constant: ty::Const<'tcx>, location: Location) {
+        debug!("visiting const {:?} @ {:?}", constant, location);
 
-        let substituted_constant = self.monomorphize(*constant);
+        let substituted_constant = self.monomorphize(constant);
         let param_env = ty::ParamEnv::reveal_all();
 
-        match substituted_constant.val {
+        match substituted_constant.val() {
             ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output),
             ty::ConstKind::Unevaluated(unevaluated) => {
                 match self.tcx.const_eval_resolve(param_env, unevaluated, None) {
@@ -947,9 +947,7 @@ fn visit_instance_use<'tcx>(
 /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we
 /// can just link to the upstream crate and therefore don't need a mono item.
 fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool {
-    let def_id = if let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() {
-        def_id
-    } else {
+    let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else {
         return true;
     };
 
@@ -1042,7 +1040,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
     match (&source_ty.kind(), &target_ty.kind()) {
         (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(ty::TypeAndMut { ty: b, .. }))
         | (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }), &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
-            ptr_vtable(a, b)
+            ptr_vtable(*a, *b)
         }
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
             ptr_vtable(source_ty.boxed_ty(), target_ty.boxed_ty())
index 4b17c22a68c268c8ee17b782c097af6dd67ceb06..48b6951f10ef0751b8230b4d6e65154b67696d5c 100644 (file)
@@ -267,7 +267,7 @@ fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
         self.super_local_decl(local, local_decl);
     }
 
-    fn visit_const(&mut self, c: &&'tcx Const<'tcx>, _: Location) {
+    fn visit_const(&mut self, c: Const<'tcx>, _: Location) {
         c.visit_with(self);
     }
 
@@ -278,12 +278,12 @@ fn visit_ty(&mut self, ty: Ty<'tcx>, _: TyContext) {
 
 impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
     #[instrument(level = "debug", skip(self))]
-    fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+    fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !c.has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
         }
 
-        match c.val {
+        match c.val() {
             ty::ConstKind::Param(param) => {
                 debug!(?param);
                 self.unused_parameters.clear(param.index);
@@ -348,12 +348,12 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
     type BreakTy = ();
 
     #[instrument(level = "debug", skip(self))]
-    fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+    fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
         if !c.has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
         }
 
-        match c.val {
+        match c.val() {
             ty::ConstKind::Param(param) => {
                 if self.unused_parameters.contains(param.index).unwrap_or(false) {
                     ControlFlow::CONTINUE
index 27540395c07892054465dc5d1a1af0c866369e81..04baa01832be64e171a8178d9442bda61e978039 100644 (file)
@@ -8,13 +8,11 @@
 /// During the same compile all closures dump the information in the same file
 /// "closure_profile_XXXXX.csv", which is created in the directory where the compiler is invoked.
 crate fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: Instance<'tcx>) {
-    let mut file = if let Ok(file) = OpenOptions::new()
+    let Ok(mut file) = OpenOptions::new()
         .create(true)
         .append(true)
         .open(&format!("closure_profile_{}.csv", std::process::id()))
-    {
-        file
-    } else {
+    else {
         eprintln!("Cound't open file for writing closure profile");
         return;
     };
index 1a620968d56a8d092336304a562484b3341a98be..4cdd83c0acd3c5a4af56fdce6b4418970228ecef 100644 (file)
@@ -158,9 +158,7 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Opt
         Some(match token {
             rustc_lexer::TokenKind::LineComment { doc_style } => {
                 // Skip non-doc comments
-                let doc_style = if let Some(doc_style) = doc_style {
-                    doc_style
-                } else {
+                let Some(doc_style) = doc_style else {
                     self.lint_unicode_text_flow(start);
                     return None;
                 };
@@ -185,9 +183,7 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Opt
                 }
 
                 // Skip non-doc comments
-                let doc_style = if let Some(doc_style) = doc_style {
-                    doc_style
-                } else {
+                let Some(doc_style) = doc_style else {
                     self.lint_unicode_text_flow(start);
                     return None;
                 };
index 7f68112a427ba1be2270c2bf58dfe06b6c09cdc2..a41956c58f005af4b4a6c0ce43df5fc784094c3c 100644 (file)
@@ -185,6 +185,15 @@ pub(crate) fn emit_unescape_error(
                      version control settings",
                 );
             } else {
+                if !mode.is_bytes() {
+                    diag.span_suggestion(
+                        span_with_quotes,
+                        "if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal",
+                        format!("r\"{}\"", lit),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+
                 diag.help(
                     "for more information, visit \
                      <https://static.rust-lang.org/doc/master/reference.html#literals>",
index 2b1b2f3fce496f9eff9f95254ff0b9628ae29be9..eb0d1a12c778f471333f10ac21babd5b9a2253dc 100644 (file)
@@ -4,6 +4,7 @@
 #![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(box_patterns)]
+#![feature(let_else)]
 #![recursion_limit = "256"]
 
 #[macro_use]
index 0115d498a7fb889b4415d8aa1e4165d917c7bf10..e9aa4adcaf79bae5faddf019378d84bf3f8b5e29 100644 (file)
@@ -1457,9 +1457,9 @@ fn parse_labeled_expr(
         } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
             self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs)
         } else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) {
-            // We're probably inside of a `Path<'a>` that needs a turbofish, so suppress the
-            // "must be followed by a colon" error, and the "expected one of" error.
-            self.diagnostic().delay_span_bug(lo, "this label wasn't parsed correctly");
+            // We're probably inside of a `Path<'a>` that needs a turbofish
+            let msg = "expected `while`, `for`, `loop` or `{` after a label";
+            self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
             consume_colon = false;
             Ok(self.mk_expr_err(lo))
         } else {
@@ -1702,11 +1702,11 @@ fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
 
         // Try to lowercase the prefix if it's a valid base prefix.
         fn fix_base_capitalisation(s: &str) -> Option<String> {
-            if let Some(stripped) = s.strip_prefix("B") {
+            if let Some(stripped) = s.strip_prefix('B') {
                 Some(format!("0b{stripped}"))
-            } else if let Some(stripped) = s.strip_prefix("O") {
+            } else if let Some(stripped) = s.strip_prefix('O') {
                 Some(format!("0o{stripped}"))
-            } else if let Some(stripped) = s.strip_prefix("X") {
+            } else if let Some(stripped) = s.strip_prefix('X') {
                 Some(format!("0x{stripped}"))
             } else {
                 None
index 9d653de910fecad7602732312243e5a43164544f..a6a2cbc277c208c98643d87fb80d82f202f703ad 100644 (file)
@@ -95,7 +95,7 @@ pub enum Position {
     /// The argument is located at a specific index given in the format
     ArgumentIs(usize),
     /// The argument has a name.
-    ArgumentNamed(Symbol),
+    ArgumentNamed(Symbol, InnerSpan),
 }
 
 impl Position {
@@ -147,7 +147,7 @@ pub enum Count {
     /// The count is specified explicitly.
     CountIs(usize),
     /// The count is specified by the argument with the given name.
-    CountIsName(Symbol),
+    CountIsName(Symbol, InnerSpan),
     /// The count is specified by the argument at the given index.
     CountIsParam(usize),
     /// The count is implied and cannot be explicitly specified.
@@ -494,8 +494,11 @@ fn position(&mut self) -> Option<Position> {
             Some(ArgumentIs(i))
         } else {
             match self.cur.peek() {
-                Some(&(_, c)) if rustc_lexer::is_id_start(c) => {
-                    Some(ArgumentNamed(Symbol::intern(self.word())))
+                Some(&(start, c)) if rustc_lexer::is_id_start(c) => {
+                    let word = self.word();
+                    let end = start + word.len();
+                    let span = self.to_span_index(start).to(self.to_span_index(end));
+                    Some(ArgumentNamed(Symbol::intern(word), span))
                 }
 
                 // This is an `ArgumentNext`.
@@ -662,8 +665,9 @@ fn count(&mut self, start: usize) -> (Count, Option<InnerSpan>) {
             if word.is_empty() {
                 self.cur = tmp;
                 (CountImplied, None)
-            } else if self.consume('$') {
-                (CountIsName(Symbol::intern(word)), None)
+            } else if let Some(end) = self.consume_pos('$') {
+                let span = self.to_span_index(start + 1).to(self.to_span_index(end));
+                (CountIsName(Symbol::intern(word), span), None)
             } else {
                 self.cur = tmp;
                 (CountImplied, None)
index b7693a85ad955a0365c91ffbe42829a1eabf3aff..6c960fdc72bfd583ab0ffd243829ef8da57103b3 100644 (file)
@@ -221,8 +221,8 @@ fn format_counts() {
                     fill: None,
                     align: AlignUnknown,
                     flags: 0,
-                    precision: CountIsName(Symbol::intern("b")),
-                    width: CountIsName(Symbol::intern("a")),
+                    precision: CountIsName(Symbol::intern("b"), InnerSpan::new(6, 7)),
+                    width: CountIsName(Symbol::intern("a"), InnerSpan::new(4, 4)),
                     precision_span: None,
                     width_span: None,
                     ty: "?",
index ca511f7b814be858724ac352628126e78c26aa82..479a08e43c01a78b64110a0785280942195bc311 100644 (file)
@@ -1741,12 +1741,46 @@ fn check_repr(
     }
 
     fn check_used(&self, attrs: &[Attribute], target: Target) {
+        let mut used_linker_span = None;
+        let mut used_compiler_span = None;
         for attr in attrs {
             if attr.has_name(sym::used) && target != Target::Static {
                 self.tcx
                     .sess
                     .span_err(attr.span, "attribute must be applied to a `static` variable");
             }
+            let inner = attr.meta_item_list();
+            match inner.as_deref() {
+                Some([item]) if item.has_name(sym::linker) => {
+                    if used_linker_span.is_none() {
+                        used_linker_span = Some(attr.span);
+                    }
+                }
+                Some([item]) if item.has_name(sym::compiler) => {
+                    if used_compiler_span.is_none() {
+                        used_compiler_span = Some(attr.span);
+                    }
+                }
+                Some(_) => {
+                    // This error case is handled in rustc_typeck::collect.
+                }
+                None => {
+                    // Default case (compiler) when arg isn't defined.
+                    if used_compiler_span.is_none() {
+                        used_compiler_span = Some(attr.span);
+                    }
+                }
+            }
+        }
+        if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
+            let spans = vec![linker_span, compiler_span];
+            self.tcx
+                .sess
+                .struct_span_err(
+                    spans,
+                    "`used(compiler)` and `used(linker)` can't be used together",
+                )
+                .emit();
         }
     }
 
index e7e56711b33c5298790980d12e78607ad595c89a..e52fbc8ab92d6587285f7fb779cc2e29e53a7931 100644 (file)
@@ -104,7 +104,7 @@ fn handle_res(&mut self, res: Res) {
                     self.check_def_id(variant_id);
                 }
             }
-            Res::SelfTy(t, i) => {
+            Res::SelfTy { trait_: t, alias_to: i } => {
                 if let Some(t) = t {
                     self.check_def_id(t);
                 }
@@ -466,7 +466,10 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
 
     // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
     // forcefully, e.g., for placing it in a specific section.
-    if cg_attrs.contains_extern_indicator() || cg_attrs.flags.contains(CodegenFnAttrFlags::USED) {
+    if cg_attrs.contains_extern_indicator()
+        || cg_attrs.flags.contains(CodegenFnAttrFlags::USED)
+        || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
+    {
         return true;
     }
 
index 3521b6fc1696c7978072e63fe92636be9baf4ecb..136059677c5ae94a80203d3768b13ee63901dc90 100644 (file)
@@ -577,17 +577,21 @@ fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
     }
 
     fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
-        let stab_map = self.tcx.stability();
-        let stab = stab_map.local_stability(def_id);
-        if stab.map_or(false, |stab| stab.level.is_stable()) {
-            let const_stab = stab_map.local_const_stability(def_id);
-            if const_stab.is_none() {
-                self.tcx.sess.span_err(
-                    span,
-                    "`#[stable]` const functions must also be either \
-                    `#[rustc_const_stable]` or `#[rustc_const_unstable]`",
-                );
-            }
+        if !self.tcx.features().staged_api {
+            return;
+        }
+
+        let is_const = self.tcx.is_const_fn(def_id.to_def_id());
+        let is_stable = self
+            .tcx
+            .lookup_stability(def_id)
+            .map_or(false, |stability| stability.level.is_stable());
+        let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
+        let is_reachable = self.access_levels.is_reachable(def_id);
+
+        if is_const && is_stable && missing_const_stability_attribute && is_reachable {
+            let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
+            self.tcx.sess.span_err(span, &format!("{descr} has missing const stability attribute"));
         }
     }
 }
@@ -612,13 +616,8 @@ fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
             self.check_missing_stability(i.def_id, i.span);
         }
 
-        // Ensure `const fn` that are `stable` have one of `rustc_const_unstable` or
-        // `rustc_const_stable`.
-        if self.tcx.features().staged_api
-            && matches!(&i.kind, hir::ItemKind::Fn(sig, ..) if sig.header.is_const())
-        {
-            self.check_missing_const_stability(i.def_id, i.span);
-        }
+        // Ensure stable `const fn` have a const stability attribute.
+        self.check_missing_const_stability(i.def_id, i.span);
 
         intravisit::walk_item(self, i)
     }
@@ -632,6 +631,7 @@ fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
         let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id());
         if self.tcx.impl_trait_ref(impl_def_id).is_none() {
             self.check_missing_stability(ii.def_id, ii.span);
+            self.check_missing_const_stability(ii.def_id, ii.span);
         }
         intravisit::walk_impl_item(self, ii);
     }
index 7c511ccbd576aeef1edd857d31075c0ce3a1fc55..48594e73f5b8359ed32e0c4e43ab00d2833d514a 100644 (file)
@@ -280,8 +280,8 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
         }
     }
 
-    fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        self.visit_ty(c.ty)?;
+    fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        self.visit_ty(c.ty())?;
         let tcx = self.def_id_visitor.tcx();
         if let Ok(Some(ct)) = AbstractConst::from_const(tcx, c) {
             self.visit_abstract_const_expr(tcx, ct)?;
@@ -1350,7 +1350,7 @@ struct ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
 impl<'a, 'tcx> ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
     fn path_is_private_type(&self, path: &hir::Path<'_>) -> bool {
         let did = match path.res {
-            Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => return false,
+            Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => return false,
             res => res.def_id(),
         };
 
index 581a2bce2e50e5cd81b8835aecfd117b2ba0bf68..84de31a194da08d711acaf3c08b28e18bff728d8 100644 (file)
@@ -275,7 +275,7 @@ fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
     }
 }
 
-impl<'tcx> Key for (&'tcx ty::Const<'tcx>, mir::Field) {
+impl<'tcx> Key for (ty::Const<'tcx>, mir::Field) {
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
@@ -345,7 +345,7 @@ fn default_span(&self, _: TyCtxt<'_>) -> Span {
     }
 }
 
-impl<'tcx> Key for &'tcx ty::Const<'tcx> {
+impl<'tcx> Key for ty::Const<'tcx> {
     #[inline(always)]
     fn query_crate_is_local(&self) -> bool {
         true
index bf859decc70fddeea9069ea5d966dfbcac50bc2b..55e95e1a592d34f51c9cf47c7f8edb02d18a0608 100644 (file)
@@ -15,6 +15,7 @@
 extern crate rustc_middle;
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::AtomicU64;
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::{self, DepKindStruct, SerializedDepNodeIndex};
 use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_values};
@@ -28,9 +29,6 @@
 pub use plumbing::QueryCtxt;
 use rustc_query_system::query::*;
 
-mod stats;
-pub use self::stats::print_stats;
-
 mod keys;
 use keys::Key;
 
index 6d76d09f6190e21d5fa56fe8c17be3c3299df2ab..ff9d32a6776520fb1aae2bd69b1900477fb61946 100644 (file)
@@ -3,7 +3,7 @@
 //! manage the caches, and so forth.
 
 use crate::{on_disk_cache, Queries};
-use rustc_middle::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex};
+use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
 use rustc_middle::ty::tls::{self, ImplicitCtxt};
 use rustc_middle::ty::TyCtxt;
 use rustc_query_system::dep_graph::HasDepContext;
@@ -15,6 +15,7 @@
 use rustc_serialize::opaque;
 
 use std::any::Any;
+use std::num::NonZeroU64;
 
 #[derive(Copy, Clone)]
 pub struct QueryCtxt<'tcx> {
@@ -42,11 +43,20 @@ fn dep_context(&self) -> &Self::DepContext {
 }
 
 impl QueryContext for QueryCtxt<'_> {
-    fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>> {
+    fn next_job_id(&self) -> QueryJobId {
+        QueryJobId(
+            NonZeroU64::new(
+                self.queries.jobs.fetch_add(1, rustc_data_structures::sync::Ordering::Relaxed),
+            )
+            .unwrap(),
+        )
+    }
+
+    fn current_query_job(&self) -> Option<QueryJobId> {
         tls::with_related_context(**self, |icx| icx.query)
     }
 
-    fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind>> {
+    fn try_collect_active_jobs(&self) -> Option<QueryMap> {
         self.queries.try_collect_active_jobs(**self)
     }
 
@@ -81,7 +91,7 @@ fn store_side_effects_for_anon_node(
     #[inline(always)]
     fn start_query<R>(
         &self,
-        token: QueryJobId<Self::DepKind>,
+        token: QueryJobId,
         diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
         compute: impl FnOnce() -> R,
     ) -> R {
@@ -152,7 +162,7 @@ macro_rules! encode_queries {
 
     pub fn try_print_query_stack(
         self,
-        query: Option<QueryJobId<DepKind>>,
+        query: Option<QueryJobId>,
         handler: &Handler,
         num_frames: Option<usize>,
     ) -> usize {
@@ -299,7 +309,7 @@ pub fn $name<$tcx>(tcx: QueryCtxt<$tcx>, key: query_keys::$name<$tcx>) -> QueryS
         }
 
         #[allow(nonstandard_style)]
-        pub mod queries {
+        mod queries {
             use std::marker::PhantomData;
 
             $(pub struct $name<$tcx> {
@@ -320,7 +330,7 @@ impl<$tcx> QueryDescription<QueryCtxt<$tcx>> for queries::$name<$tcx> {
             type Cache = query_storage::$name<$tcx>;
 
             #[inline(always)]
-            fn query_state<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryState<crate::dep_graph::DepKind, Self::Key>
+            fn query_state<'a>(tcx: QueryCtxt<$tcx>) -> &'a QueryState<Self::Key>
                 where QueryCtxt<$tcx>: 'a
             {
                 &tcx.queries.$name
@@ -353,7 +363,7 @@ fn make_vtable(tcx: QueryCtxt<'tcx>, key: &Self::Key) ->
         })*
 
         #[allow(nonstandard_style)]
-        pub mod query_callbacks {
+        mod query_callbacks {
             use super::*;
             use rustc_middle::dep_graph::DepNode;
             use rustc_middle::ty::query::query_keys;
@@ -402,7 +412,7 @@ pub fn CompileMonoItem() -> DepKindStruct {
                 }
             }
 
-            $(pub fn $name()-> DepKindStruct {
+            $(pub(crate) fn $name()-> DepKindStruct {
                 let is_anon = is_anon!([$($modifiers)*]);
                 let is_eval_always = is_eval_always!([$($modifiers)*]);
 
@@ -471,10 +481,9 @@ pub struct Queries<$tcx> {
 
             pub on_disk_cache: Option<OnDiskCache<$tcx>>,
 
-            $($(#[$attr])*  $name: QueryState<
-                crate::dep_graph::DepKind,
-                query_keys::$name<$tcx>,
-            >,)*
+            jobs: AtomicU64,
+
+            $($(#[$attr])*  $name: QueryState<query_keys::$name<$tcx>>,)*
         }
 
         impl<$tcx> Queries<$tcx> {
@@ -487,6 +496,7 @@ pub fn new(
                     local_providers: Box::new(local_providers),
                     extern_providers: Box::new(extern_providers),
                     on_disk_cache,
+                    jobs: AtomicU64::new(1),
                     $($name: Default::default()),*
                 }
             }
@@ -494,14 +504,13 @@ pub fn new(
             pub(crate) fn try_collect_active_jobs(
                 &$tcx self,
                 tcx: TyCtxt<$tcx>,
-            ) -> Option<QueryMap<crate::dep_graph::DepKind>> {
+            ) -> Option<QueryMap> {
                 let tcx = QueryCtxt { tcx, queries: self };
                 let mut jobs = QueryMap::default();
 
                 $(
                     self.$name.try_collect_active_jobs(
                         tcx,
-                        dep_graph::DepKind::$name,
                         make_query::$name,
                         &mut jobs,
                     )?;
diff --git a/compiler/rustc_query_impl/src/stats.rs b/compiler/rustc_query_impl/src/stats.rs
deleted file mode 100644 (file)
index c3bbd51..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-use rustc_hir::def_id::{DefId, LOCAL_CRATE};
-use rustc_middle::ty::query::query_storage;
-use rustc_middle::ty::TyCtxt;
-use rustc_query_system::query::{QueryCache, QueryCacheStore};
-
-use std::any::type_name;
-use std::mem;
-
-trait KeyStats {
-    fn key_stats(&self, stats: &mut QueryStats);
-}
-
-impl<T> KeyStats for T {
-    default fn key_stats(&self, _: &mut QueryStats) {}
-}
-
-impl KeyStats for DefId {
-    fn key_stats(&self, stats: &mut QueryStats) {
-        if self.krate == LOCAL_CRATE {
-            stats.local_def_id_keys = Some(stats.local_def_id_keys.unwrap_or(0) + 1);
-        }
-    }
-}
-
-#[derive(Clone)]
-struct QueryStats {
-    name: &'static str,
-    key_size: usize,
-    key_type: &'static str,
-    value_size: usize,
-    value_type: &'static str,
-    entry_count: usize,
-    local_def_id_keys: Option<usize>,
-}
-
-fn stats<C>(name: &'static str, map: &QueryCacheStore<C>) -> QueryStats
-where
-    C: QueryCache,
-{
-    let mut stats = QueryStats {
-        name,
-        key_size: mem::size_of::<C::Key>(),
-        key_type: type_name::<C::Key>(),
-        value_size: mem::size_of::<C::Value>(),
-        value_type: type_name::<C::Value>(),
-        entry_count: 0,
-        local_def_id_keys: None,
-    };
-    map.iter_results(&mut |key, _, _| {
-        stats.entry_count += 1;
-        key.key_stats(&mut stats)
-    });
-    stats
-}
-
-pub fn print_stats(tcx: TyCtxt<'_>) {
-    let queries = query_stats(tcx);
-
-    let mut query_key_sizes = queries.clone();
-    query_key_sizes.sort_by_key(|q| q.key_size);
-    eprintln!("\nLarge query keys:");
-    for q in query_key_sizes.iter().rev().filter(|q| q.key_size > 8) {
-        eprintln!("   {} - {} x {} - {}", q.name, q.key_size, q.entry_count, q.key_type);
-    }
-
-    let mut query_value_sizes = queries.clone();
-    query_value_sizes.sort_by_key(|q| q.value_size);
-    eprintln!("\nLarge query values:");
-    for q in query_value_sizes.iter().rev().filter(|q| q.value_size > 8) {
-        eprintln!("   {} - {} x {} - {}", q.name, q.value_size, q.entry_count, q.value_type);
-    }
-
-    let mut query_value_count = queries.clone();
-    query_value_count.sort_by_key(|q| q.entry_count);
-    eprintln!("\nQuery value count:");
-    for q in query_value_count.iter().rev() {
-        eprintln!("   {} - {}", q.name, q.entry_count);
-    }
-
-    let mut def_id_density: Vec<_> =
-        queries.iter().filter(|q| q.local_def_id_keys.is_some()).collect();
-    def_id_density.sort_by_key(|q| q.local_def_id_keys.unwrap());
-    eprintln!("\nLocal DefId density:");
-    let total = tcx.resolutions(()).definitions.def_index_count() as f64;
-    for q in def_id_density.iter().rev() {
-        let local = q.local_def_id_keys.unwrap();
-        eprintln!("   {} - {} = ({}%)", q.name, local, (local as f64 * 100.0) / total);
-    }
-}
-
-macro_rules! print_stats {
-    (<$tcx:tt>
-        $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($K:ty) -> $V:ty,)*
-    ) => {
-        fn query_stats(tcx: TyCtxt<'_>) -> Vec<QueryStats> {
-            let mut queries = Vec::new();
-
-            $(
-                queries.push(stats::<
-                    query_storage::$name<'_>,
-                >(
-                    stringify!($name),
-                    &tcx.query_caches.$name,
-                ));
-            )*
-
-            queries
-        }
-    }
-}
-
-rustc_query_append! { [print_stats!][<'tcx>] }
index 003867beeb7e66f457762f6cd0f0eb32a264655d..718a2971c403d02b494f653e61be9f89cb8e7766 100644 (file)
@@ -1,5 +1,5 @@
 use super::QueryCtxt;
-use rustc_middle::ty::{self, AdtSizedConstraint, Ty, TyS};
+use rustc_middle::ty::{self, AdtSizedConstraint, Ty};
 
 pub(super) trait Value<'tcx>: Sized {
     fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self;
@@ -12,7 +12,7 @@ impl<'tcx, T> Value<'tcx> for T {
     }
 }
 
-impl<'tcx> Value<'tcx> for &'_ TyS<'_> {
+impl<'tcx> Value<'tcx> for Ty<'_> {
     fn from_cycle_error(tcx: QueryCtxt<'tcx>) -> Self {
         // SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
         // FIXME: Represent the above fact in the trait system somehow.
index 283eda7c85e647cd3f9aceb2ccb7583722e0749b..c95dff13d6615ffe71097d8f480fad6097a7f9c6 100644 (file)
@@ -182,7 +182,7 @@ fn new(encoder: FileEncoder, record_stats: bool) -> Self {
             total_edge_count: 0,
             total_node_count: 0,
             result: Ok(()),
-            stats: if record_stats { Some(FxHashMap::default()) } else { None },
+            stats: record_stats.then(FxHashMap::default),
         }
     }
 
index d2b102b6f89681358bca92bfb1cd9b3bf8d53b87..b1ff1e15a9db53e0367d0fc895f2056c78c809ac 100644 (file)
@@ -59,7 +59,7 @@ pub trait QueryDescription<CTX: QueryContext>: QueryConfig {
     fn describe(tcx: CTX, key: Self::Key) -> String;
 
     // Don't use this method to access query results, instead use the methods on TyCtxt
-    fn query_state<'a>(tcx: CTX) -> &'a QueryState<CTX::DepKind, Self::Key>
+    fn query_state<'a>(tcx: CTX) -> &'a QueryState<Self::Key>
     where
         CTX: 'a;
 
index bd67303099220e39ee508d2e855ad8cdc1ea7ab3..adf878a7f04c189a84c025e9737bb09a7ced0fee 100644 (file)
@@ -7,13 +7,11 @@
 use rustc_session::Session;
 use rustc_span::Span;
 
-use std::convert::TryFrom;
 use std::hash::Hash;
-use std::num::NonZeroU32;
+use std::num::NonZeroU64;
 
 #[cfg(parallel_compiler)]
 use {
-    crate::dep_graph::DepKind,
     parking_lot::{Condvar, Mutex},
     rustc_data_structures::fx::FxHashSet,
     rustc_data_structures::sync::Lock,
@@ -33,80 +31,57 @@ pub struct QueryInfo {
     pub query: QueryStackFrame,
 }
 
-pub type QueryMap<D> = FxHashMap<QueryJobId<D>, QueryJobInfo<D>>;
-
-/// A value uniquely identifying an active query job within a shard in the query cache.
-#[derive(Copy, Clone, Eq, PartialEq, Hash)]
-pub struct QueryShardJobId(pub NonZeroU32);
+pub type QueryMap = FxHashMap<QueryJobId, QueryJobInfo>;
 
 /// A value uniquely identifying an active query job.
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
-pub struct QueryJobId<D> {
-    /// Which job within a shard is this
-    pub job: QueryShardJobId,
-
-    /// In which shard is this job
-    pub shard: u16,
+pub struct QueryJobId(pub NonZeroU64);
 
-    /// What kind of query this job is.
-    pub kind: D,
-}
-
-impl<D> QueryJobId<D>
-where
-    D: Copy + Clone + Eq + Hash,
-{
-    pub fn new(job: QueryShardJobId, shard: usize, kind: D) -> Self {
-        QueryJobId { job, shard: u16::try_from(shard).unwrap(), kind }
-    }
-
-    fn query(self, map: &QueryMap<D>) -> QueryStackFrame {
+impl QueryJobId {
+    fn query(self, map: &QueryMap) -> QueryStackFrame {
         map.get(&self).unwrap().query.clone()
     }
 
     #[cfg(parallel_compiler)]
-    fn span(self, map: &QueryMap<D>) -> Span {
+    fn span(self, map: &QueryMap) -> Span {
         map.get(&self).unwrap().job.span
     }
 
     #[cfg(parallel_compiler)]
-    fn parent(self, map: &QueryMap<D>) -> Option<QueryJobId<D>> {
+    fn parent(self, map: &QueryMap) -> Option<QueryJobId> {
         map.get(&self).unwrap().job.parent
     }
 
     #[cfg(parallel_compiler)]
-    fn latch<'a>(self, map: &'a QueryMap<D>) -> Option<&'a QueryLatch<D>> {
+    fn latch<'a>(self, map: &'a QueryMap) -> Option<&'a QueryLatch> {
         map.get(&self).unwrap().job.latch.as_ref()
     }
 }
 
-pub struct QueryJobInfo<D> {
+pub struct QueryJobInfo {
     pub query: QueryStackFrame,
-    pub job: QueryJob<D>,
+    pub job: QueryJob,
 }
 
 /// Represents an active query job.
 #[derive(Clone)]
-pub struct QueryJob<D> {
-    pub id: QueryShardJobId,
+pub struct QueryJob {
+    pub id: QueryJobId,
 
     /// The span corresponding to the reason for which this query was required.
     pub span: Span,
 
     /// The parent query job which created this job and is implicitly waiting on it.
-    pub parent: Option<QueryJobId<D>>,
+    pub parent: Option<QueryJobId>,
 
     /// The latch that is used to wait on this job.
     #[cfg(parallel_compiler)]
-    latch: Option<QueryLatch<D>>,
+    latch: Option<QueryLatch>,
 }
 
-impl<D> QueryJob<D>
-where
-    D: Copy + Clone + Eq + Hash,
-{
+impl QueryJob {
     /// Creates a new query job.
-    pub fn new(id: QueryShardJobId, span: Span, parent: Option<QueryJobId<D>>) -> Self {
+    pub fn new(id: QueryJobId, span: Span, parent: Option<QueryJobId>) -> Self {
         QueryJob {
             id,
             span,
@@ -117,7 +92,7 @@ pub fn new(id: QueryShardJobId, span: Span, parent: Option<QueryJobId<D>>) -> Se
     }
 
     #[cfg(parallel_compiler)]
-    pub(super) fn latch(&mut self) -> QueryLatch<D> {
+    pub(super) fn latch(&mut self) -> QueryLatch {
         if self.latch.is_none() {
             self.latch = Some(QueryLatch::new());
         }
@@ -139,16 +114,13 @@ pub fn signal_complete(self) {
 }
 
 #[cfg(not(parallel_compiler))]
-impl<D> QueryJobId<D>
-where
-    D: Copy + Clone + Eq + Hash,
-{
+impl QueryJobId {
     #[cold]
     #[inline(never)]
     pub(super) fn find_cycle_in_stack(
         &self,
-        query_map: QueryMap<D>,
-        current_job: &Option<QueryJobId<D>>,
+        query_map: QueryMap,
+        current_job: &Option<QueryJobId>,
         span: Span,
     ) -> CycleError {
         // Find the waitee amongst `current_job` parents
@@ -184,15 +156,15 @@ pub(super) fn find_cycle_in_stack(
 }
 
 #[cfg(parallel_compiler)]
-struct QueryWaiter<D> {
-    query: Option<QueryJobId<D>>,
+struct QueryWaiter {
+    query: Option<QueryJobId>,
     condvar: Condvar,
     span: Span,
     cycle: Lock<Option<CycleError>>,
 }
 
 #[cfg(parallel_compiler)]
-impl<D> QueryWaiter<D> {
+impl QueryWaiter {
     fn notify(&self, registry: &rayon_core::Registry) {
         rayon_core::mark_unblocked(registry);
         self.condvar.notify_one();
@@ -200,34 +172,27 @@ fn notify(&self, registry: &rayon_core::Registry) {
 }
 
 #[cfg(parallel_compiler)]
-struct QueryLatchInfo<D> {
+struct QueryLatchInfo {
     complete: bool,
-    waiters: Vec<Lrc<QueryWaiter<D>>>,
+    waiters: Vec<Lrc<QueryWaiter>>,
 }
 
 #[cfg(parallel_compiler)]
 #[derive(Clone)]
-pub(super) struct QueryLatch<D> {
-    info: Lrc<Mutex<QueryLatchInfo<D>>>,
+pub(super) struct QueryLatch {
+    info: Lrc<Mutex<QueryLatchInfo>>,
 }
 
 #[cfg(parallel_compiler)]
-impl<D: Eq + Hash> QueryLatch<D> {
+impl QueryLatch {
     fn new() -> Self {
         QueryLatch {
             info: Lrc::new(Mutex::new(QueryLatchInfo { complete: false, waiters: Vec::new() })),
         }
     }
-}
 
-#[cfg(parallel_compiler)]
-impl<D> QueryLatch<D> {
     /// Awaits for the query job to complete.
-    pub(super) fn wait_on(
-        &self,
-        query: Option<QueryJobId<D>>,
-        span: Span,
-    ) -> Result<(), CycleError> {
+    pub(super) fn wait_on(&self, query: Option<QueryJobId>, span: Span) -> Result<(), CycleError> {
         let waiter =
             Lrc::new(QueryWaiter { query, span, cycle: Lock::new(None), condvar: Condvar::new() });
         self.wait_on_inner(&waiter);
@@ -242,7 +207,7 @@ pub(super) fn wait_on(
     }
 
     /// Awaits the caller on this latch by blocking the current thread.
-    fn wait_on_inner(&self, waiter: &Lrc<QueryWaiter<D>>) {
+    fn wait_on_inner(&self, waiter: &Lrc<QueryWaiter>) {
         let mut info = self.info.lock();
         if !info.complete {
             // We push the waiter on to the `waiters` list. It can be accessed inside
@@ -276,7 +241,7 @@ fn set(&self) {
 
     /// Removes a single waiter from the list of waiters.
     /// This is used to break query cycles.
-    fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter<D>> {
+    fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter> {
         let mut info = self.info.lock();
         debug_assert!(!info.complete);
         // Remove the waiter from the list of waiters
@@ -286,7 +251,7 @@ fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter<D>> {
 
 /// A resumable waiter of a query. The usize is the index into waiters in the query's latch
 #[cfg(parallel_compiler)]
-type Waiter<D> = (QueryJobId<D>, usize);
+type Waiter = (QueryJobId, usize);
 
 /// Visits all the non-resumable and resumable waiters of a query.
 /// Only waiters in a query are visited.
@@ -298,14 +263,9 @@ fn extract_waiter(&self, waiter: usize) -> Lrc<QueryWaiter<D>> {
 /// required information to resume the waiter.
 /// If all `visit` calls returns None, this function also returns None.
 #[cfg(parallel_compiler)]
-fn visit_waiters<D, F>(
-    query_map: &QueryMap<D>,
-    query: QueryJobId<D>,
-    mut visit: F,
-) -> Option<Option<Waiter<D>>>
+fn visit_waiters<F>(query_map: &QueryMap, query: QueryJobId, mut visit: F) -> Option<Option<Waiter>>
 where
-    D: Copy + Clone + Eq + Hash,
-    F: FnMut(Span, QueryJobId<D>) -> Option<Option<Waiter<D>>>,
+    F: FnMut(Span, QueryJobId) -> Option<Option<Waiter>>,
 {
     // Visit the parent query which is a non-resumable waiter since it's on the same stack
     if let Some(parent) = query.parent(query_map) {
@@ -334,16 +294,13 @@ fn visit_waiters<D, F>(
 /// If a cycle is detected, this initial value is replaced with the span causing
 /// the cycle.
 #[cfg(parallel_compiler)]
-fn cycle_check<D>(
-    query_map: &QueryMap<D>,
-    query: QueryJobId<D>,
+fn cycle_check(
+    query_map: &QueryMap,
+    query: QueryJobId,
     span: Span,
-    stack: &mut Vec<(Span, QueryJobId<D>)>,
-    visited: &mut FxHashSet<QueryJobId<D>>,
-) -> Option<Option<Waiter<D>>>
-where
-    D: Copy + Clone + Eq + Hash,
-{
+    stack: &mut Vec<(Span, QueryJobId)>,
+    visited: &mut FxHashSet<QueryJobId>,
+) -> Option<Option<Waiter>> {
     if !visited.insert(query) {
         return if let Some(p) = stack.iter().position(|q| q.1 == query) {
             // We detected a query cycle, fix up the initial span and return Some
@@ -378,14 +335,11 @@ fn cycle_check<D>(
 /// from `query` without going through any of the queries in `visited`.
 /// This is achieved with a depth first search.
 #[cfg(parallel_compiler)]
-fn connected_to_root<D>(
-    query_map: &QueryMap<D>,
-    query: QueryJobId<D>,
-    visited: &mut FxHashSet<QueryJobId<D>>,
-) -> bool
-where
-    D: Copy + Clone + Eq + Hash,
-{
+fn connected_to_root(
+    query_map: &QueryMap,
+    query: QueryJobId,
+    visited: &mut FxHashSet<QueryJobId>,
+) -> bool {
     // We already visited this or we're deliberately ignoring it
     if !visited.insert(query) {
         return false;
@@ -404,10 +358,9 @@ fn connected_to_root<D>(
 
 // Deterministically pick an query from a list
 #[cfg(parallel_compiler)]
-fn pick_query<'a, D, T, F>(query_map: &QueryMap<D>, queries: &'a [T], f: F) -> &'a T
+fn pick_query<'a, T, F>(query_map: &QueryMap, queries: &'a [T], f: F) -> &'a T
 where
-    D: Copy + Clone + Eq + Hash,
-    F: Fn(&T) -> (Span, QueryJobId<D>),
+    F: Fn(&T) -> (Span, QueryJobId),
 {
     // Deterministically pick an entry point
     // FIXME: Sort this instead
@@ -431,10 +384,10 @@ fn pick_query<'a, D, T, F>(query_map: &QueryMap<D>, queries: &'a [T], f: F) -> &
 /// If a cycle was not found, the starting query is removed from `jobs` and
 /// the function returns false.
 #[cfg(parallel_compiler)]
-fn remove_cycle<D: DepKind>(
-    query_map: &QueryMap<D>,
-    jobs: &mut Vec<QueryJobId<D>>,
-    wakelist: &mut Vec<Lrc<QueryWaiter<D>>>,
+fn remove_cycle(
+    query_map: &QueryMap,
+    jobs: &mut Vec<QueryJobId>,
+    wakelist: &mut Vec<Lrc<QueryWaiter>>,
 ) -> bool {
     let mut visited = FxHashSet::default();
     let mut stack = Vec::new();
@@ -489,7 +442,7 @@ fn remove_cycle<D: DepKind>(
                     }
                 }
             })
-            .collect::<Vec<(Span, QueryJobId<D>, Option<(Span, QueryJobId<D>)>)>>();
+            .collect::<Vec<(Span, QueryJobId, Option<(Span, QueryJobId)>)>>();
 
         // Deterministically pick an entry point
         let (_, entry_point, usage) = pick_query(query_map, &entry_points, |e| (e.0, e.1));
@@ -544,7 +497,7 @@ pub fn deadlock<CTX: QueryContext>(tcx: CTX, registry: &rayon_core::Registry) {
 
     let mut wakelist = Vec::new();
     let query_map = tcx.try_collect_active_jobs().unwrap();
-    let mut jobs: Vec<QueryJobId<CTX::DepKind>> = query_map.keys().cloned().collect();
+    let mut jobs: Vec<QueryJobId> = query_map.keys().cloned().collect();
 
     let mut found_cycle = false;
 
@@ -630,7 +583,7 @@ pub(crate) fn report_cycle<'a>(
 
 pub fn print_query_stack<CTX: QueryContext>(
     tcx: CTX,
-    mut current_query: Option<QueryJobId<CTX::DepKind>>,
+    mut current_query: Option<QueryJobId>,
     handler: &Handler,
     num_frames: Option<usize>,
 ) -> usize {
index a2f7843baaa680b2c1b52cf679646d470102f0ae..361ae3c43527dcd26eb701df848f4d642ace24c9 100644 (file)
@@ -117,10 +117,12 @@ pub fn append(&mut self, other: QuerySideEffects) {
 }
 
 pub trait QueryContext: HasDepContext {
+    fn next_job_id(&self) -> QueryJobId;
+
     /// Get the query information from the TLS context.
-    fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>;
+    fn current_query_job(&self) -> Option<QueryJobId>;
 
-    fn try_collect_active_jobs(&self) -> Option<QueryMap<Self::DepKind>>;
+    fn try_collect_active_jobs(&self) -> Option<QueryMap>;
 
     /// Load side effects associated to the node in the previous session.
     fn load_side_effects(&self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects;
@@ -140,7 +142,7 @@ fn store_side_effects_for_anon_node(
     /// captured during execution and the actual result.
     fn start_query<R>(
         &self,
-        token: QueryJobId<Self::DepKind>,
+        token: QueryJobId,
         diagnostics: Option<&Lock<ThinVec<Diagnostic>>>,
         compute: impl FnOnce() -> R,
     ) -> R;
index da1f3617647804b835a289dcbb6ca6218ee54326..77e1fd3f2ccbbda9952dda4d3faa617db717214f 100644 (file)
@@ -5,9 +5,7 @@
 use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams};
 use crate::query::caches::QueryCache;
 use crate::query::config::{QueryDescription, QueryVtable};
-use crate::query::job::{
-    report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
-};
+use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
 use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHasher};
@@ -24,7 +22,6 @@
 use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
 use std::mem;
-use std::num::NonZeroU32;
 use std::ptr;
 
 pub struct QueryCacheStore<C: QueryCache> {
@@ -69,36 +66,32 @@ pub fn iter_results(&self, f: &mut dyn FnMut(&C::Key, &C::Value, DepNodeIndex))
     }
 }
 
-struct QueryStateShard<D, K> {
-    active: FxHashMap<K, QueryResult<D>>,
-
-    /// Used to generate unique ids for active jobs.
-    jobs: u32,
+struct QueryStateShard<K> {
+    active: FxHashMap<K, QueryResult>,
 }
 
-impl<D, K> Default for QueryStateShard<D, K> {
-    fn default() -> QueryStateShard<D, K> {
-        QueryStateShard { active: Default::default(), jobs: 0 }
+impl<K> Default for QueryStateShard<K> {
+    fn default() -> QueryStateShard<K> {
+        QueryStateShard { active: Default::default() }
     }
 }
 
-pub struct QueryState<D, K> {
-    shards: Sharded<QueryStateShard<D, K>>,
+pub struct QueryState<K> {
+    shards: Sharded<QueryStateShard<K>>,
 }
 
 /// Indicates the state of a query for a given key in a query map.
-enum QueryResult<D> {
+enum QueryResult {
     /// An already executing query. The query job can be used to await for its completion.
-    Started(QueryJob<D>),
+    Started(QueryJob),
 
     /// The query panicked. Queries trying to wait on this will raise a fatal error which will
     /// silently panic.
     Poisoned,
 }
 
-impl<D, K> QueryState<D, K>
+impl<K> QueryState<K>
 where
-    D: Copy + Clone + Eq + Hash,
     K: Eq + Hash + Clone + Debug,
 {
     pub fn all_inactive(&self) -> bool {
@@ -109,19 +102,17 @@ pub fn all_inactive(&self) -> bool {
     pub fn try_collect_active_jobs<CTX: Copy>(
         &self,
         tcx: CTX,
-        kind: D,
         make_query: fn(CTX, K) -> QueryStackFrame,
-        jobs: &mut QueryMap<D>,
+        jobs: &mut QueryMap,
     ) -> Option<()> {
         // We use try_lock_shards here since we are called from the
         // deadlock handler, and this shouldn't be locked.
         let shards = self.shards.try_lock_shards()?;
-        for (shard_id, shard) in shards.iter().enumerate() {
+        for shard in shards.iter() {
             for (k, v) in shard.active.iter() {
                 if let QueryResult::Started(ref job) = *v {
-                    let id = QueryJobId::new(job.id, shard_id, kind);
                     let query = make_query(tcx, k.clone());
-                    jobs.insert(id, QueryJobInfo { query, job: job.clone() });
+                    jobs.insert(job.id, QueryJobInfo { query, job: job.clone() });
                 }
             }
         }
@@ -130,22 +121,21 @@ pub fn try_collect_active_jobs<CTX: Copy>(
     }
 }
 
-impl<D, K> Default for QueryState<D, K> {
-    fn default() -> QueryState<D, K> {
+impl<K> Default for QueryState<K> {
+    fn default() -> QueryState<K> {
         QueryState { shards: Default::default() }
     }
 }
 
 /// A type representing the responsibility to execute the job in the `job` field.
 /// This will poison the relevant query if dropped.
-struct JobOwner<'tcx, D, K>
+struct JobOwner<'tcx, K>
 where
-    D: Copy + Clone + Eq + Hash,
     K: Eq + Hash + Clone,
 {
-    state: &'tcx QueryState<D, K>,
+    state: &'tcx QueryState<K>,
     key: K,
-    id: QueryJobId<D>,
+    id: QueryJobId,
 }
 
 #[cold]
@@ -166,9 +156,8 @@ fn mk_cycle<CTX, V, R>(
     cache.store_nocache(value)
 }
 
-impl<'tcx, D, K> JobOwner<'tcx, D, K>
+impl<'tcx, K> JobOwner<'tcx, K>
 where
-    D: Copy + Clone + Eq + Hash,
     K: Eq + Hash + Clone,
 {
     /// Either gets a `JobOwner` corresponding the query, allowing us to
@@ -182,12 +171,11 @@ impl<'tcx, D, K> JobOwner<'tcx, D, K>
     #[inline(always)]
     fn try_start<'b, CTX>(
         tcx: &'b CTX,
-        state: &'b QueryState<CTX::DepKind, K>,
+        state: &'b QueryState<K>,
         span: Span,
         key: K,
         lookup: QueryLookup,
-        dep_kind: CTX::DepKind,
-    ) -> TryGetJob<'b, CTX::DepKind, K>
+    ) -> TryGetJob<'b, K>
     where
         CTX: QueryContext,
     {
@@ -197,27 +185,21 @@ fn try_start<'b, CTX>(
 
         match lock.active.entry(key) {
             Entry::Vacant(entry) => {
-                // Generate an id unique within this shard.
-                let id = lock.jobs.checked_add(1).unwrap();
-                lock.jobs = id;
-                let id = QueryShardJobId(NonZeroU32::new(id).unwrap());
-
+                let id = tcx.next_job_id();
                 let job = tcx.current_query_job();
                 let job = QueryJob::new(id, span, job);
 
                 let key = entry.key().clone();
                 entry.insert(QueryResult::Started(job));
 
-                let global_id = QueryJobId::new(id, shard, dep_kind);
-                let owner = JobOwner { state, id: global_id, key };
+                let owner = JobOwner { state, id, key };
                 return TryGetJob::NotYetStarted(owner);
             }
             Entry::Occupied(mut entry) => {
                 match entry.get_mut() {
                     #[cfg(not(parallel_compiler))]
                     QueryResult::Started(job) => {
-                        let id = QueryJobId::new(job.id, shard, dep_kind);
-
+                        let id = job.id;
                         drop(state_lock);
 
                         // If we are single-threaded we know that we have cycle error,
@@ -295,9 +277,8 @@ fn complete<C>(
     }
 }
 
-impl<'tcx, D, K> Drop for JobOwner<'tcx, D, K>
+impl<'tcx, K> Drop for JobOwner<'tcx, K>
 where
-    D: Copy + Clone + Eq + Hash,
     K: Eq + Hash + Clone,
 {
     #[inline(never)]
@@ -329,13 +310,12 @@ pub(crate) struct CycleError {
 }
 
 /// The result of `try_start`.
-enum TryGetJob<'tcx, D, K>
+enum TryGetJob<'tcx, K>
 where
-    D: Copy + Clone + Eq + Hash,
     K: Eq + Hash + Clone,
 {
     /// The query is not yet started. Contains a guard to the cache eventually used to start it.
-    NotYetStarted(JobOwner<'tcx, D, K>),
+    NotYetStarted(JobOwner<'tcx, K>),
 
     /// The query was already completed.
     /// Returns the result of the query and its dep-node index
@@ -375,7 +355,7 @@ pub fn try_get_cached<'a, CTX, C, R, OnHit>(
 
 fn try_execute_query<CTX, C>(
     tcx: CTX,
-    state: &QueryState<CTX::DepKind, C::Key>,
+    state: &QueryState<C::Key>,
     cache: &QueryCacheStore<C>,
     span: Span,
     key: C::Key,
@@ -388,14 +368,7 @@ fn try_execute_query<CTX, C>(
     C::Key: Clone + DepNodeParams<CTX::DepContext>,
     CTX: QueryContext,
 {
-    match JobOwner::<'_, CTX::DepKind, C::Key>::try_start(
-        &tcx,
-        state,
-        span,
-        key.clone(),
-        lookup,
-        query.dep_kind,
-    ) {
+    match JobOwner::<'_, C::Key>::try_start(&tcx, state, span, key.clone(), lookup) {
         TryGetJob::NotYetStarted(job) => {
             let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id);
             let result = job.complete(cache, result, dep_node_index);
@@ -427,7 +400,7 @@ fn execute_job<CTX, K, V>(
     key: K,
     mut dep_node_opt: Option<DepNode<CTX::DepKind>>,
     query: &QueryVtable<CTX, K, V>,
-    job_id: QueryJobId<CTX::DepKind>,
+    job_id: QueryJobId,
 ) -> (V, DepNodeIndex)
 where
     K: Clone + DepNodeParams<CTX::DepContext>,
index e4d8b7d528319cd3d770784132a079f7ca5355f3..3fa9343c399adf2a32115a9c5ae63a7552764ab8 100644 (file)
@@ -991,7 +991,7 @@ fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) {
                 _,
             )
             | Res::Local(..)
-            | Res::SelfTy(..)
+            | Res::SelfTy { .. }
             | Res::SelfCtor(..)
             | Res::Err => bug!("unexpected resolution: {:?}", res),
         }
index c7edcb077b917ec7a0582ae891aae2138fd66efe..4b85531557c68d2a36b92fcf0d5e307d9bdc03a2 100644 (file)
@@ -123,7 +123,7 @@ impl<'a> Resolver<'a> {
 
                 let sm = self.session.source_map();
                 match outer_res {
-                    Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => {
+                    Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => {
                         if let Some(impl_span) =
                             maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id))
                         {
@@ -453,28 +453,28 @@ impl<'a> Resolver<'a> {
                 // edit:
                 // only do this if the const and usage of the non-constant value are on the same line
                 // the further the two are apart, the higher the chance of the suggestion being wrong
-                // also make sure that the pos for the suggestion is not 0 (ICE #90878)
 
-                let sp =
-                    self.session.source_map().span_extend_to_prev_str(ident.span, current, true);
-
-                let pos_for_suggestion = sp.lo().0.saturating_sub(current.len() as u32);
+                let sp = self
+                    .session
+                    .source_map()
+                    .span_extend_to_prev_str(ident.span, current, true, false);
 
-                if sp.lo().0 == 0
-                    || pos_for_suggestion == 0
-                    || self.session.source_map().is_multiline(sp)
-                {
-                    err.span_label(ident.span, &format!("this would need to be a `{}`", sugg));
-                } else {
-                    let sp = sp.with_lo(BytePos(pos_for_suggestion));
-                    err.span_suggestion(
-                        sp,
-                        &format!("consider using `{}` instead of `{}`", sugg, current),
-                        format!("{} {}", sugg, ident),
-                        Applicability::MaybeIncorrect,
-                    );
-                    err.span_label(span, "non-constant value");
+                match sp {
+                    Some(sp) if !self.session.source_map().is_multiline(sp) => {
+                        let sp = sp.with_lo(BytePos(sp.lo().0 - (current.len() as u32)));
+                        err.span_suggestion(
+                            sp,
+                            &format!("consider using `{}` instead of `{}`", sugg, current),
+                            format!("{} {}", sugg, ident),
+                            Applicability::MaybeIncorrect,
+                        );
+                        err.span_label(span, "non-constant value");
+                    }
+                    _ => {
+                        err.span_label(ident.span, &format!("this would need to be a `{}`", sugg));
+                    }
                 }
+
                 err
             }
             ResolutionError::BindingShadowsSomethingUnacceptable {
index e7f76a18ad31addf4cb8608b1b052c2ed4260f1f..a8c2a5e1424b829712ec6666a6f38aaf397cd641 100644 (file)
@@ -11,7 +11,7 @@
 
 use rustc_ast::NodeId;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::ptr_key::PtrKey;
+use rustc_data_structures::intern::Interned;
 use rustc_errors::{pluralize, struct_span_err, Applicability};
 use rustc_hir::def::{self, PartialRes};
 use rustc_hir::def_id::DefId;
@@ -134,7 +134,7 @@ pub fn is_nested(&self) -> bool {
 pub struct NameResolution<'a> {
     /// Single imports that may define the name in the namespace.
     /// Imports are arena-allocated, so it's ok to use pointers as keys.
-    single_imports: FxHashSet<PtrKey<'a, Import<'a>>>,
+    single_imports: FxHashSet<Interned<'a, Import<'a>>>,
     /// The least shadowable known binding for this name, or None if there are no known bindings.
     pub binding: Option<&'a NameBinding<'a>>,
     shadowed_glob: Option<&'a NameBinding<'a>>,
@@ -153,7 +153,7 @@ pub(crate) fn binding(&self) -> Option<&'a NameBinding<'a>> {
     }
 
     crate fn add_single_import(&mut self, import: &'a Import<'a>) {
-        self.single_imports.insert(PtrKey(import));
+        self.single_imports.insert(Interned::new_unchecked(import));
     }
 }
 
@@ -850,7 +850,7 @@ fn resolve_import(&mut self, import: &'b Import<'b>) -> bool {
                     Err(Determined) => {
                         let key = this.new_key(target, ns);
                         this.update_resolution(parent, key, |_, resolution| {
-                            resolution.single_imports.remove(&PtrKey(import));
+                            resolution.single_imports.remove(&Interned::new_unchecked(import));
                         });
                     }
                     Ok(binding) if !binding.is_importable() => {
index 6aed3223480f1a93645fb95f00ddeec878a0a0f0..9ac3e6e22bd9d81aa17f4b9c49ca1812e8acd9a3 100644 (file)
@@ -289,7 +289,7 @@ fn is_call(self) -> bool {
                         | DefKind::ForeignTy,
                     _,
                 ) | Res::PrimTy(..)
-                    | Res::SelfTy(..)
+                    | Res::SelfTy { .. }
             ),
             PathSource::Trait(AliasPossibility::No) => matches!(res, Res::Def(DefKind::Trait, _)),
             PathSource::Trait(AliasPossibility::Maybe) => {
@@ -326,7 +326,7 @@ fn is_call(self) -> bool {
                         | DefKind::TyAlias
                         | DefKind::AssocTy,
                     _,
-                ) | Res::SelfTy(..)
+                ) | Res::SelfTy { .. }
             ),
             PathSource::TraitItem(ns) => match res {
                 Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) if ns == ValueNS => true,
@@ -911,9 +911,12 @@ fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) {
         self.with_current_self_item(item, |this| {
             this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
                 let item_def_id = this.r.local_def_id(item.id).to_def_id();
-                this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| {
-                    visit::walk_item(this, item);
-                });
+                this.with_self_rib(
+                    Res::SelfTy { trait_: None, alias_to: Some((item_def_id, false)) },
+                    |this| {
+                        visit::walk_item(this, item);
+                    },
+                );
             });
         });
     }
@@ -999,8 +1002,8 @@ fn resolve_item(&mut self, item: &'ast Item) {
                 self.compute_num_lifetime_params(item.id, generics);
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    let local_def_id = this.r.local_def_id(item.id).to_def_id();
-                    this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
+                    let def = this.r.local_def_id(item.id).to_def_id();
+                    this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
                         this.visit_generics(generics);
                         walk_list!(this, visit_param_bound, bounds);
 
@@ -1051,8 +1054,8 @@ fn resolve_item(&mut self, item: &'ast Item) {
                 self.compute_num_lifetime_params(item.id, generics);
                 // Create a new rib for the trait-wide type parameters.
                 self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
-                    let local_def_id = this.r.local_def_id(item.id).to_def_id();
-                    this.with_self_rib(Res::SelfTy(Some(local_def_id), None), |this| {
+                    let def = this.r.local_def_id(item.id).to_def_id();
+                    this.with_self_rib(Res::SelfTy { trait_: Some(def), alias_to: None }, |this| {
                         this.visit_generics(generics);
                         walk_list!(this, visit_param_bound, bounds);
                     });
@@ -1296,7 +1299,7 @@ fn resolve_implementation(
         // If applicable, create a rib for the type parameters.
         self.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| {
             // Dummy self type for better errors if `Self` is used in the trait path.
-            this.with_self_rib(Res::SelfTy(None, None), |this| {
+            this.with_self_rib(Res::SelfTy { trait_: None, alias_to: None }, |this| {
                 // Resolve the trait reference, if necessary.
                 this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| {
                     let item_def_id = this.r.local_def_id(item_id);
@@ -1307,7 +1310,9 @@ fn resolve_implementation(
                     }
 
                     let item_def_id = item_def_id.to_def_id();
-                    this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| {
+                    let res =
+                        Res::SelfTy { trait_: trait_id, alias_to: Some((item_def_id, false)) };
+                    this.with_self_rib(res, |this| {
                         if let Some(trait_ref) = opt_trait_reference.as_ref() {
                             // Resolve type arguments in the trait path.
                             visit::walk_trait_ref(this, trait_ref);
index d05f139e3bf5aaf9876a78708a614b766b967146..f9926a71c30ac2cd44c6cb9628fa18a3cecd7e23 100644 (file)
@@ -704,7 +704,7 @@ fn restrict_assoc_type_in_where_clause(
         ) = &bounded_ty.kind
         {
             // use this to verify that ident is a type param.
-            let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
+            let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
                 bounded_ty.id,
                 None,
                 &Segment::from_path(path),
@@ -712,9 +712,7 @@ fn restrict_assoc_type_in_where_clause(
                 span,
                 true,
                 CrateLint::No,
-            ) {
-                partial_res
-            } else {
+            ) else {
                 return false;
             };
             if !(matches!(
@@ -731,7 +729,7 @@ fn restrict_assoc_type_in_where_clause(
 
         if let ast::TyKind::Path(None, type_param_path) = &ty.peel_refs().kind {
             // Confirm that the `SelfTy` is a type parameter.
-            let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
+            let Ok(Some(partial_res)) = self.resolve_qpath_anywhere(
                 bounded_ty.id,
                 None,
                 &Segment::from_path(type_param_path),
@@ -739,9 +737,7 @@ fn restrict_assoc_type_in_where_clause(
                 span,
                 true,
                 CrateLint::No,
-            ) {
-                partial_res
-            } else {
+            ) else {
                 return false;
             };
             if !(matches!(
@@ -1189,7 +1185,7 @@ fn smart_resolve_context_dependent_help(
                     Applicability::HasPlaceholders,
                 );
             }
-            (Res::SelfTy(..), _) if ns == ValueNS => {
+            (Res::SelfTy { .. }, _) if ns == ValueNS => {
                 err.span_label(span, fallback_label);
                 err.note("can't use `Self` as a constructor, you must use the implemented struct");
             }
index 6ef85c426be7040839311d9f414902ad076028de..3bea95fa1d554ecfcaa418cd8c909dbce92902e2 100644 (file)
@@ -41,9 +41,9 @@ pub enum LifetimeUseSet<'tcx> {
 }
 
 trait RegionExt {
-    fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region);
+    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region);
 
-    fn late(index: u32, hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region);
+    fn late(index: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region);
 
     fn late_anon(named_late_bound_vars: u32, index: &Cell<u32>) -> Region;
 
@@ -59,7 +59,7 @@ fn subst<'a, L>(self, params: L, map: &NamedRegionMap) -> Option<Region>
 }
 
 impl RegionExt for Region {
-    fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) {
+    fn early(hir_map: Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (ParamName, Region) {
         let i = *index;
         *index += 1;
         let def_id = hir_map.local_def_id(param.hir_id);
@@ -68,7 +68,7 @@ fn early(hir_map: &Map<'_>, index: &mut u32, param: &GenericParam<'_>) -> (Param
         (param.name.normalize_to_macros_2_0(), Region::EarlyBound(i, def_id.to_def_id(), origin))
     }
 
-    fn late(idx: u32, hir_map: &Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) {
+    fn late(idx: u32, hir_map: Map<'_>, param: &GenericParam<'_>) -> (ParamName, Region) {
         let depth = ty::INNERMOST;
         let def_id = hir_map.local_def_id(param.hir_id);
         let origin = LifetimeDefOrigin::from_param(param);
@@ -377,7 +377,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
 
         named_region_map: |tcx, id| resolve_lifetimes_for(tcx, id).defs.get(&id),
         is_late_bound_map,
-        object_lifetime_defaults_map: |tcx, id| match tcx.hir().find_by_def_id(id) {
+        object_lifetime_defaults: |tcx, id| match tcx.hir().find_by_def_id(id) {
             Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item),
             _ => None,
         },
@@ -817,7 +817,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     .iter()
                     .filter_map(|param| match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(&self.tcx.hir(), &mut index, param))
+                            Some(Region::early(self.tcx.hir(), &mut index, param))
                         }
                         GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
                             non_lifetime_count += 1;
@@ -888,7 +888,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
                     .enumerate()
                     .map(|(late_bound_idx, param)| {
-                        let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param);
+                        let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
                         let r = late_region_as_bound_region(self.tcx, &pair.1);
                         (pair, r)
                     })
@@ -1045,7 +1045,7 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                 for param in generics.params {
                     match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            let (name, reg) = Region::early(&self.tcx.hir(), &mut index, &param);
+                            let (name, reg) = Region::early(self.tcx.hir(), &mut index, &param);
                             let Region::EarlyBound(_, def_id, _) = reg else {
                                 bug!();
                             };
@@ -1145,7 +1145,7 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
                     .iter()
                     .filter_map(|param| match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(&self.tcx.hir(), &mut index, param))
+                            Some(Region::early(self.tcx.hir(), &mut index, param))
                         }
                         GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
                             non_lifetime_count += 1;
@@ -1214,7 +1214,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
                     .iter()
                     .filter_map(|param| match param.kind {
                         GenericParamKind::Lifetime { .. } => {
-                            Some(Region::early(&self.tcx.hir(), &mut index, param))
+                            Some(Region::early(self.tcx.hir(), &mut index, param))
                         }
                         GenericParamKind::Const { .. } | GenericParamKind::Type { .. } => {
                             non_lifetime_count += 1;
@@ -1339,11 +1339,14 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                             this.visit_ty(&ty);
                         }
                     }
-                    GenericParamKind::Const { ref ty, .. } => {
+                    GenericParamKind::Const { ref ty, default } => {
                         let was_in_const_generic = this.is_in_const_generic;
                         this.is_in_const_generic = true;
                         walk_list!(this, visit_param_bound, param.bounds);
                         this.visit_ty(&ty);
+                        if let Some(default) = default {
+                            this.visit_body(this.tcx.hir().body(default.body));
+                        }
                         this.is_in_const_generic = was_in_const_generic;
                     }
                 }
@@ -1365,7 +1368,7 @@ fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
                                 .enumerate()
                                 .map(|(late_bound_idx, param)| {
                                     let pair =
-                                        Region::late(late_bound_idx as u32, &this.tcx.hir(), param);
+                                        Region::late(late_bound_idx as u32, this.tcx.hir(), param);
                                     let r = late_region_as_bound_region(this.tcx, &pair.1);
                                     (pair, r)
                                 })
@@ -1460,11 +1463,8 @@ fn visit_poly_trait_ref(
             .filter(|param| matches!(param.kind, GenericParamKind::Lifetime { .. }))
             .enumerate()
             .map(|(late_bound_idx, param)| {
-                let pair = Region::late(
-                    initial_bound_vars + late_bound_idx as u32,
-                    &self.tcx.hir(),
-                    param,
-                );
+                let pair =
+                    Region::late(initial_bound_vars + late_bound_idx as u32, self.tcx.hir(), param);
                 let r = late_region_as_bound_region(self.tcx, &pair.1);
                 lifetimes.insert(pair.0, pair.1);
                 r
@@ -1670,10 +1670,10 @@ fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, lab
     }
 }
 
-fn compute_object_lifetime_defaults(
-    tcx: TyCtxt<'_>,
+fn compute_object_lifetime_defaults<'tcx>(
+    tcx: TyCtxt<'tcx>,
     item: &hir::Item<'_>,
-) -> Option<Vec<ObjectLifetimeDefault>> {
+) -> Option<&'tcx [ObjectLifetimeDefault]> {
     match item.kind {
         hir::ItemKind::Struct(_, ref generics)
         | hir::ItemKind::Union(_, ref generics)
@@ -1726,10 +1726,10 @@ fn compute_object_lifetime_defaults(
 /// Scan the bounds and where-clauses on parameters to extract bounds
 /// of the form `T:'a` so as to determine the `ObjectLifetimeDefault`
 /// for each type parameter.
-fn object_lifetime_defaults_for_item(
-    tcx: TyCtxt<'_>,
+fn object_lifetime_defaults_for_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
     generics: &hir::Generics<'_>,
-) -> Vec<ObjectLifetimeDefault> {
+) -> &'tcx [ObjectLifetimeDefault] {
     fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound<'_>]) {
         for bound in bounds {
             if let hir::GenericBound::Outlives(ref lifetime) = *bound {
@@ -1738,81 +1738,75 @@ fn add_bounds(set: &mut Set1<hir::LifetimeName>, bounds: &[hir::GenericBound<'_>
         }
     }
 
-    generics
-        .params
-        .iter()
-        .filter_map(|param| match param.kind {
-            GenericParamKind::Lifetime { .. } => None,
-            GenericParamKind::Type { .. } => {
-                let mut set = Set1::Empty;
-
-                add_bounds(&mut set, &param.bounds);
-
-                let param_def_id = tcx.hir().local_def_id(param.hir_id);
-                for predicate in generics.where_clause.predicates {
-                    // Look for `type: ...` where clauses.
-                    let data = match *predicate {
-                        hir::WherePredicate::BoundPredicate(ref data) => data,
-                        _ => continue,
-                    };
+    let process_param = |param: &hir::GenericParam<'_>| match param.kind {
+        GenericParamKind::Lifetime { .. } => None,
+        GenericParamKind::Type { .. } => {
+            let mut set = Set1::Empty;
 
-                    // Ignore `for<'a> type: ...` as they can change what
-                    // lifetimes mean (although we could "just" handle it).
-                    if !data.bound_generic_params.is_empty() {
-                        continue;
-                    }
+            add_bounds(&mut set, &param.bounds);
 
-                    let res = match data.bounded_ty.kind {
-                        hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res,
-                        _ => continue,
-                    };
+            let param_def_id = tcx.hir().local_def_id(param.hir_id);
+            for predicate in generics.where_clause.predicates {
+                // Look for `type: ...` where clauses.
+                let data = match *predicate {
+                    hir::WherePredicate::BoundPredicate(ref data) => data,
+                    _ => continue,
+                };
 
-                    if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) {
-                        add_bounds(&mut set, &data.bounds);
-                    }
+                // Ignore `for<'a> type: ...` as they can change what
+                // lifetimes mean (although we could "just" handle it).
+                if !data.bound_generic_params.is_empty() {
+                    continue;
                 }
 
-                Some(match set {
-                    Set1::Empty => Set1::Empty,
-                    Set1::One(name) => {
-                        if name == hir::LifetimeName::Static {
-                            Set1::One(Region::Static)
-                        } else {
-                            generics
-                                .params
-                                .iter()
-                                .filter_map(|param| match param.kind {
-                                    GenericParamKind::Lifetime { .. } => Some((
-                                        param.hir_id,
-                                        hir::LifetimeName::Param(param.name),
-                                        LifetimeDefOrigin::from_param(param),
-                                    )),
-                                    _ => None,
-                                })
-                                .enumerate()
-                                .find(|&(_, (_, lt_name, _))| lt_name == name)
-                                .map_or(Set1::Many, |(i, (id, _, origin))| {
-                                    let def_id = tcx.hir().local_def_id(id);
-                                    Set1::One(Region::EarlyBound(
-                                        i as u32,
-                                        def_id.to_def_id(),
-                                        origin,
-                                    ))
-                                })
-                        }
-                    }
-                    Set1::Many => Set1::Many,
-                })
-            }
-            GenericParamKind::Const { .. } => {
-                // Generic consts don't impose any constraints.
-                //
-                // We still store a dummy value here to allow generic parameters
-                // in an arbitrary order.
-                Some(Set1::Empty)
+                let res = match data.bounded_ty.kind {
+                    hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.res,
+                    _ => continue,
+                };
+
+                if res == Res::Def(DefKind::TyParam, param_def_id.to_def_id()) {
+                    add_bounds(&mut set, &data.bounds);
+                }
             }
-        })
-        .collect()
+
+            Some(match set {
+                Set1::Empty => Set1::Empty,
+                Set1::One(name) => {
+                    if name == hir::LifetimeName::Static {
+                        Set1::One(Region::Static)
+                    } else {
+                        generics
+                            .params
+                            .iter()
+                            .filter_map(|param| match param.kind {
+                                GenericParamKind::Lifetime { .. } => Some((
+                                    param.hir_id,
+                                    hir::LifetimeName::Param(param.name),
+                                    LifetimeDefOrigin::from_param(param),
+                                )),
+                                _ => None,
+                            })
+                            .enumerate()
+                            .find(|&(_, (_, lt_name, _))| lt_name == name)
+                            .map_or(Set1::Many, |(i, (id, _, origin))| {
+                                let def_id = tcx.hir().local_def_id(id);
+                                Set1::One(Region::EarlyBound(i as u32, def_id.to_def_id(), origin))
+                            })
+                    }
+                }
+                Set1::Many => Set1::Many,
+            })
+        }
+        GenericParamKind::Const { .. } => {
+            // Generic consts don't impose any constraints.
+            //
+            // We still store a dummy value here to allow generic parameters
+            // in an arbitrary order.
+            Some(Set1::Empty)
+        }
+    };
+
+    tcx.arena.alloc_from_iter(generics.params.iter().filter_map(process_param))
 }
 
 impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
@@ -2197,9 +2191,9 @@ fn visit_early_late<F>(
                     if self.map.late_bound.contains(&param.hir_id) {
                         let late_bound_idx = named_late_bound_vars;
                         named_late_bound_vars += 1;
-                        Some(Region::late(late_bound_idx, &self.tcx.hir(), param))
+                        Some(Region::late(late_bound_idx, self.tcx.hir(), param))
                     } else {
-                        Some(Region::early(&self.tcx.hir(), &mut next_early_index, param))
+                        Some(Region::early(self.tcx.hir(), &mut next_early_index, param))
                     }
                 }
                 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
@@ -2219,7 +2213,7 @@ fn visit_early_late<F>(
             })
             .enumerate()
             .map(|(late_bound_idx, param)| {
-                let pair = Region::late(late_bound_idx as u32, &self.tcx.hir(), param);
+                let pair = Region::late(late_bound_idx as u32, self.tcx.hir(), param);
                 late_region_as_bound_region(self.tcx, &pair.1)
             })
             .collect();
@@ -2506,7 +2500,12 @@ fn visit_segment_args(
             };
             if let Some(def_id) = def_id.as_local() {
                 let id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-                self.tcx.object_lifetime_defaults(id).unwrap().iter().map(set_to_region).collect()
+                self.tcx
+                    .object_lifetime_defaults(id.owner)
+                    .unwrap()
+                    .iter()
+                    .map(set_to_region)
+                    .collect()
             } else {
                 let tcx = self.tcx;
                 self.xcrate_object_lifetime_defaults
@@ -2794,7 +2793,7 @@ impl SelfVisitor<'_> {
                 // Look for `self: &'a Self` - also desugared from `&'a self`,
                 // and if that matches, use it for elision and return early.
                 fn is_self_ty(&self, res: Res) -> bool {
-                    if let Res::SelfTy(..) = res {
+                    if let Res::SelfTy { .. } = res {
                         return true;
                     }
 
index 28f06ed3a261424f7ac2b71d786428f9ec6c0070..28d8d9247ac131b827ec0b44cc5c2301521a4b39 100644 (file)
@@ -38,7 +38,7 @@
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_data_structures::ptr_key::PtrKey;
+use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
@@ -964,7 +964,7 @@ pub struct Resolver<'a> {
     /// language items.
     empty_module: Module<'a>,
     module_map: FxHashMap<DefId, Module<'a>>,
-    binding_parent_modules: FxHashMap<PtrKey<'a, NameBinding<'a>>, Module<'a>>,
+    binding_parent_modules: FxHashMap<Interned<'a, NameBinding<'a>>, Module<'a>>,
     underscore_disambiguator: u32,
 
     /// Maps glob imports to the names of items actually imported.
@@ -1115,7 +1115,7 @@ fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> {
         self.name_resolutions.alloc(Default::default())
     }
     fn alloc_macro_rules_scope(&'a self, scope: MacroRulesScope<'a>) -> MacroRulesScopeRef<'a> {
-        PtrKey(self.dropless.alloc(Cell::new(scope)))
+        Interned::new_unchecked(self.dropless.alloc(Cell::new(scope)))
     }
     fn alloc_macro_rules_binding(
         &'a self,
@@ -2784,7 +2784,7 @@ fn validate_res_from_ribs(
                     return Res::Err;
                 }
             }
-            Res::Def(DefKind::TyParam, _) | Res::SelfTy(..) => {
+            Res::Def(DefKind::TyParam, _) | Res::SelfTy { .. } => {
                 for rib in ribs {
                     let has_generic_params: HasGenericParams = match rib.kind {
                         NormalRibKind
@@ -2804,8 +2804,8 @@ fn validate_res_from_ribs(
                                 // HACK(min_const_generics): If we encounter `Self` in an anonymous constant
                                 // we can't easily tell if it's generic at this stage, so we instead remember
                                 // this and then enforce the self type to be concrete later on.
-                                if let Res::SelfTy(trait_def, Some((impl_def, _))) = res {
-                                    res = Res::SelfTy(trait_def, Some((impl_def, true)));
+                                if let Res::SelfTy { trait_, alias_to: Some((def, _)) } = res {
+                                    res = Res::SelfTy { trait_, alias_to: Some((def, true)) }
                                 } else {
                                     if record_used {
                                         self.report_error(
@@ -2938,7 +2938,9 @@ fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
     }
 
     fn set_binding_parent_module(&mut self, binding: &'a NameBinding<'a>, module: Module<'a>) {
-        if let Some(old_module) = self.binding_parent_modules.insert(PtrKey(binding), module) {
+        if let Some(old_module) =
+            self.binding_parent_modules.insert(Interned::new_unchecked(binding), module)
+        {
             if !ptr::eq(module, old_module) {
                 span_bug!(binding.span, "parent module is reset for binding");
             }
@@ -2954,8 +2956,8 @@ fn disambiguate_macro_rules_vs_modularized(
         // is disambiguated to mitigate regressions from macro modularization.
         // Scoping for `macro_rules` behaves like scoping for `let` at module level, in general.
         match (
-            self.binding_parent_modules.get(&PtrKey(macro_rules)),
-            self.binding_parent_modules.get(&PtrKey(modularized)),
+            self.binding_parent_modules.get(&Interned::new_unchecked(macro_rules)),
+            self.binding_parent_modules.get(&Interned::new_unchecked(modularized)),
         ) {
             (Some(macro_rules), Some(modularized)) => {
                 macro_rules.nearest_parent_mod() == modularized.nearest_parent_mod()
index 82807e2d0a2c55b281e18ec85de513299f2fd682..89c2a0c74bd36b950f89d88b749b00dc06b86b0e 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_ast_pretty::pprust;
 use rustc_attr::StabilityLevel;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::ptr_key::PtrKey;
+use rustc_data_structures::intern::Interned;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::struct_span_err;
 use rustc_expand::base::{Annotatable, DeriveResolutions, Indeterminate, ResolverExpand};
@@ -71,7 +71,7 @@ pub enum MacroRulesScope<'a> {
 /// This helps to avoid uncontrollable growth of `macro_rules!` scope chains,
 /// which usually grow lineraly with the number of macro invocations
 /// in a module (including derives) and hurt performance.
-pub(crate) type MacroRulesScopeRef<'a> = PtrKey<'a, Cell<MacroRulesScope<'a>>>;
+pub(crate) type MacroRulesScopeRef<'a> = Interned<'a, Cell<MacroRulesScope<'a>>>;
 
 // Macro namespace is separated into two sub-namespaces, one for bang macros and
 // one for attribute-like macros (attributes, derives).
index a3f7e84b1d524b5ccca0d5feb7481813c5c691da..0ff56a30ea005fb50d43996b0632e5c39dfe2024 100644 (file)
@@ -262,7 +262,7 @@ fn process_method(
     ) {
         debug!("process_method: {:?}:{}", def_id, ident);
 
-        let map = &self.tcx.hir();
+        let map = self.tcx.hir();
         let hir_id = map.local_def_id_to_hir_id(def_id);
         self.nest_typeck_results(def_id, |v| {
             if let Some(mut method_data) = v.save_ctxt.get_method_data(hir_id, ident, span) {
@@ -361,7 +361,7 @@ fn process_fn(
         ty_params: &'tcx hir::Generics<'tcx>,
         body: hir::BodyId,
     ) {
-        let map = &self.tcx.hir();
+        let map = self.tcx.hir();
         self.nest_typeck_results(item.def_id, |v| {
             let body = map.body(body);
             if let Some(fn_data) = v.save_ctxt.get_item_data(item) {
@@ -626,7 +626,7 @@ fn process_impl(&mut self, item: &'tcx hir::Item<'tcx>, impl_: &'tcx hir::Impl<'
             }
         }
 
-        let map = &self.tcx.hir();
+        let map = self.tcx.hir();
         self.nest_typeck_results(item.def_id, |v| {
             v.visit_ty(&impl_.self_ty);
             if let Some(trait_ref) = &impl_.of_trait {
@@ -716,7 +716,7 @@ fn process_trait(
         // walk generics and methods
         self.process_generic_params(generics, &qualname, item.hir_id());
         for method in methods {
-            let map = &self.tcx.hir();
+            let map = self.tcx.hir();
             self.process_trait_item(map.trait_item(method.id), item.def_id.to_def_id())
         }
     }
@@ -921,7 +921,7 @@ fn process_var_decl(&mut self, pat: &'tcx hir::Pat<'tcx>) {
                     | HirDefKind::AssocTy,
                     _,
                 )
-                | Res::SelfTy(..) => {
+                | Res::SelfTy { .. } => {
                     self.dump_path_segment_ref(id, &hir::PathSegment::from_ident(ident));
                 }
                 def => {
index 2eebddb47df5c24d2f7f4ea74ad05c36996d8b18..8b0adba9fab15b0202765c791ce53aaffc743ac0 100644 (file)
@@ -749,7 +749,7 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
                 _,
             )
             | Res::PrimTy(..)
-            | Res::SelfTy(..)
+            | Res::SelfTy { .. }
             | Res::ToolMod
             | Res::NonMacroAttr(..)
             | Res::SelfCtor(..)
@@ -814,7 +814,7 @@ fn get_macro_use_data(&self, span: Span) -> Option<MacroRef> {
 
     fn lookup_def_id(&self, ref_id: hir::HirId) -> Option<DefId> {
         match self.get_path_res(ref_id) {
-            Res::PrimTy(_) | Res::SelfTy(..) | Res::Err => None,
+            Res::PrimTy(_) | Res::SelfTy { .. } | Res::Err => None,
             def => def.opt_def_id(),
         }
     }
index 4971bb6d1aad7bff565fd43bf957cfae6b7620cd..3bb1d2ff35730ad5ecc45d32c641ae303ebf4ef1 100644 (file)
@@ -573,7 +573,7 @@ fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) ->
         let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
 
         let (name, start, end) = match res {
-            Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => {
+            Res::PrimTy(..) | Res::SelfTy { .. } | Res::Err => {
                 return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] });
             }
             Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => {
index 044de8e4e24839eedd178a8dd92d56819cb26255..6a3985492412262d382a0160922ddd24b94d5f3e 100644 (file)
 
 use std::borrow::Cow;
 use std::collections::{BTreeMap, HashMap};
-use std::io;
-use std::io::prelude::*;
 use std::mem::swap;
 use std::num::FpCategory as Fp;
 use std::ops::Index;
@@ -250,7 +248,6 @@ pub enum ErrorCode {
 pub enum ParserError {
     /// msg, line, col
     SyntaxError(ErrorCode, usize, usize),
-    IoError(io::ErrorKind, String),
 }
 
 // Builder and Parser have the same errors.
@@ -329,10 +326,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-fn io_error_to_error(io: io::Error) -> ParserError {
-    IoError(io.kind(), io.to_string())
-}
-
 impl fmt::Display for ParserError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // FIXME this should be a nicer error
@@ -2163,21 +2156,6 @@ fn build_object(&mut self) -> Result<Json, BuilderError> {
     }
 }
 
-/// Decodes a json value from an `&mut io::Read`
-pub fn from_reader(rdr: &mut dyn Read) -> Result<Json, BuilderError> {
-    let mut contents = Vec::new();
-    match rdr.read_to_end(&mut contents) {
-        Ok(c) => c,
-        Err(e) => return Err(io_error_to_error(e)),
-    };
-    let s = match str::from_utf8(&contents).ok() {
-        Some(s) => s,
-        _ => return Err(SyntaxError(NotUtf8, 0, 0)),
-    };
-    let mut builder = Builder::new(s.chars());
-    builder.build()
-}
-
 /// Decodes a json value from a string
 pub fn from_str(s: &str) -> Result<Json, BuilderError> {
     let mut builder = Builder::new(s.chars());
index d2d5b06ad67b622553d6930cad8eb46e652f4c86..68e7cc3dc98746f2a472bf0a44f8d8e3fd28ad15 100644 (file)
@@ -63,6 +63,22 @@ pub enum CFGuard {
     Checks,
 }
 
+/// The different settings that the `-Z cf-protection` flag can have.
+#[derive(Clone, Copy, PartialEq, Hash, Debug)]
+pub enum CFProtection {
+    /// Do not enable control-flow protection
+    None,
+
+    /// Emit control-flow protection for branches (enables indirect branch tracking).
+    Branch,
+
+    /// Emit control-flow protection for returns.
+    Return,
+
+    /// Emit control-flow protection for both branches and returns.
+    Full,
+}
+
 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
 pub enum OptLevel {
     No,         // -O0
@@ -127,16 +143,16 @@ pub enum MirSpanview {
     Block,
 }
 
-/// The different settings that the `-Z instrument-coverage` flag can have.
+/// The different settings that the `-C instrument-coverage` flag can have.
 ///
-/// Coverage instrumentation now supports combining `-Z instrument-coverage`
+/// Coverage instrumentation now supports combining `-C instrument-coverage`
 /// with compiler and linker optimization (enabled with `-O` or `-C opt-level=1`
 /// and higher). Nevertheless, there are many variables, depending on options
 /// selected, code structure, and enabled attributes. If errors are encountered,
 /// either while compiling or when generating `llvm-cov show` reports, consider
 /// lowering the optimization level, including or excluding `-C link-dead-code`,
-/// or using `-Z instrument-coverage=except-unused-functions` or `-Z
-/// instrument-coverage=except-unused-generics`.
+/// or using `-Zunstable-options -C instrument-coverage=except-unused-functions`
+/// or `-Zunstable-options -C instrument-coverage=except-unused-generics`.
 ///
 /// Note that `ExceptUnusedFunctions` means: When `mapgen.rs` generates the
 /// coverage map, it will not attempt to generate synthetic functions for unused
@@ -148,13 +164,13 @@ pub enum MirSpanview {
 /// unless the function has type parameters.
 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
 pub enum InstrumentCoverage {
-    /// Default `-Z instrument-coverage` or `-Z instrument-coverage=statement`
+    /// Default `-C instrument-coverage` or `-C instrument-coverage=statement`
     All,
-    /// `-Z instrument-coverage=except-unused-generics`
+    /// `-Zunstable-options -C instrument-coverage=except-unused-generics`
     ExceptUnusedGenerics,
-    /// `-Z instrument-coverage=except-unused-functions`
+    /// `-Zunstable-options -C instrument-coverage=except-unused-functions`
     ExceptUnusedFunctions,
-    /// `-Z instrument-coverage=off` (or `no`, etc.)
+    /// `-C instrument-coverage=off` (or `no`, etc.)
     Off,
 }
 
@@ -770,7 +786,6 @@ fn default() -> Options {
             externs: Externs(BTreeMap::new()),
             extern_dep_specs: ExternDepSpecs(BTreeMap::new()),
             crate_name: None,
-            alt_std_name: None,
             libs: Vec::new(),
             unstable_features: UnstableFeatures::Disallow,
             debug_assertions: true,
@@ -2195,18 +2210,44 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         _ => {}
     }
 
-    if debugging_opts.instrument_coverage.is_some()
-        && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
-    {
+    // Handle both `-Z instrument-coverage` and `-C instrument-coverage`; the latter takes
+    // precedence.
+    match (cg.instrument_coverage, debugging_opts.instrument_coverage) {
+        (Some(ic_c), Some(ic_z)) if ic_c != ic_z => {
+            early_error(
+                error_format,
+                "incompatible values passed for `-C instrument-coverage` \
+                and `-Z instrument-coverage`",
+            );
+        }
+        (Some(InstrumentCoverage::Off | InstrumentCoverage::All), _) => {}
+        (Some(_), _) if !debugging_opts.unstable_options => {
+            early_error(
+                error_format,
+                "`-C instrument-coverage=except-*` requires `-Z unstable-options`",
+            );
+        }
+        (None, None) => {}
+        (None, ic) => {
+            early_warn(
+                error_format,
+                "`-Z instrument-coverage` is deprecated; use `-C instrument-coverage`",
+            );
+            cg.instrument_coverage = ic;
+        }
+        _ => {}
+    }
+
+    if cg.instrument_coverage.is_some() && cg.instrument_coverage != Some(InstrumentCoverage::Off) {
         if cg.profile_generate.enabled() || cg.profile_use.is_some() {
             early_error(
                 error_format,
-                "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
+                "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
                 or `-C profile-generate`",
             );
         }
 
-        // `-Z instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
+        // `-C instrument-coverage` implies `-C symbol-mangling-version=v0` - to ensure consistent
         // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over
         // multiple runs, including some changes to source code; so mangled names must be consistent
         // across compilations.
@@ -2215,7 +2256,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
             Some(SymbolManglingVersion::Legacy) => {
                 early_warn(
                     error_format,
-                    "-Z instrument-coverage requires symbol mangling version `v0`, \
+                    "-C instrument-coverage requires symbol mangling version `v0`, \
                     but `-C symbol-mangling-version=legacy` was specified",
                 );
             }
@@ -2356,7 +2397,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         unstable_features: UnstableFeatures::from_environment(crate_name.as_deref()),
         extern_dep_specs,
         crate_name,
-        alt_std_name: None,
         libs,
         debug_assertions,
         actually_rustdoc: false,
@@ -2606,11 +2646,11 @@ pub fn needs_analysis(&self) -> bool {
 /// we have an opt-in scheme here, so one is hopefully forced to think about
 /// how the hash should be calculated when adding a new command-line argument.
 crate mod dep_tracking {
-    use super::LdImpl;
     use super::{
-        BranchProtection, CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage,
-        LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType, OutputTypes, Passes,
-        SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
+        BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
+        InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OptLevel, OutputType,
+        OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath, SymbolManglingVersion,
+        TrimmedDefPaths,
     };
     use crate::lint;
     use crate::options::WasiExecModel;
@@ -2691,6 +2731,7 @@ fn hash(
         NativeLibKind,
         SanitizerSet,
         CFGuard,
+        CFProtection,
         TargetTriple,
         Edition,
         LinkerPluginLto,
index 357190178ce014a01041fcbe685bb5c470c6515e..9200be363addec569720abb729430f2e64ce633f 100644 (file)
@@ -1,13 +1,11 @@
 //! A module for searching for libraries
 
-pub use self::FileMatch::*;
-
 use std::env;
 use std::fs;
 use std::iter::FromIterator;
 use std::path::{Path, PathBuf};
 
-use crate::search_paths::{PathKind, SearchPath, SearchPathFile};
+use crate::search_paths::{PathKind, SearchPath};
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use tracing::debug;
 
@@ -43,36 +41,6 @@ pub fn get_self_contained_lib_path(&self) -> PathBuf {
         self.get_lib_path().join("self-contained")
     }
 
-    pub fn search<F>(&self, mut pick: F)
-    where
-        F: FnMut(&SearchPathFile, PathKind) -> FileMatch,
-    {
-        for search_path in self.search_paths() {
-            debug!("searching {}", search_path.dir.display());
-            fn is_rlib(spf: &SearchPathFile) -> bool {
-                if let Some(f) = &spf.file_name_str { f.ends_with(".rlib") } else { false }
-            }
-            // Reading metadata out of rlibs is faster, and if we find both
-            // an rlib and a dylib we only read one of the files of
-            // metadata, so in the name of speed, bring all rlib files to
-            // the front of the search list.
-            let files1 = search_path.files.iter().filter(|spf| is_rlib(&spf));
-            let files2 = search_path.files.iter().filter(|spf| !is_rlib(&spf));
-            for spf in files1.chain(files2) {
-                debug!("testing {}", spf.path.display());
-                let maybe_picked = pick(spf, search_path.kind);
-                match maybe_picked {
-                    FileMatches => {
-                        debug!("picked {}", spf.path.display());
-                    }
-                    FileDoesntMatch => {
-                        debug!("rejected {}", spf.path.display());
-                    }
-                }
-            }
-        }
-    }
-
     pub fn new(
         sysroot: &'a Path,
         triple: &'a str,
index e7ab8fffdf35c4440f3392151b7590c6eefb193d..c069144fa9f1c95ded254def6476abfe507743ff 100644 (file)
@@ -109,17 +109,16 @@ pub fn mir_opt_level(&self) -> usize {
     }
 
     pub fn instrument_coverage(&self) -> bool {
-        self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
-            != InstrumentCoverage::Off
+        self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off) != InstrumentCoverage::Off
     }
 
     pub fn instrument_coverage_except_unused_generics(&self) -> bool {
-        self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+        self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
             == InstrumentCoverage::ExceptUnusedGenerics
     }
 
     pub fn instrument_coverage_except_unused_functions(&self) -> bool {
-        self.debugging_opts.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
+        self.cg.instrument_coverage.unwrap_or(InstrumentCoverage::Off)
             == InstrumentCoverage::ExceptUnusedFunctions
     }
 }
@@ -185,10 +184,6 @@ pub struct Options {
         externs: Externs [UNTRACKED],
         extern_dep_specs: ExternDepSpecs [UNTRACKED],
         crate_name: Option<String> [TRACKED],
-        /// An optional name to use as the crate for std during std injection,
-        /// written `extern crate name as std`. Defaults to `std`. Used by
-        /// out-of-tree drivers.
-        alt_std_name: Option<String> [TRACKED],
         /// Indicates how the compiler should treat unstable features.
         unstable_features: UnstableFeatures [TRACKED],
 
@@ -385,6 +380,7 @@ mod desc {
     pub const parse_sanitizer_memory_track_origins: &str = "0, 1, or 2";
     pub const parse_cfguard: &str =
         "either a boolean (`yes`, `no`, `on`, `off`, etc), `checks`, or `nochecks`";
+    pub const parse_cfprotection: &str = "`none`|`no`|`n` (default), `branch`, `return`, or `full`|`yes`|`y` (equivalent to `branch` and `return`)";
     pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`";
     pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of();
     pub const parse_optimization_fuel: &str = "crate=integer";
@@ -700,6 +696,25 @@ mod parse {
         true
     }
 
+    crate fn parse_cfprotection(slot: &mut CFProtection, v: Option<&str>) -> bool {
+        if v.is_some() {
+            let mut bool_arg = None;
+            if parse_opt_bool(&mut bool_arg, v) {
+                *slot = if bool_arg.unwrap() { CFProtection::Full } else { CFProtection::None };
+                return true;
+            }
+        }
+
+        *slot = match v {
+            None | Some("none") => CFProtection::None,
+            Some("branch") => CFProtection::Branch,
+            Some("return") => CFProtection::Return,
+            Some("full") => CFProtection::Full,
+            Some(_) => return false,
+        };
+        true
+    }
+
     crate fn parse_linker_flavor(slot: &mut Option<LinkerFlavor>, v: Option<&str>) -> bool {
         match v.and_then(LinkerFlavor::from_str) {
             Some(lf) => *slot = Some(lf),
@@ -1031,6 +1046,14 @@ mod parse {
         "enable incremental compilation"),
     inline_threshold: Option<u32> = (None, parse_opt_number, [TRACKED],
         "set the threshold for inlining a function"),
+    instrument_coverage: Option<InstrumentCoverage> = (None, parse_instrument_coverage, [TRACKED],
+        "instrument the generated code to support LLVM source-based code coverage \
+        reports (note, the compiler build config must include `profiler = true`); \
+        implies `-C symbol-mangling-version=v0`. Optional values are:
+        `=all` (implicit value)
+        `=except-unused-generics`
+        `=except-unused-functions`
+        `=off` (default)"),
     link_arg: (/* redirected to link_args */) = ((), parse_string_push, [UNTRACKED],
         "a single extra argument to append to the linker invocation (can be used several times)"),
     link_args: Vec<String> = (Vec::new(), parse_list, [UNTRACKED],
@@ -1139,6 +1162,8 @@ mod parse {
         "select which borrowck is used (`mir` or `migrate`) (default: `migrate`)"),
     branch_protection: BranchProtection = (BranchProtection::default(), parse_branch_protection, [TRACKED],
         "set options for branch target identification and pointer authentication on AArch64"),
+    cf_protection: CFProtection = (CFProtection::None, parse_cfprotection, [TRACKED],
+        "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],
@@ -1166,6 +1191,8 @@ mod parse {
     dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
         "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
         (default: no)"),
+    drop_tracking: bool = (false, parse_bool, [TRACKED],
+        "enables drop tracking in generators (default: no)"),
     dual_proc_macros: bool = (false, parse_bool, [TRACKED],
         "load proc macros for both target and host, but only link to the target (default: no)"),
     dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
@@ -1360,8 +1387,6 @@ mod parse {
         "use the given `.prof` file for sampled profile-guided optimization (also known as AutoFDO)"),
     query_dep_graph: bool = (false, parse_bool, [UNTRACKED],
         "enable queries of the dependency graph for regression testing (default: no)"),
-    query_stats: bool = (false, parse_bool, [UNTRACKED],
-        "print some statistics about the query system (default: no)"),
     randomize_layout: bool = (false, parse_bool, [TRACKED],
         "randomize the layout of types (default: no)"),
     layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
index acb6c735e051ebc2cfb90b5310e07c7bc8208533..b6bde28233d243bc2ad86c0e5619111f3bc1d6d7 100644 (file)
@@ -15,22 +15,15 @@ pub struct SearchPath {
 /// doable, but very slow, because it involves calls to `file_name` and
 /// `extension` that are themselves slow.
 ///
-/// This type augments the `PathBuf` with an `Option<String>` containing the
+/// This type augments the `PathBuf` with an `String` containing the
 /// `PathBuf`'s filename. The prefix and suffix checking is much faster on the
-/// `Option<String>` than the `PathBuf`. (It's an `Option` because
-/// `Path::file_name` can fail; if that happens then all subsequent checking
-/// will also fail, which is fine.)
+/// `String` than the `PathBuf`. (The filename must be valid UTF-8. If it's
+/// not, the entry should be skipped, because all Rust output files are valid
+/// UTF-8, and so a non-UTF-8 filename couldn't be one we're looking for.)
 #[derive(Clone, Debug)]
 pub struct SearchPathFile {
     pub path: PathBuf,
-    pub file_name_str: Option<String>,
-}
-
-impl SearchPathFile {
-    fn new(path: PathBuf) -> SearchPathFile {
-        let file_name_str = path.file_name().and_then(|f| f.to_str()).map(|s| s.to_string());
-        SearchPathFile { path, file_name_str }
-    }
+    pub file_name_str: String,
 }
 
 #[derive(PartialEq, Clone, Copy, Debug, Hash, Eq, Encodable, Decodable)]
@@ -85,7 +78,14 @@ fn new(kind: PathKind, dir: PathBuf) -> Self {
         // Get the files within the directory.
         let files = match std::fs::read_dir(&dir) {
             Ok(files) => files
-                .filter_map(|e| e.ok().map(|e| SearchPathFile::new(e.path())))
+                .filter_map(|e| {
+                    e.ok().and_then(|e| {
+                        e.file_name().to_str().map(|s| SearchPathFile {
+                            path: e.path(),
+                            file_name_str: s.to_string(),
+                        })
+                    })
+                })
                 .collect::<Vec<_>>(),
             Err(..) => vec![],
         };
index 781fb8c1e5d8c8644dfe872cdb22943cb76daae1..7227b193f2194046d2aa81e15ffbb62ad673140f 100644 (file)
@@ -16,6 +16,6 @@ scoped-tls = "1.0"
 unicode-width = "0.1.4"
 cfg-if = "0.1.2"
 tracing = "0.1"
-sha1 = { package = "sha-1", version = "0.9" }
-sha2 = "0.9"
-md5 = { package = "md-5", version = "0.9" }
+sha1 = { package = "sha-1", version = "0.10.0" }
+sha2 = "0.10.1"
+md5 = { package = "md-5", version = "0.10.0" }
index e0d6bd8cb7bba6f709f3942499d285e45a2e3c29..8265eb23c3db4a4de89c224116bd34fcca828342 100644 (file)
@@ -172,10 +172,12 @@ impl LocalExpnId {
     /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
     pub const ROOT: LocalExpnId = LocalExpnId::from_u32(0);
 
+    #[inline]
     pub fn from_raw(idx: ExpnIndex) -> LocalExpnId {
         LocalExpnId::from_u32(idx.as_u32())
     }
 
+    #[inline]
     pub fn as_raw(self) -> ExpnIndex {
         ExpnIndex::from_u32(self.as_u32())
     }
index 823a927fd8c74c531eff95d138203f9c09716499..dea2fbf04be59b52f5aacac8c9c32018346c8ffc 100644 (file)
@@ -68,8 +68,8 @@
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 
+use md5::Digest;
 use md5::Md5;
-use sha1::Digest;
 use sha1::Sha1;
 use sha2::Sha256;
 
@@ -1013,37 +1013,25 @@ fn drop(&mut self) {
     f()
 }
 
-pub fn debug_with_source_map(
-    span: Span,
-    f: &mut fmt::Formatter<'_>,
-    source_map: &SourceMap,
-) -> fmt::Result {
-    write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(span), span.ctxt())
-}
-
-pub fn default_span_debug(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-    with_session_globals(|session_globals| {
-        if let Some(source_map) = &*session_globals.source_map.borrow() {
-            debug_with_source_map(span, f, source_map)
-        } else {
-            f.debug_struct("Span")
-                .field("lo", &span.lo())
-                .field("hi", &span.hi())
-                .field("ctxt", &span.ctxt())
-                .finish()
-        }
-    })
-}
-
 impl fmt::Debug for Span {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        (*SPAN_DEBUG)(*self, f)
+        with_session_globals(|session_globals| {
+            if let Some(source_map) = &*session_globals.source_map.borrow() {
+                write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
+            } else {
+                f.debug_struct("Span")
+                    .field("lo", &self.lo())
+                    .field("hi", &self.hi())
+                    .field("ctxt", &self.ctxt())
+                    .finish()
+            }
+        })
     }
 }
 
 impl fmt::Debug for SpanData {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        (*SPAN_DEBUG)(Span::new(self.lo, self.hi, self.ctxt, self.parent), f)
+        fmt::Debug::fmt(&Span::new(self.lo, self.hi, self.ctxt, self.parent), f)
     }
 }
 
@@ -2003,8 +1991,6 @@ pub struct FileLines {
     pub lines: Vec<LineInfo>,
 }
 
-pub static SPAN_DEBUG: AtomicRef<fn(Span, &mut fmt::Formatter<'_>) -> fmt::Result> =
-    AtomicRef::new(&(default_span_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
 pub static SPAN_TRACK: AtomicRef<fn(LocalDefId)> = AtomicRef::new(&((|_| {}) as fn(_)));
 
 // _____________________________________________________________________________
index 7414d201f511d099b79cba7748fdfc8abe47fe79..95177102dcf8678df118ab6d58cc65750219d8be 100644 (file)
@@ -629,26 +629,41 @@ pub fn span_extend_to_prev_char(&self, sp: Span, c: char, accept_newlines: bool)
     }
 
     /// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by
-    /// whitespace. Returns the same span if no character could be found or if an error occurred
-    /// while retrieving the code snippet.
-    pub fn span_extend_to_prev_str(&self, sp: Span, pat: &str, accept_newlines: bool) -> Span {
+    /// whitespace. Returns None if the pattern could not be found or if an error occurred while
+    /// retrieving the code snippet.
+    pub fn span_extend_to_prev_str(
+        &self,
+        sp: Span,
+        pat: &str,
+        accept_newlines: bool,
+        include_whitespace: bool,
+    ) -> Option<Span> {
         // assure that the pattern is delimited, to avoid the following
         //     fn my_fn()
         //           ^^^^ returned span without the check
         //     ---------- correct span
+        let prev_source = self.span_to_prev_source(sp).ok()?;
         for ws in &[" ", "\t", "\n"] {
             let pat = pat.to_owned() + ws;
-            if let Ok(prev_source) = self.span_to_prev_source(sp) {
-                let prev_source = prev_source.rsplit(&pat).next().unwrap_or("").trim_start();
-                if prev_source.is_empty() && sp.lo().0 != 0 {
-                    return sp.with_lo(BytePos(sp.lo().0 - 1));
-                } else if accept_newlines || !prev_source.contains('\n') {
-                    return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32));
+            if let Some(pat_pos) = prev_source.rfind(&pat) {
+                let just_after_pat_pos = pat_pos + pat.len() - 1;
+                let just_after_pat_plus_ws = if include_whitespace {
+                    just_after_pat_pos
+                        + prev_source[just_after_pat_pos..]
+                            .find(|c: char| !c.is_whitespace())
+                            .unwrap_or(0)
+                } else {
+                    just_after_pat_pos
+                };
+                let len = prev_source.len() - just_after_pat_plus_ws;
+                let prev_source = &prev_source[just_after_pat_plus_ws..];
+                if accept_newlines || !prev_source.trim_start().contains('\n') {
+                    return Some(sp.with_lo(BytePos(sp.lo().0 - len as u32)));
                 }
             }
         }
 
-        sp
+        None
     }
 
     /// Returns the source snippet as `String` after the given `Span`.
@@ -927,7 +942,7 @@ pub fn count_lines(&self) -> usize {
     }
 
     pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> {
-        let prev_span = self.span_extend_to_prev_str(span, "fn", true);
+        let prev_span = self.span_extend_to_prev_str(span, "fn", true, true).unwrap_or(span);
         if let Ok(snippet) = self.span_to_snippet(prev_span) {
             debug!(
                 "generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}",
@@ -968,8 +983,7 @@ pub fn generate_fn_name_span(&self, span: Span) -> Option<Span> {
     pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> {
         // Try to extend the span to the previous "fn" keyword to retrieve the function
         // signature.
-        let sugg_span = self.span_extend_to_prev_str(span, "fn", false);
-        if sugg_span != span {
+        if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) {
             if let Ok(snippet) = self.span_to_snippet(sugg_span) {
                 // Consume the function name.
                 let mut offset = snippet
index 18627cd2c099d28a2da577408f0a5f830fa0d296..33140911f91c6cba0cf8aba1321300f0f4f510dc 100644 (file)
         Formatter,
         From,
         FromIterator,
+        FromResidual,
         Future,
         FxHashMap,
         FxHashSet,
         cfg_target_abi,
         cfg_target_feature,
         cfg_target_has_atomic,
+        cfg_target_has_atomic_equal_alignment,
+        cfg_target_has_atomic_load_store,
         cfg_target_thread_local,
         cfg_target_vendor,
         cfg_version,
         compare_exchange_weak,
         compile_error,
         compile_error_macro,
+        compiler,
         compiler_builtins,
         compiler_fence,
         concat,
         fill,
         finish,
         flags,
+        float,
         float_to_int_unchecked,
         floorf32,
         floorf64,
         inline_const_pat,
         inout,
         instruction_set,
+        integer_: "integer",
+        integral,
         intel,
         into_future,
         into_iter,
         link_ordinal,
         link_section,
         linkage,
+        linker,
         lint_reasons,
         literal,
         load,
         unmarked_api,
         unpin,
         unreachable,
+        unreachable_2015,
+        unreachable_2015_macro,
+        unreachable_2021,
+        unreachable_2021_macro,
         unreachable_code,
+        unreachable_display,
         unreachable_macro,
         unrestricted_attribute_tokens,
         unsafe_block_in_unsafe_fn,
         unsafe_cell,
         unsafe_no_drop_flag,
+        unsafe_pin_internals,
         unsize,
         unsized_fn_params,
         unsized_locals,
         use_extern_macros,
         use_nested_groups,
         used,
+        used_with_arg,
         usize,
         v1,
         va_arg,
index c981b3ff54663a21f66dd28decbafda8e0bb74af..cec1d4bc15717c35f2c1a8e4a523d707da8f4ba5 100644 (file)
@@ -243,10 +243,10 @@ fn print_dyn_existential(
         Ok(self)
     }
 
-    fn print_const(self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+    fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
         // only print integers
-        if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int { .. })) = ct.val {
-            if ct.ty.is_integral() {
+        if let ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int { .. })) = ct.val() {
+            if ct.ty().is_integral() {
                 return self.pretty_print_const(ct, true);
             }
         }
index f8e8e15e78c9ed560d85122ebd1963389334d14e..c21c3d3ac330f487449d17757c853e635f97b2f0 100644 (file)
@@ -116,7 +116,7 @@ struct SymbolMangler<'tcx> {
     /// The values are start positions in `out`, in bytes.
     paths: FxHashMap<(DefId, &'tcx [GenericArg<'tcx>]), usize>,
     types: FxHashMap<Ty<'tcx>, usize>,
-    consts: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+    consts: FxHashMap<ty::Const<'tcx>, usize>,
 }
 
 impl<'tcx> SymbolMangler<'tcx> {
@@ -420,7 +420,7 @@ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
                     hir::Mutability::Not => "R",
                     hir::Mutability::Mut => "Q",
                 });
-                if *r != ty::ReErased {
+                if !r.is_erased() {
                     self = r.print(self)?;
                 }
                 self = ty.print(self)?;
@@ -576,10 +576,10 @@ fn print_dyn_existential(
         Ok(self)
     }
 
-    fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+    fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
         // We only mangle a typed value if the const can be evaluated.
         let ct = ct.eval(self.tcx, ty::ParamEnv::reveal_all());
-        match ct.val {
+        match ct.val() {
             ty::ConstKind::Value(_) => {}
 
             // Placeholders (should be demangled as `_`).
@@ -603,14 +603,14 @@ fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self:
         }
         let start = self.out.len();
 
-        match ct.ty.kind() {
+        match ct.ty().kind() {
             ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
-                self = ct.ty.print(self)?;
+                self = ct.ty().print(self)?;
 
-                let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty);
+                let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty());
 
                 // Negative integer values are mangled using `n` as a "sign prefix".
-                if let ty::Int(ity) = ct.ty.kind() {
+                if let ty::Int(ity) = ct.ty().kind() {
                     let val =
                         Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128;
                     if val < 0 {
@@ -627,7 +627,7 @@ fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self:
             // handle `&str` and include both `&` ("R") and `str` ("e") prefixes.
             ty::Ref(_, ty, hir::Mutability::Not) if *ty == self.tcx.types.str_ => {
                 self.push("R");
-                match ct.val {
+                match ct.val() {
                     ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
                         // NOTE(eddyb) the following comment was kept from `ty::print::pretty`:
                         // The `inspect` here is okay since we checked the bounds, and there are no
@@ -671,7 +671,7 @@ fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self:
                     Ok(this)
                 };
 
-                match *ct.ty.kind() {
+                match *ct.ty().kind() {
                     ty::Array(..) => {
                         self.push("A");
                         self = print_field_list(self)?;
@@ -721,7 +721,7 @@ fn print_const(mut self, ct: &'tcx ty::Const<'tcx>) -> Result<Self::Const, Self:
             }
 
             _ => {
-                bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct);
+                bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty(), ct);
             }
         }
 
@@ -811,7 +811,7 @@ fn path_generic_args(
     ) -> Result<Self::Path, Self::Error> {
         // Don't print any regions if they're all erased.
         let print_regions = args.iter().any(|arg| match arg.unpack() {
-            GenericArgKind::Lifetime(r) => *r != ty::ReErased,
+            GenericArgKind::Lifetime(r) => !r.is_erased(),
             _ => false,
         });
         let args = args.iter().cloned().filter(|arg| match arg.unpack() {
index 735b7e76e3862a5ceaf792d0226c9f4fa7e71625..34324a582977db24f1a89692d792d39f67dd63fd 100644 (file)
@@ -1,6 +1,7 @@
 use crate::abi::{self, Abi, Align, FieldsShape, Size};
 use crate::abi::{HasDataLayout, TyAbiInterface, TyAndLayout};
 use crate::spec::{self, HasTargetSpec};
+use rustc_span::Symbol;
 use std::fmt;
 
 mod aarch64;
@@ -73,6 +74,7 @@ pub struct ArgAttribute: u16 {
             // 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;
         }
     }
 }
@@ -494,7 +496,11 @@ fn indirect_pass_mode(layout: &TyAndLayout<'a, Ty>) -> PassMode {
         // For non-immediate arguments the callee gets its own copy of
         // the value on the stack, so there are no aliases. It's also
         // program-invisible so can't possibly capture
-        attrs.set(ArgAttribute::NoAlias).set(ArgAttribute::NoCapture).set(ArgAttribute::NonNull);
+        attrs
+            .set(ArgAttribute::NoAlias)
+            .set(ArgAttribute::NoCapture)
+            .set(ArgAttribute::NonNull)
+            .set(ArgAttribute::NoUndef);
         attrs.pointee_size = layout.size;
         // FIXME(eddyb) We should be doing this, but at least on
         // i686-pc-windows-msvc, it results in wrong stack offsets.
@@ -623,10 +629,10 @@ pub struct FnAbi<'a, Ty> {
 }
 
 /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
-#[derive(Clone, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
 pub enum AdjustForForeignAbiError {
     /// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs.
-    Unsupported { arch: String, abi: spec::abi::Abi },
+    Unsupported { arch: Symbol, abi: spec::abi::Abi },
 }
 
 impl fmt::Display for AdjustForForeignAbiError {
@@ -658,22 +664,24 @@ pub fn adjust_for_foreign_abi<C>(
 
         match &cx.target_spec().arch[..] {
             "x86" => {
-                let flavor = if abi == spec::abi::Abi::Fastcall {
+                let flavor = if let spec::abi::Abi::Fastcall { .. } = abi {
                     x86::Flavor::Fastcall
                 } else {
                     x86::Flavor::General
                 };
                 x86::compute_abi_info(cx, self, flavor);
             }
-            "x86_64" => {
-                if abi == spec::abi::Abi::SysV64 {
-                    x86_64::compute_abi_info(cx, self);
-                } else if abi == spec::abi::Abi::Win64 || cx.target_spec().is_like_windows {
-                    x86_win64::compute_abi_info(self);
-                } else {
-                    x86_64::compute_abi_info(cx, self);
+            "x86_64" => match abi {
+                spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
+                spec::abi::Abi::Win64 { .. } => x86_win64::compute_abi_info(self),
+                _ => {
+                    if cx.target_spec().is_like_windows {
+                        x86_win64::compute_abi_info(self)
+                    } else {
+                        x86_64::compute_abi_info(cx, self)
+                    }
                 }
-            }
+            },
             "aarch64" => aarch64::compute_abi_info(cx, self),
             "amdgpu" => amdgpu::compute_abi_info(cx, self),
             "arm" => arm::compute_abi_info(cx, self),
@@ -701,7 +709,10 @@ pub fn adjust_for_foreign_abi<C>(
             "asmjs" => wasm::compute_c_abi_info(cx, self),
             "bpf" => bpf::compute_abi_info(self),
             arch => {
-                return Err(AdjustForForeignAbiError::Unsupported { arch: arch.to_string(), abi });
+                return Err(AdjustForForeignAbiError::Unsupported {
+                    arch: Symbol::intern(arch),
+                    abi,
+                });
             }
         }
 
index 44beb2f6ad8d37686aef0469a3f388f486cac5f2..f8e1e1b02f5a285cc8b23ab7beadb332b56dcd3c 100644 (file)
@@ -3,6 +3,7 @@
 pub fn target() -> Target {
     let mut base = super::hermit_base::opts();
     base.max_atomic_width = Some(128);
+    base.features = "+strict-align,+neon,+fp-armv8".to_string();
 
     Target {
         llvm_target: "aarch64-unknown-hermit".to_string(),
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_hermitkernel.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_hermitkernel.rs
new file mode 100644 (file)
index 0000000..6e9d6c6
--- /dev/null
@@ -0,0 +1,16 @@
+use crate::spec::Target;
+
+pub fn target() -> Target {
+    let mut base = super::hermit_kernel_base::opts();
+    base.max_atomic_width = Some(128);
+    base.abi = "softfloat".to_string();
+    base.features = "+strict-align,-neon,-fp-armv8".to_string();
+
+    Target {
+        llvm_target: "aarch64-unknown-hermit".to_string(),
+        pointer_width: 64,
+        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+        arch: "aarch64".to_string(),
+        options: base,
+    }
+}
index e3a2226eb9d152a4a64f4d36da1be0b930b62849..d9e571c72e53a946de00bb350475071640e1d77e 100644 (file)
@@ -13,14 +13,14 @@ pub enum Abi {
     // churn. The specific values are meaningless.
     Rust,
     C { unwind: bool },
-    Cdecl,
+    Cdecl { unwind: bool },
     Stdcall { unwind: bool },
-    Fastcall,
-    Vectorcall,
+    Fastcall { unwind: bool },
+    Vectorcall { unwind: bool },
     Thiscall { unwind: bool },
-    Aapcs,
-    Win64,
-    SysV64,
+    Aapcs { unwind: bool },
+    Win64 { unwind: bool },
+    SysV64 { unwind: bool },
     PtxKernel,
     Msp430Interrupt,
     X86Interrupt,
@@ -50,16 +50,22 @@ pub struct AbiData {
     AbiData { abi: Abi::Rust, name: "Rust" },
     AbiData { abi: Abi::C { unwind: false }, name: "C" },
     AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" },
-    AbiData { abi: Abi::Cdecl, name: "cdecl" },
+    AbiData { abi: Abi::Cdecl { unwind: false }, name: "cdecl" },
+    AbiData { abi: Abi::Cdecl { unwind: true }, name: "cdecl-unwind" },
     AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall" },
     AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind" },
-    AbiData { abi: Abi::Fastcall, name: "fastcall" },
-    AbiData { abi: Abi::Vectorcall, name: "vectorcall" },
+    AbiData { abi: Abi::Fastcall { unwind: false }, name: "fastcall" },
+    AbiData { abi: Abi::Fastcall { unwind: true }, name: "fastcall-unwind" },
+    AbiData { abi: Abi::Vectorcall { unwind: false }, name: "vectorcall" },
+    AbiData { abi: Abi::Vectorcall { unwind: true }, name: "vectorcall-unwind" },
     AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall" },
     AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind" },
-    AbiData { abi: Abi::Aapcs, name: "aapcs" },
-    AbiData { abi: Abi::Win64, name: "win64" },
-    AbiData { abi: Abi::SysV64, name: "sysv64" },
+    AbiData { abi: Abi::Aapcs { unwind: false }, name: "aapcs" },
+    AbiData { abi: Abi::Aapcs { unwind: true }, name: "aapcs-unwind" },
+    AbiData { abi: Abi::Win64 { unwind: false }, name: "win64" },
+    AbiData { abi: Abi::Win64 { unwind: true }, name: "win64-unwind" },
+    AbiData { abi: Abi::SysV64 { unwind: false }, name: "sysv64" },
+    AbiData { abi: Abi::SysV64 { unwind: true }, name: "sysv64-unwind" },
     AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" },
     AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" },
     AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" },
@@ -101,32 +107,38 @@ pub fn index(self) -> usize {
             C { unwind: false } => 1,
             C { unwind: true } => 2,
             // Platform-specific ABIs
-            Cdecl => 3,
-            Stdcall { unwind: false } => 4,
-            Stdcall { unwind: true } => 5,
-            Fastcall => 6,
-            Vectorcall => 7,
-            Thiscall { unwind: false } => 8,
-            Thiscall { unwind: true } => 9,
-            Aapcs => 10,
-            Win64 => 11,
-            SysV64 => 12,
-            PtxKernel => 13,
-            Msp430Interrupt => 14,
-            X86Interrupt => 15,
-            AmdGpuKernel => 16,
-            EfiApi => 17,
-            AvrInterrupt => 18,
-            AvrNonBlockingInterrupt => 19,
-            CCmseNonSecureCall => 20,
-            Wasm => 21,
+            Cdecl { unwind: false } => 3,
+            Cdecl { unwind: true } => 4,
+            Stdcall { unwind: false } => 5,
+            Stdcall { unwind: true } => 6,
+            Fastcall { unwind: false } => 7,
+            Fastcall { unwind: true } => 8,
+            Vectorcall { unwind: false } => 9,
+            Vectorcall { unwind: true } => 10,
+            Thiscall { unwind: false } => 11,
+            Thiscall { unwind: true } => 12,
+            Aapcs { unwind: false } => 13,
+            Aapcs { unwind: true } => 14,
+            Win64 { unwind: false } => 15,
+            Win64 { unwind: true } => 16,
+            SysV64 { unwind: false } => 17,
+            SysV64 { unwind: true } => 18,
+            PtxKernel => 19,
+            Msp430Interrupt => 20,
+            X86Interrupt => 21,
+            AmdGpuKernel => 22,
+            EfiApi => 23,
+            AvrInterrupt => 24,
+            AvrNonBlockingInterrupt => 25,
+            CCmseNonSecureCall => 26,
+            Wasm => 27,
             // Cross-platform ABIs
-            System { unwind: false } => 22,
-            System { unwind: true } => 23,
-            RustIntrinsic => 24,
-            RustCall => 25,
-            PlatformIntrinsic => 26,
-            Unadjusted => 27,
+            System { unwind: false } => 28,
+            System { unwind: true } => 29,
+            RustIntrinsic => 30,
+            RustCall => 31,
+            PlatformIntrinsic => 32,
+            Unadjusted => 33,
         };
         debug_assert!(
             AbiDatas
index e982b3565b56c521a5607f1d6ec5a8725922a892..dc14d260e925e5ba9065e9df7ff7c427ab87cc9a 100644 (file)
@@ -1,14 +1,8 @@
-use crate::spec::{LinkerFlavor, TargetOptions};
+use crate::spec::TargetOptions;
 
 pub fn opts() -> TargetOptions {
     let mut base = super::linux_base::opts();
     base.os = "android".to_string();
-    // Many of the symbols defined in compiler-rt are also defined in libgcc.
-    // Android's linker doesn't like that by default.
-    base.pre_link_args
-        .entry(LinkerFlavor::Gcc)
-        .or_default()
-        .push("-Wl,--allow-multiple-definition".to_string());
     base.dwarf_version = Some(2);
     base.position_independent_executables = true;
     base.has_thread_local = false;
diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_uclibceabi.rs
new file mode 100644 (file)
index 0000000..7faa8ed
--- /dev/null
@@ -0,0 +1,23 @@
+use crate::spec::{Target, TargetOptions};
+
+// This target is for uclibc Linux on ARMv7 without NEON,
+// thumb-mode or hardfloat.
+
+pub fn target() -> Target {
+    let base = super::linux_uclibc_base::opts();
+    Target {
+        llvm_target: "armv7-unknown-linux-gnueabi".to_string(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+
+        options: TargetOptions {
+            features: "+v7,+thumb2,+soft-float,-neon".to_string(),
+            cpu: "generic".to_string(),
+            max_atomic_width: Some(64),
+            mcount: "_mcount".to_string(),
+            abi: "eabi".to_string(),
+            ..base
+        },
+    }
+}
index 74074cfb5dda16d0dd10d0ad7a19722641e05cb7..174294895bf7a435d05b706ab1b0acd3ebd17a30 100644 (file)
@@ -24,7 +24,7 @@ pub fn target() -> Target {
         llvm_target: "i686-pc-windows-msvc".to_string(),
         pointer_width: 32,
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
-            i64:64-f80:32-n8:16:32-a:0:32-S32"
+            i64:64-f80:128-n8:16:32-a:0:32-S32"
             .to_string(),
         arch: "x86".to_string(),
         options: base,
index 05f204c56044612c2ee9825d86ccee642206275a..e2f65e7a7c938c102182ab89f00d2e57d5e6b1d8 100644 (file)
@@ -9,7 +9,7 @@ pub fn target() -> Target {
         llvm_target: "i686-pc-windows-msvc".to_string(),
         pointer_width: 32,
         data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\
-            i64:64-f80:32-n8:16:32-a:0:32-S32"
+            i64:64-f80:128-n8:16:32-a:0:32-S32"
             .to_string(),
         arch: "x86".to_string(),
         options: base,
diff --git a/compiler/rustc_target/src/spec/mips64_openwrt_linux_musl.rs b/compiler/rustc_target/src/spec/mips64_openwrt_linux_musl.rs
new file mode 100644 (file)
index 0000000..1199ed4
--- /dev/null
@@ -0,0 +1,26 @@
+/// A target tuple for OpenWrt MIPS64 targets
+///
+use crate::abi::Endian;
+use crate::spec::{Target, TargetOptions};
+
+pub fn target() -> Target {
+    let mut base = super::linux_musl_base::opts();
+    base.cpu = "mips64r2".to_string();
+    base.features = "+mips64r2".to_string();
+    base.max_atomic_width = Some(64);
+    base.crt_static_default = false;
+
+    Target {
+        // LLVM doesn't recognize "muslabi64" yet.
+        llvm_target: "mips64-unknown-linux-musl".to_string(),
+        pointer_width: 64,
+        data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(),
+        arch: "mips64".to_string(),
+        options: TargetOptions {
+            abi: "abi64".to_string(),
+            endian: Endian::Big,
+            mcount: "_mcount".to_string(),
+            ..base
+        },
+    }
+}
index 4effb8bacf6d6cfc01e57aa22e48b5330506da98..bfafe2d83d7c9677943a17ff9efe71c79491d46d 100644 (file)
@@ -964,6 +964,7 @@ fn $module() {
     ("aarch64-unknown-hermit", aarch64_unknown_hermit),
     ("x86_64-unknown-hermit", x86_64_unknown_hermit),
 
+    ("aarch64-unknown-none-hermitkernel", aarch64_unknown_none_hermitkernel),
     ("x86_64-unknown-none-hermitkernel", x86_64_unknown_none_hermitkernel),
 
     ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf),
@@ -1013,9 +1014,12 @@ fn $module() {
 
     ("armv6k-nintendo-3ds", armv6k_nintendo_3ds),
 
+    ("armv7-unknown-linux-uclibceabi", armv7_unknown_linux_uclibceabi),
     ("armv7-unknown-linux-uclibceabihf", armv7_unknown_linux_uclibceabihf),
 
     ("x86_64-unknown-none", x86_64_unknown_none),
+
+    ("mips64-openwrt-linux-musl", mips64_openwrt_linux_musl),
 }
 
 /// Warnings encountered when parsing the target `json`.
@@ -1537,11 +1541,13 @@ fn default() -> TargetOptions {
 impl Deref for Target {
     type Target = TargetOptions;
 
+    #[inline]
     fn deref(&self) -> &Self::Target {
         &self.options
     }
 }
 impl DerefMut for Target {
+    #[inline]
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.options
     }
@@ -1556,15 +1562,15 @@ pub fn adjust_abi(&self, abi: Abi) -> Abi {
                 Abi::Stdcall { unwind }
             }
             Abi::System { unwind } => Abi::C { unwind },
-            Abi::EfiApi if self.arch == "x86_64" => Abi::Win64,
+            Abi::EfiApi if self.arch == "x86_64" => Abi::Win64 { unwind: false },
             Abi::EfiApi => Abi::C { unwind: false },
 
             // See commentary in `is_abi_supported`.
             Abi::Stdcall { .. } | Abi::Thiscall { .. } if self.arch == "x86" => abi,
             Abi::Stdcall { unwind } | Abi::Thiscall { unwind } => Abi::C { unwind },
-            Abi::Fastcall if self.arch == "x86" => abi,
-            Abi::Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
-            Abi::Fastcall | Abi::Vectorcall => Abi::C { unwind: false },
+            Abi::Fastcall { .. } if self.arch == "x86" => abi,
+            Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
+            Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind },
 
             abi => abi,
         }
@@ -1581,12 +1587,12 @@ pub fn is_abi_supported(&self, abi: Abi) -> Option<bool> {
             | RustCall
             | PlatformIntrinsic
             | Unadjusted
-            | Cdecl
+            | Cdecl { .. }
             | EfiApi => true,
             X86Interrupt => ["x86", "x86_64"].contains(&&self.arch[..]),
-            Aapcs => "arm" == self.arch,
+            Aapcs { .. } => "arm" == self.arch,
             CCmseNonSecureCall => ["arm", "aarch64"].contains(&&self.arch[..]),
-            Win64 | SysV64 => self.arch == "x86_64",
+            Win64 { .. } | SysV64 { .. } => self.arch == "x86_64",
             PtxKernel => self.arch == "nvptx64",
             Msp430Interrupt => self.arch == "msp430",
             AmdGpuKernel => self.arch == "amdgcn",
@@ -1623,13 +1629,13 @@ pub fn is_abi_supported(&self, abi: Abi) -> Option<bool> {
             // > convention is used.
             //
             // -- https://docs.microsoft.com/en-us/cpp/cpp/argument-passing-and-naming-conventions
-            Stdcall { .. } | Fastcall | Vectorcall if self.is_like_windows => true,
+            Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } if self.is_like_windows => true,
             // Outside of Windows we want to only support these calling conventions for the
             // architectures for which these calling conventions are actually well defined.
-            Stdcall { .. } | Fastcall if self.arch == "x86" => true,
-            Vectorcall if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
+            Stdcall { .. } | Fastcall { .. } if self.arch == "x86" => true,
+            Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => true,
             // Return a `None` for other cases so that we know to emit a future compat lint.
-            Stdcall { .. } | Fastcall | Vectorcall => return None,
+            Stdcall { .. } | Fastcall { .. } | Vectorcall { .. } => return None,
         })
     }
 
@@ -2145,8 +2151,8 @@ pub fn search(
         use std::fs;
 
         fn load_file(path: &Path) -> Result<(Target, TargetWarnings), String> {
-            let contents = fs::read(path).map_err(|e| e.to_string())?;
-            let obj = json::from_reader(&mut &contents[..]).map_err(|e| e.to_string())?;
+            let contents = fs::read_to_string(path).map_err(|e| e.to_string())?;
+            let obj = json::from_str(&contents).map_err(|e| e.to_string())?;
             Target::from_json(obj)
         }
 
index 69a404ec564e2d85210bc9ba395b6fa984e4122b..8fcdbc146af93dcb00eb785076ee77882bee6983 100644 (file)
@@ -43,7 +43,8 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm32-unknown-emscripten".to_string(),
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-i64:64-f128:64-n32:64-S128-ni:1:10:20".to_string(),
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-f128:64-n32:64-S128-ni:1:10:20"
+            .to_string(),
         arch: "wasm32".to_string(),
         options: opts,
     }
index 134c6803b15d13dbacd839cfb1ba55011e73bffb..e50cf9740947549f4fb8486cd19d7844bc5a6b96 100644 (file)
@@ -54,7 +54,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm32-unknown-unknown".to_string(),
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20".to_string(),
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".to_string(),
         arch: "wasm32".to_string(),
         options,
     }
index 2dab206dc760250b87bbe21b8b5a0bfdeae0c649..a4b81c9a2788f939eaf93d25f36c103baa8dd522 100644 (file)
@@ -109,7 +109,7 @@ pub fn target() -> Target {
     Target {
         llvm_target: "wasm32-wasi".to_string(),
         pointer_width: 32,
-        data_layout: "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20".to_string(),
+        data_layout: "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20".to_string(),
         arch: "wasm32".to_string(),
         options,
     }
index ea0ac6318bc9a71ff736d9d986b1825010a89eb6..c93ff0aa6e27734ace8720f23342e36572b8308c 100644 (file)
@@ -141,7 +141,7 @@ fn tcx(&self) -> TyCtxt<'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match r {
+        match *r {
             // Ignore bound regions and `'static` regions that appear in the
             // type, we only need to remap regions that reference lifetimes
             // from the function declaraion.
@@ -287,10 +287,10 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         trace!("checking const {:?}", ct);
         // Find a const parameter
-        match ct.val {
+        match ct.val() {
             ty::ConstKind::Param(..) => {
                 // Look it up in the substitution list.
                 match self.map.get(&ct.into()).map(|k| k.unpack()) {
@@ -311,7 +311,7 @@ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
                             )
                             .emit();
 
-                        self.tcx().const_error(ct.ty)
+                        self.tcx().const_error(ct.ty())
                     }
                 }
             }
index f2ed5ae26a3c268569cf3174c25ef9d77e04407a..5fe7b62f454186c9fb453064f16fb6efff068e46 100644 (file)
@@ -437,16 +437,12 @@ fn add_user_pred(
                     for (new_region, old_region) in
                         iter::zip(new_substs.regions(), old_substs.regions())
                     {
-                        match (new_region, old_region) {
+                        match (*new_region, *old_region) {
                             // If both predicates have an `ReLateBound` (a HRTB) in the
                             // same spot, we do nothing.
-                            (
-                                ty::RegionKind::ReLateBound(_, _),
-                                ty::RegionKind::ReLateBound(_, _),
-                            ) => {}
+                            (ty::ReLateBound(_, _), ty::ReLateBound(_, _)) => {}
 
-                            (ty::RegionKind::ReLateBound(_, _), _)
-                            | (_, ty::RegionKind::ReVar(_)) => {
+                            (ty::ReLateBound(_, _), _) | (_, ty::ReVar(_)) => {
                                 // One of these is true:
                                 // The new predicate has a HRTB in a spot where the old
                                 // predicate does not (if they both had a HRTB, the previous
@@ -472,8 +468,7 @@ fn add_user_pred(
                                 // `user_computed_preds`.
                                 return false;
                             }
-                            (_, ty::RegionKind::ReLateBound(_, _))
-                            | (ty::RegionKind::ReVar(_), _) => {
+                            (_, ty::ReLateBound(_, _)) | (ty::ReVar(_), _) => {
                                 // This is the opposite situation as the previous arm.
                                 // One of these is true:
                                 //
@@ -814,14 +809,14 @@ fn evaluate_nested_obligations(
                     };
                 }
                 ty::PredicateKind::ConstEquate(c1, c2) => {
-                    let evaluate = |c: &'tcx ty::Const<'tcx>| {
-                        if let ty::ConstKind::Unevaluated(unevaluated) = c.val {
+                    let evaluate = |c: ty::Const<'tcx>| {
+                        if let ty::ConstKind::Unevaluated(unevaluated) = c.val() {
                             match select.infcx().const_eval_resolve(
                                 obligation.param_env,
                                 unevaluated,
                                 Some(obligation.cause.span),
                             ) {
-                                Ok(val) => Ok(ty::Const::from_value(select.tcx(), val, c.ty)),
+                                Ok(val) => Ok(ty::Const::from_value(select.tcx(), val, c.ty())),
                                 Err(err) => Err(err),
                             }
                         } else {
@@ -880,8 +875,8 @@ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
     }
 
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        (match r {
-            ty::ReVar(vid) => self.vid_to_region.get(vid).cloned(),
+        (match *r {
+            ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(),
             _ => None,
         })
         .unwrap_or_else(|| r.super_fold_with(self))
index 34fc4ca8fead7d6ecaf9ad7cda1caa3b2e2880e0..93c2f202545f604fbc706073f1b47395182336bf 100644 (file)
@@ -8,7 +8,7 @@
     PredicateObligation, SelectionError, TraitEngine,
 };
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::{self, Ty, TypeFoldable};
 
 pub struct FulfillmentContext<'tcx> {
     obligations: FxIndexSet<PredicateObligation<'tcx>>,
@@ -91,7 +91,12 @@ fn select_where_possible(
                 let environment = obligation.param_env.caller_bounds();
                 let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate };
                 let mut orig_values = OriginalQueryValues::default();
-                let canonical_goal = infcx.canonicalize_query(goal, &mut orig_values);
+                if goal.references_error() {
+                    continue;
+                }
+
+                let canonical_goal =
+                    infcx.canonicalize_query_preserving_universes(goal, &mut orig_values);
 
                 match infcx.tcx.evaluate_goal(canonical_goal) {
                     Ok(response) => {
index 759bc696981676162f708c376ee9f0406f649c1f..bf6e6a4fcbb9d9e0d70bd3601712e367b19bf111 100644 (file)
@@ -22,7 +22,7 @@
 pub fn codegen_fulfill_obligation<'tcx>(
     tcx: TyCtxt<'tcx>,
     (param_env, trait_ref): (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>),
-) -> Result<ImplSource<'tcx, ()>, ErrorReported> {
+) -> Result<&'tcx ImplSource<'tcx, ()>, ErrorReported> {
     // Remove any references to regions; this helps improve caching.
     let trait_ref = tcx.erase_regions(trait_ref);
     // We expect the input to be fully normalized.
@@ -64,6 +64,8 @@ pub fn codegen_fulfill_obligation<'tcx>(
             Err(Unimplemented) => {
                 // This can trigger when we probe for the source of a `'static` lifetime requirement
                 // on a trait object: `impl Foo for dyn Trait {}` has an implicit `'static` bound.
+                // This can also trigger when we have a global bound that is not actually satisfied,
+                // but was included during typeck due to the trivial_bounds feature.
                 infcx.tcx.sess.delay_span_bug(
                     rustc_span::DUMMY_SP,
                     &format!(
@@ -91,7 +93,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
         let impl_source = drain_fulfillment_cx_or_panic(&infcx, &mut fulfill_cx, impl_source);
 
         debug!("Cache miss: {:?} => {:?}", trait_ref, impl_source);
-        Ok(impl_source)
+        Ok(&*tcx.arena.alloc(impl_source))
     })
 }
 
index 21775a5c49f09da7690485fd36354d833db9b51d..b2aa72e0e67416e4f2b36713e0bcdda14c769440 100644 (file)
@@ -4,8 +4,8 @@
 //! [trait-resolution]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html
 //! [trait-specialization]: https://rustc-dev-guide.rust-lang.org/traits/specialization.html
 
-use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
-use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::infer::outlives::env::OutlivesEnvironment;
+use crate::infer::{CombinedSnapshot, InferOk, RegionckMode};
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::util::impl_trait_ref_and_oblig;
 use crate::traits::SkipLeakCheck;
     self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
     PredicateObligations, SelectionContext,
 };
+//use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
+use rustc_hir::CRATE_HIR_ID;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::TraitEngine;
 use rustc_middle::traits::specialization_graph::OverlapMode;
-use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifyParams};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -82,8 +86,8 @@ pub fn overlapping_impls<F1, F2, R>(
         impl2_ref.iter().flat_map(|tref| tref.substs.types()),
     )
     .any(|(ty1, ty2)| {
-        let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No, StripReferences::No);
-        let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No, StripReferences::No);
+        let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No);
+        let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No);
 
         if let (Some(t1), Some(t2)) = (t1, t2) {
             // Simplified successfully
@@ -150,7 +154,10 @@ fn overlap<'cx, 'tcx>(
     impl2_def_id: DefId,
     overlap_mode: OverlapMode,
 ) -> Option<OverlapResult<'tcx>> {
-    debug!("overlap(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
+    debug!(
+        "overlap(impl1_def_id={:?}, impl2_def_id={:?}, overlap_mode={:?})",
+        impl1_def_id, impl2_def_id, overlap_mode
+    );
 
     selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
         overlap_within_probe(
@@ -191,9 +198,6 @@ fn overlap_within_probe<'cx, 'tcx>(
     let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
     let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id);
 
-    debug!("overlap: impl1_header={:?}", impl1_header);
-    debug!("overlap: impl2_header={:?}", impl2_header);
-
     let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?;
     debug!("overlap: unification check succeeded");
 
@@ -226,6 +230,7 @@ fn equate_impl_headers<'cx, 'tcx>(
     impl2_header: &ty::ImplHeader<'tcx>,
 ) -> Option<PredicateObligations<'tcx>> {
     // Do `a` and `b` unify? If not, no overlap.
+    debug!("equate_impl_headers(impl1_header={:?}, impl2_header={:?}", impl1_header, impl2_header);
     selcx
         .infcx()
         .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
@@ -264,8 +269,11 @@ fn implicit_negative<'cx, 'tcx>(
     // If the obligation `&'?a str: Error` holds, it means that there's overlap. If that doesn't
     // hold we need to check if `&'?a str: !Error` holds, if doesn't hold there's overlap because
     // at some point an impl for `&'?a str: Error` could be added.
+    debug!(
+        "implicit_negative(impl1_header={:?}, impl2_header={:?}, obligations={:?})",
+        impl1_header, impl2_header, obligations
+    );
     let infcx = selcx.infcx();
-    let tcx = infcx.tcx;
     let opt_failing_obligation = impl1_header
         .predicates
         .iter()
@@ -279,12 +287,7 @@ fn implicit_negative<'cx, 'tcx>(
             predicate: p,
         })
         .chain(obligations)
-        .find(|o| {
-            loose_check(selcx, o) || tcx.features().negative_impls && negative_impl_exists(selcx, o)
-        });
-    // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
-    // to the canonical trait query form, `infcx.predicate_may_hold`, once
-    // the new system supports intercrate mode (which coherence needs).
+        .find(|o| !selcx.predicate_may_hold_fatal(o));
 
     if let Some(failing_obligation) = opt_failing_obligation {
         debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
@@ -301,6 +304,7 @@ fn negative_impl<'cx, 'tcx>(
     impl1_def_id: DefId,
     impl2_def_id: DefId,
 ) -> bool {
+    debug!("negative_impl(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
     let tcx = selcx.infcx().tcx;
 
     // create a parameter environment corresponding to a (placeholder) instantiation of impl1
@@ -348,7 +352,7 @@ fn negative_impl<'cx, 'tcx>(
         let opt_failing_obligation = obligations
             .into_iter()
             .chain(more_obligations)
-            .find(|o| negative_impl_exists(selcx, o));
+            .find(|o| negative_impl_exists(selcx, impl1_env, impl1_def_id, o));
 
         if let Some(failing_obligation) = opt_failing_obligation {
             debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
@@ -359,24 +363,47 @@ fn negative_impl<'cx, 'tcx>(
     })
 }
 
-fn loose_check<'cx, 'tcx>(
-    selcx: &mut SelectionContext<'cx, 'tcx>,
-    o: &PredicateObligation<'tcx>,
-) -> bool {
-    !selcx.predicate_may_hold_fatal(o)
-}
-
 fn negative_impl_exists<'cx, 'tcx>(
     selcx: &SelectionContext<'cx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    region_context: DefId,
     o: &PredicateObligation<'tcx>,
 ) -> bool {
-    let infcx = selcx.infcx();
+    let infcx = &selcx.infcx().fork();
     let tcx = infcx.tcx;
     o.flip_polarity(tcx)
-        .as_ref()
         .map(|o| {
-            // FIXME This isn't quite correct, regions should be included
-            selcx.infcx().predicate_must_hold_modulo_regions(o)
+            let mut fulfillment_cx = FulfillmentContext::new();
+            fulfillment_cx.register_predicate_obligation(infcx, o);
+
+            let errors = fulfillment_cx.select_all_or_error(infcx);
+            if !errors.is_empty() {
+                return false;
+            }
+
+            let mut outlives_env = OutlivesEnvironment::new(param_env);
+            // FIXME -- add "assumed to be well formed" types into the `outlives_env`
+
+            // "Save" the accumulated implied bounds into the outlives environment
+            // (due to the FIXME above, there aren't any, but this step is still needed).
+            // The "body id" is given as `CRATE_HIR_ID`, which is the same body-id used
+            // by the "dummy" causes elsewhere (body-id is only relevant when checking
+            // function bodies with closures).
+            outlives_env.save_implied_bounds(CRATE_HIR_ID);
+
+            infcx.process_registered_region_obligations(
+                outlives_env.region_bound_pairs_map(),
+                Some(tcx.lifetimes.re_root_empty),
+                param_env,
+            );
+
+            let errors =
+                infcx.resolve_regions(region_context, &outlives_env, RegionckMode::default());
+            if !errors.is_empty() {
+                return false;
+            }
+
+            true
         })
         .unwrap_or(false)
 }
@@ -599,7 +626,7 @@ fn uncover_fundamental_ty<'tcx>(
                 .substs
                 .types()
                 .flat_map(|ty| uncover_fundamental_ty(tcx, ty, in_crate))
-                .find(|ty| ty_is_local_constructor(ty, in_crate));
+                .find(|ty| ty_is_local_constructor(*ty, in_crate));
 
             debug!("orphan_check_trait_ref: uncovered ty local_type: `{:?}`", local_type);
 
index 96a944017bc2406b375fd18cd5c9273b2da0c279..1994faed70c66bfabe0514160b28a582530c8cc3 100644 (file)
@@ -8,6 +8,7 @@
 //! In this case we try to build an abstract representation of this constant using
 //! `thir_abstract_const` which can then be checked for structural equality with other
 //! generic constants mentioned in the `caller_bounds` of the current environment.
+use rustc_data_structures::intern::Interned;
 use rustc_errors::ErrorReported;
 use rustc_hir::def::DefKind;
 use rustc_index::vec::IndexVec;
@@ -201,9 +202,9 @@ pub fn new(
 
     pub fn from_const(
         tcx: TyCtxt<'tcx>,
-        ct: &ty::Const<'tcx>,
+        ct: ty::Const<'tcx>,
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
-        match ct.val {
+        match ct.val() {
             ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv.shrink()),
             ty::ConstKind::Error(_) => Err(ErrorReported),
             _ => Ok(None),
@@ -293,7 +294,7 @@ fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) {
                 }
             }
 
-            fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) {
+            fn visit_const(&mut self, ct: ty::Const<'tcx>) {
                 self.is_poly |= ct.has_param_types_or_consts();
             }
         }
@@ -334,7 +335,11 @@ fn build(mut self) -> Result<&'tcx [Node<'tcx>], ErrorReported> {
         self.recurse_build(self.body_id)?;
 
         for n in self.nodes.iter() {
-            if let Node::Leaf(ty::Const { val: ty::ConstKind::Unevaluated(ct), ty: _ }) = n {
+            if let Node::Leaf(ty::Const(Interned(
+                ty::ConstS { val: ty::ConstKind::Unevaluated(ct), ty: _ },
+                _,
+            ))) = n
+            {
                 // `AbstractConst`s should not contain any promoteds as they require references which
                 // are not allowed.
                 assert_eq!(ct.promoted, None);
@@ -602,11 +607,11 @@ pub(super) fn try_unify<'tcx>(
 
     match (a.root(tcx), b.root(tcx)) {
         (Node::Leaf(a_ct), Node::Leaf(b_ct)) => {
-            if a_ct.ty != b_ct.ty {
+            if a_ct.ty() != b_ct.ty() {
                 return false;
             }
 
-            match (a_ct.val, b_ct.val) {
+            match (a_ct.val(), b_ct.val()) {
                 // We can just unify errors with everything to reduce the amount of
                 // emitted errors here.
                 (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true,
index 6cb19416cd769be512516716938bf2e57bd0e1ed..f22b4e8d072a81f243d8b0d5687a1e4b548868de 100644 (file)
 use rustc_hir::Node;
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{
-    self, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable,
+    self, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_session::DiagnosticMessageId;
 use rustc_span::symbol::{kw, sym};
 
 pub use rustc_infer::traits::error_reporting::*;
 
+// When outputting impl candidates, prefer showing those that are more similar.
+//
+// We also compare candidates after skipping lifetimes, which has a lower
+// priority than exact matches.
+#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+pub enum CandidateSimilarity {
+    Exact { ignoring_lifetimes: bool },
+    Fuzzy { ignoring_lifetimes: bool },
+}
+
+#[derive(Debug, Clone, Copy)]
+pub struct ImplCandidate<'tcx> {
+    pub trait_ref: ty::TraitRef<'tcx>,
+    pub similarity: CandidateSimilarity,
+}
+
 pub trait InferCtxtExt<'tcx> {
     fn report_fulfillment_errors(
         &self,
@@ -262,7 +277,7 @@ fn report_selection_error(
                         .tcx
                         .diagnostic_hir_wf_check((tcx.erase_regions(obligation.predicate), *wf_loc))
                     {
-                        obligation.cause = cause;
+                        obligation.cause = cause.clone();
                         span = obligation.cause.span;
                     }
                 }
@@ -1143,18 +1158,23 @@ fn report_projection_error(
         error: &MismatchedProjectionTypes<'tcx>,
     );
 
-    fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool;
+    fn fuzzy_match_tys(
+        &self,
+        a: Ty<'tcx>,
+        b: Ty<'tcx>,
+        ignoring_lifetimes: bool,
+    ) -> Option<CandidateSimilarity>;
 
     fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str>;
 
     fn find_similar_impl_candidates(
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Vec<ty::TraitRef<'tcx>>;
+    ) -> Vec<ImplCandidate<'tcx>>;
 
     fn report_similar_impl_candidates(
         &self,
-        impl_candidates: Vec<ty::TraitRef<'tcx>>,
+        impl_candidates: Vec<ImplCandidate<'tcx>>,
         err: &mut DiagnosticBuilder<'_>,
     );
 
@@ -1231,7 +1251,7 @@ fn maybe_indirection_for_unsized(
 
     fn is_recursive_obligation(
         &self,
-        obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+        obligated_types: &mut Vec<Ty<'tcx>>,
         cause_code: &ObligationCauseCode<'tcx>,
     ) -> bool;
 }
@@ -1378,26 +1398,11 @@ fn report_projection_error(
                     normalized_ty,
                     data.term,
                 ) {
-                    values = Some(match (normalized_ty, data.term) {
-                        (ty::Term::Ty(normalized_ty), ty::Term::Ty(ty)) => {
-                            infer::ValuePairs::Types(ExpectedFound::new(
-                                is_normalized_ty_expected,
-                                normalized_ty,
-                                ty,
-                            ))
-                        }
-                        (ty::Term::Const(normalized_ct), ty::Term::Const(ct)) => {
-                            infer::ValuePairs::Consts(ExpectedFound::new(
-                                is_normalized_ty_expected,
-                                normalized_ct,
-                                ct,
-                            ))
-                        }
-                        (_, _) => span_bug!(
-                            obligation.cause.span,
-                            "found const or type where other expected"
-                        ),
-                    });
+                    values = Some(infer::ValuePairs::Terms(ExpectedFound::new(
+                        is_normalized_ty_expected,
+                        normalized_ty,
+                        data.term,
+                    )));
                     err_buf = error;
                     err = &err_buf;
                 }
@@ -1461,45 +1466,80 @@ fn report_projection_error(
         });
     }
 
-    fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+    fn fuzzy_match_tys(
+        &self,
+        mut a: Ty<'tcx>,
+        mut b: Ty<'tcx>,
+        ignoring_lifetimes: bool,
+    ) -> Option<CandidateSimilarity> {
         /// returns the fuzzy category of a given type, or None
         /// if the type can be equated to any type.
-        fn type_category(t: Ty<'_>) -> Option<u32> {
+        fn type_category(tcx: TyCtxt<'_>, t: Ty<'_>) -> Option<u32> {
             match t.kind() {
                 ty::Bool => Some(0),
                 ty::Char => Some(1),
                 ty::Str => Some(2),
-                ty::Int(..) | ty::Uint(..) | ty::Infer(ty::IntVar(..)) => Some(3),
-                ty::Float(..) | ty::Infer(ty::FloatVar(..)) => Some(4),
+                ty::Adt(def, _) if tcx.is_diagnostic_item(sym::String, def.did) => Some(2),
+                ty::Int(..)
+                | ty::Uint(..)
+                | ty::Float(..)
+                | ty::Infer(ty::IntVar(..) | ty::FloatVar(..)) => Some(4),
                 ty::Ref(..) | ty::RawPtr(..) => Some(5),
                 ty::Array(..) | ty::Slice(..) => Some(6),
                 ty::FnDef(..) | ty::FnPtr(..) => Some(7),
                 ty::Dynamic(..) => Some(8),
                 ty::Closure(..) => Some(9),
                 ty::Tuple(..) => Some(10),
-                ty::Projection(..) => Some(11),
-                ty::Param(..) => Some(12),
+                ty::Param(..) => Some(11),
+                ty::Projection(..) => Some(12),
                 ty::Opaque(..) => Some(13),
                 ty::Never => Some(14),
-                ty::Adt(adt, ..) => match adt.adt_kind() {
-                    AdtKind::Struct => Some(15),
-                    AdtKind::Union => Some(16),
-                    AdtKind::Enum => Some(17),
-                },
-                ty::Generator(..) => Some(18),
-                ty::Foreign(..) => Some(19),
-                ty::GeneratorWitness(..) => Some(20),
+                ty::Adt(..) => Some(15),
+                ty::Generator(..) => Some(16),
+                ty::Foreign(..) => Some(17),
+                ty::GeneratorWitness(..) => Some(18),
                 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
             }
         }
 
-        match (type_category(a), type_category(b)) {
-            (Some(cat_a), Some(cat_b)) => match (a.kind(), b.kind()) {
-                (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b,
-                _ => cat_a == cat_b,
-            },
-            // infer and error can be equated to all types
-            _ => true,
+        let strip_references = |mut t: Ty<'tcx>| -> Ty<'tcx> {
+            loop {
+                match t.kind() {
+                    ty::Ref(_, inner, _) | ty::RawPtr(ty::TypeAndMut { ty: inner, .. }) => {
+                        t = *inner
+                    }
+                    _ => break t,
+                }
+            }
+        };
+
+        if !ignoring_lifetimes {
+            a = strip_references(a);
+            b = strip_references(b);
+        }
+
+        let cat_a = type_category(self.tcx, a)?;
+        let cat_b = type_category(self.tcx, b)?;
+        if a == b {
+            Some(CandidateSimilarity::Exact { ignoring_lifetimes })
+        } else if cat_a == cat_b {
+            match (a.kind(), b.kind()) {
+                (ty::Adt(def_a, _), ty::Adt(def_b, _)) => def_a == def_b,
+                // Matching on references results in a lot of unhelpful
+                // suggestions, so let's just not do that for now.
+                //
+                // We still upgrade successful matches to `ignoring_lifetimes: true`
+                // to prioritize that impl.
+                (ty::Ref(..) | ty::RawPtr(..), ty::Ref(..) | ty::RawPtr(..)) => {
+                    self.fuzzy_match_tys(a, b, true).is_some()
+                }
+                _ => true,
+            }
+            .then_some(CandidateSimilarity::Fuzzy { ignoring_lifetimes })
+        } else if ignoring_lifetimes {
+            None
+        } else {
+            self.fuzzy_match_tys(a, b, true)
         }
     }
 
@@ -1515,58 +1555,25 @@ fn describe_generator(&self, body_id: hir::BodyId) -> Option<&'static str> {
     fn find_similar_impl_candidates(
         &self,
         trait_ref: ty::PolyTraitRef<'tcx>,
-    ) -> Vec<ty::TraitRef<'tcx>> {
-        // We simplify params and strip references here.
-        //
-        // This both removes a lot of unhelpful suggestions, e.g.
-        // when searching for `&Foo: Trait` it doesn't suggestion `impl Trait for &Bar`,
-        // while also suggesting impls for `&Foo` when we're looking for `Foo: Trait`.
-        //
-        // The second thing isn't necessarily always a good thing, but
-        // any other simple setup results in a far worse output, so 🤷
-        let simp = fast_reject::simplify_type(
-            self.tcx,
-            trait_ref.skip_binder().self_ty(),
-            SimplifyParams::Yes,
-            StripReferences::Yes,
-        );
-        let all_impls = self.tcx.all_impls(trait_ref.def_id());
-
-        match simp {
-            Some(simp) => all_impls
-                .filter_map(|def_id| {
-                    let imp = self.tcx.impl_trait_ref(def_id).unwrap();
-                    let imp_simp = fast_reject::simplify_type(
-                        self.tcx,
-                        imp.self_ty(),
-                        SimplifyParams::Yes,
-                        StripReferences::Yes,
-                    );
-                    if let Some(imp_simp) = imp_simp {
-                        if simp != imp_simp {
-                            return None;
-                        }
-                    }
-                    if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative {
-                        return None;
-                    }
-                    Some(imp)
-                })
-                .collect(),
-            None => all_impls
-                .filter_map(|def_id| {
-                    if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative {
-                        return None;
-                    }
-                    self.tcx.impl_trait_ref(def_id)
-                })
-                .collect(),
-        }
+    ) -> Vec<ImplCandidate<'tcx>> {
+        self.tcx
+            .all_impls(trait_ref.def_id())
+            .filter_map(|def_id| {
+                if self.tcx.impl_polarity(def_id) == ty::ImplPolarity::Negative {
+                    return None;
+                }
+
+                let imp = self.tcx.impl_trait_ref(def_id).unwrap();
+
+                self.fuzzy_match_tys(trait_ref.skip_binder().self_ty(), imp.self_ty(), false)
+                    .map(|similarity| ImplCandidate { trait_ref: imp, similarity })
+            })
+            .collect()
     }
 
     fn report_similar_impl_candidates(
         &self,
-        impl_candidates: Vec<ty::TraitRef<'tcx>>,
+        impl_candidates: Vec<ImplCandidate<'tcx>>,
         err: &mut DiagnosticBuilder<'_>,
     ) {
         if impl_candidates.is_empty() {
@@ -1590,13 +1597,24 @@ fn report_similar_impl_candidates(
         };
 
         // Sort impl candidates so that ordering is consistent for UI tests.
-        let mut normalized_impl_candidates =
-            impl_candidates.iter().copied().map(normalize).collect::<Vec<String>>();
-
-        // Sort before taking the `..end` range,
         // because the ordering of `impl_candidates` may not be deterministic:
         // https://github.com/rust-lang/rust/pull/57475#issuecomment-455519507
-        normalized_impl_candidates.sort();
+        //
+        // Prefer more similar candidates first, then sort lexicographically
+        // by their normalized string representation.
+        let mut normalized_impl_candidates_and_similarities = impl_candidates
+            .into_iter()
+            .map(|ImplCandidate { trait_ref, similarity }| {
+                let normalized = normalize(trait_ref);
+                (similarity, normalized)
+            })
+            .collect::<Vec<_>>();
+        normalized_impl_candidates_and_similarities.sort();
+
+        let normalized_impl_candidates = normalized_impl_candidates_and_similarities
+            .into_iter()
+            .map(|(_, normalized)| normalized)
+            .collect::<Vec<_>>();
 
         err.help(&format!(
             "the following implementations were found:{}{}",
@@ -1759,7 +1777,11 @@ fn maybe_report_ambiguity(
                     return;
                 }
 
-                let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+                let impl_candidates = self
+                    .find_similar_impl_candidates(trait_ref)
+                    .into_iter()
+                    .map(|candidate| candidate.trait_ref)
+                    .collect();
                 let mut err = self.emit_inference_failure_err(
                     body_id,
                     span,
@@ -2032,7 +2054,7 @@ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
             fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() {
                     let infcx = self.infcx;
-                    self.var_map.entry(ty).or_insert_with(|| {
+                    *self.var_map.entry(ty).or_insert_with(|| {
                         infcx.next_ty_var(TypeVariableOrigin {
                             kind: TypeVariableOriginKind::TypeParameterDefinition(name, None),
                             span: DUMMY_SP,
@@ -2223,7 +2245,7 @@ fn maybe_indirection_for_unsized<'hir>(
 
     fn is_recursive_obligation(
         &self,
-        obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+        obligated_types: &mut Vec<Ty<'tcx>>,
         cause_code: &ObligationCauseCode<'tcx>,
     ) -> bool {
         if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
index 1540725246b514cd887589da70f86c6588704d2c..6c8a08c09e7778acd9549e4ebf59bc81d5636e3f 100644 (file)
@@ -56,7 +56,7 @@ fn impl_similar_to(
                     trait_ref.substs.types().skip(1),
                     impl_trait_ref.substs.types().skip(1),
                 )
-                .all(|(u, v)| self.fuzzy_match_tys(u, v))
+                .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some())
                 {
                     fuzzy_match_impls.push(def_id);
                 }
@@ -77,7 +77,7 @@ fn impl_similar_to(
     /// Used to set on_unimplemented's `ItemContext`
     /// to be the enclosing (async) block/function/closure
     fn describe_enclosure(&self, hir_id: hir::HirId) -> Option<&'static str> {
-        let hir = &self.tcx.hir();
+        let hir = self.tcx.hir();
         let node = hir.find(hir_id)?;
         match &node {
             hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, _, body_id), .. }) => {
@@ -211,7 +211,8 @@ fn on_unimplemented_note(
                     let type_string = self.tcx.type_of(def.did).to_string();
                     flags.push((sym::_Self, Some(format!("[{}]", type_string))));
 
-                    let len = len.val.try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
+                    let len =
+                        len.val().try_to_value().and_then(|v| v.try_to_machine_usize(self.tcx));
                     let string = match len {
                         Some(n) => format!("[{}; {}]", type_string, n),
                         None => format!("[{}; _]", type_string),
index 6634f3e364d327c082c5c186fa696a13d11a527a..7df880a7cc05509d463ca5546b00c91e1854648e 100644 (file)
@@ -167,7 +167,7 @@ fn note_obligation_cause_code<T>(
         predicate: &T,
         param_env: ty::ParamEnv<'tcx>,
         cause_code: &ObligationCauseCode<'tcx>,
-        obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+        obligated_types: &mut Vec<Ty<'tcx>>,
         seen_requirements: &mut FxHashSet<DefId>,
     ) where
         T: fmt::Display;
@@ -839,7 +839,7 @@ fn suggest_remove_reference(
                 let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
                     break;
                 };
-                suggested_ty = inner_ty;
+                suggested_ty = *inner_ty;
 
                 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
@@ -1099,9 +1099,7 @@ fn suggest_impl_trait(
             _ => return false,
         };
 
-        let ret_ty = if let hir::FnRetTy::Return(ret_ty) = sig.decl.output {
-            ret_ty
-        } else {
+        let hir::FnRetTy::Return(ret_ty) = sig.decl.output else {
             return false;
         };
 
@@ -1168,7 +1166,7 @@ fn suggest_impl_trait(
             };
 
         let sm = self.tcx.sess.source_map();
-        let snippet = if let (true, hir::TyKind::TraitObject(..), Ok(snippet), true) = (
+        let (true, hir::TyKind::TraitObject(..), Ok(snippet), true) = (
             // Verify that we're dealing with a return `dyn Trait`
             ret_ty.span.overlaps(span),
             &ret_ty.kind,
@@ -1176,9 +1174,7 @@ fn suggest_impl_trait(
             // If any of the return types does not conform to the trait, then we can't
             // suggest `impl Trait` nor trait objects: it is a type mismatch error.
             all_returns_conform_to_trait,
-        ) {
-            snippet
-        } else {
+        ) else {
             return false;
         };
         err.code(error_code!(E0746));
@@ -1597,7 +1593,7 @@ fn maybe_note_obligation_cause_for_async_await(
             if let Some(cause) =
                 typeck_results.generator_interior_types.as_ref().skip_binder().iter().find(
                     |ty::GeneratorInteriorTypeCause { ty, .. }| {
-                        ty_matches(typeck_results.generator_interior_types.rebind(ty))
+                        ty_matches(typeck_results.generator_interior_types.rebind(*ty))
                     },
                 )
             {
@@ -1904,7 +1900,7 @@ fn note_obligation_cause_code<T>(
         predicate: &T,
         param_env: ty::ParamEnv<'tcx>,
         cause_code: &ObligationCauseCode<'tcx>,
-        obligated_types: &mut Vec<&ty::TyS<'tcx>>,
+        obligated_types: &mut Vec<Ty<'tcx>>,
         seen_requirements: &mut FxHashSet<DefId>,
     ) where
         T: fmt::Display,
@@ -1932,7 +1928,8 @@ fn note_obligation_cause_code<T>(
             | ObligationCauseCode::AwaitableExpr(_)
             | ObligationCauseCode::ForLoopIterator
             | ObligationCauseCode::QuestionMark
-            | ObligationCauseCode::LetElse => {}
+            | ObligationCauseCode::LetElse
+            | ObligationCauseCode::CheckAssociatedTypeBounds { .. } => {}
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
             }
@@ -2471,7 +2468,7 @@ fn suggest_await_before_try(
                     // `T`
                     substs: self.tcx.mk_substs_trait(
                         trait_pred.self_ty().skip_binder(),
-                        self.fresh_substs_for_item(span, item_def_id),
+                        &self.fresh_substs_for_item(span, item_def_id)[1..],
                     ),
                     // `Future::Output`
                     item_def_id,
index e7897887df7063896245eacb455be83a41d75f81..1989184f48f0e26c434e5edc8d4747dbd302e58f 100644 (file)
@@ -562,7 +562,7 @@ fn progress_changed_obligations(
                         //
                         // Let's just see where this breaks :shrug:
                         if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
-                            (c1.val, c2.val)
+                            (c1.val(), c2.val())
                         {
                             if infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
                                 return ProcessResult::Changed(vec![]);
@@ -572,14 +572,14 @@ fn progress_changed_obligations(
 
                     let stalled_on = &mut pending_obligation.stalled_on;
 
-                    let mut evaluate = |c: &'tcx Const<'tcx>| {
-                        if let ty::ConstKind::Unevaluated(unevaluated) = c.val {
+                    let mut evaluate = |c: Const<'tcx>| {
+                        if let ty::ConstKind::Unevaluated(unevaluated) = c.val() {
                             match self.selcx.infcx().const_eval_resolve(
                                 obligation.param_env,
                                 unevaluated,
                                 Some(obligation.cause.span),
                             ) {
-                                Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty)),
+                                Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty())),
                                 Err(ErrorHandled::TooGeneric) => {
                                     stalled_on.extend(
                                         unevaluated
index 6b20476b95594de9862dc530417b850ea9a0728b..b05dbbe898a41d7498f75d5242a341ad81776b80 100644 (file)
@@ -62,6 +62,10 @@ fn parse(
         let mut errored = false;
         let mut item_iter = items.iter();
 
+        let parse_value = |value_str| {
+            OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
+        };
+
         let condition = if is_root {
             None
         } else {
@@ -86,7 +90,14 @@ fn parse(
                         None,
                     )
                 })?;
-            attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |_| true);
+            attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |item| {
+                if let Some(symbol) = item.value_str() {
+                    if parse_value(symbol).is_err() {
+                        errored = true;
+                    }
+                }
+                true
+            });
             Some(cond.clone())
         };
 
@@ -97,10 +108,6 @@ fn parse(
         let mut subcommands = vec![];
         let mut append_const_msg = None;
 
-        let parse_value = |value_str| {
-            OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
-        };
-
         for item in item_iter {
             if item.has_name(sym::message) && message.is_none() {
                 if let Some(message_) = item.value_str() {
@@ -221,6 +228,9 @@ pub fn evaluate(
         let mut append_const_msg = None;
         info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
 
+        let options_map: FxHashMap<Symbol, String> =
+            options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
+
         for command in self.subcommands.iter().chain(Some(self)).rev() {
             if let Some(ref condition) = command.condition {
                 if !attr::eval_condition(
@@ -229,7 +239,11 @@ pub fn evaluate(
                     Some(tcx.features()),
                     &mut |c| {
                         c.ident().map_or(false, |ident| {
-                            options.contains(&(ident.name, c.value_str().map(|s| s.to_string())))
+                            let value = c.value_str().map(|s| {
+                                OnUnimplementedFormatString(s).format(tcx, trait_ref, &options_map)
+                            });
+
+                            options.contains(&(ident.name, value))
                         })
                     },
                 ) {
@@ -257,13 +271,11 @@ pub fn evaluate(
             append_const_msg = command.append_const_msg.clone();
         }
 
-        let options: FxHashMap<Symbol, String> =
-            options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
         OnUnimplementedNote {
-            label: label.map(|l| l.format(tcx, trait_ref, &options)),
-            message: message.map(|m| m.format(tcx, trait_ref, &options)),
-            note: note.map(|n| n.format(tcx, trait_ref, &options)),
-            enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)),
+            label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
+            message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
+            note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
+            enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
             append_const_msg,
         }
     }
@@ -297,17 +309,23 @@ fn verify(
                 Piece::String(_) => (), // Normal string, no need to check it
                 Piece::NextArgument(a) => match a.position {
                     // `{Self}` is allowed
-                    Position::ArgumentNamed(s) if s == kw::SelfUpper => (),
+                    Position::ArgumentNamed(s, _) if s == kw::SelfUpper => (),
                     // `{ThisTraitsName}` is allowed
-                    Position::ArgumentNamed(s) if s == name => (),
+                    Position::ArgumentNamed(s, _) if s == name => (),
                     // `{from_method}` is allowed
-                    Position::ArgumentNamed(s) if s == sym::from_method => (),
+                    Position::ArgumentNamed(s, _) if s == sym::from_method => (),
                     // `{from_desugaring}` is allowed
-                    Position::ArgumentNamed(s) if s == sym::from_desugaring => (),
+                    Position::ArgumentNamed(s, _) if s == sym::from_desugaring => (),
                     // `{ItemContext}` is allowed
-                    Position::ArgumentNamed(s) if s == sym::ItemContext => (),
+                    Position::ArgumentNamed(s, _) if s == sym::ItemContext => (),
+                    // `{integral}` and `{integer}` and `{float}` are allowed
+                    Position::ArgumentNamed(s, _)
+                        if s == sym::integral || s == sym::integer_ || s == sym::float =>
+                    {
+                        ()
+                    }
                     // So is `{A}` if A is a type parameter
-                    Position::ArgumentNamed(s) => {
+                    Position::ArgumentNamed(s, _) => {
                         match generics.params.iter().find(|param| param.name == s) {
                             Some(_) => (),
                             None => {
@@ -374,7 +392,7 @@ pub fn format(
             .map(|p| match p {
                 Piece::String(s) => s,
                 Piece::NextArgument(a) => match a.position {
-                    Position::ArgumentNamed(s) => match generic_map.get(&s) {
+                    Position::ArgumentNamed(s, _) => match generic_map.get(&s) {
                         Some(val) => val,
                         None if s == name => &trait_str,
                         None => {
@@ -385,6 +403,12 @@ pub fn format(
                                 &empty_string
                             } else if s == sym::ItemContext {
                                 &item_context
+                            } else if s == sym::integral {
+                                "{integral}"
+                            } else if s == sym::integer_ {
+                                "{integer}"
+                            } else if s == sym::float {
+                                "{float}"
                             } else {
                                 bug!(
                                     "broken on_unimplemented {:?} for {:?}: \
index 5e7d4c8b415c33902049d1635124eab9e3550b53..5f338664c9a98be4d0e97e9e7210ea3281fe6eac 100644 (file)
@@ -499,7 +499,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
         if self.selcx.tcx().lazy_normalization() {
             constant
         } else {
@@ -622,24 +622,24 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        match *ct {
-            ty::Const { val: ty::ConstKind::Bound(debruijn, _), ty: _ }
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        match ct.val() {
+            ty::ConstKind::Bound(debruijn, _)
                 if debruijn.as_usize() + 1
                     > self.current_index.as_usize() + self.universe_indices.len() =>
             {
                 bug!("Bound vars outside of `self.universe_indices`");
             }
-            ty::Const { val: ty::ConstKind::Bound(debruijn, bound_const), ty }
-                if debruijn >= self.current_index =>
-            {
+            ty::ConstKind::Bound(debruijn, bound_const) if debruijn >= self.current_index => {
                 let universe = self.universe_for(debruijn);
                 let p = ty::PlaceholderConst {
                     universe,
-                    name: ty::BoundConst { var: bound_const, ty },
+                    name: ty::BoundConst { var: bound_const, ty: ct.ty() },
                 };
                 self.mapped_consts.insert(p, bound_const);
-                self.infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Placeholder(p), ty })
+                self.infcx
+                    .tcx
+                    .mk_const(ty::ConstS { val: ty::ConstKind::Placeholder(p), ty: ct.ty() })
             }
             _ if ct.has_vars_bound_at_or_above(self.current_index) => ct.super_fold_with(self),
             _ => ct,
@@ -697,7 +697,7 @@ fn fold_binder<T: TypeFoldable<'tcx>>(
     }
 
     fn fold_region(&mut self, r0: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        let r1 = match r0 {
+        let r1 = match *r0 {
             ty::ReVar(_) => self
                 .infcx
                 .inner
@@ -758,8 +758,8 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
-        if let ty::Const { val: ty::ConstKind::Placeholder(p), ty } = *ct {
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        if let ty::ConstKind::Placeholder(p) = ct.val() {
             let replace_var = self.mapped_consts.get(&p);
             match replace_var {
                 Some(replace_var) => {
@@ -771,8 +771,10 @@ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
                     let db = ty::DebruijnIndex::from_usize(
                         self.universe_indices.len() - index + self.current_index.as_usize() - 1,
                     );
-                    self.tcx()
-                        .mk_const(ty::Const { val: ty::ConstKind::Bound(db, *replace_var), ty })
+                    self.tcx().mk_const(ty::ConstS {
+                        val: ty::ConstKind::Bound(db, *replace_var),
+                        ty: ct.ty(),
+                    })
                 }
                 None => ct,
             }
@@ -1073,6 +1075,16 @@ fn project<'cx, 'tcx>(
         return Ok(Projected::Progress(Progress::error(selcx.tcx())));
     }
 
+    // If the obligation contains any inference types or consts in associated
+    // type substs, then we don't assemble any candidates.
+    // This isn't really correct, but otherwise we can end up in a case where
+    // we constrain inference variables by selecting a single predicate, when
+    // we need to stay general. See issue #91762.
+    let (_, predicate_own_substs) = obligation.predicate.trait_ref_and_own_substs(selcx.tcx());
+    if predicate_own_substs.iter().any(|g| g.has_infer_types_or_consts()) {
+        return Err(ProjectionError::TooManyCandidates);
+    }
+
     let mut candidates = ProjectionCandidateSet::None;
 
     // Make sure that the following procedures are kept in order. ParamEnv
@@ -1852,7 +1864,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
             crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
         let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
         let val = ty::ConstKind::Unevaluated(ty::Unevaluated::new(did, identity_substs));
-        tcx.mk_const(ty::Const { ty, val }).into()
+        tcx.mk_const(ty::ConstS { ty, val }).into()
     } else {
         ty.into()
     };
index f05582f0614299b0682be31434a6a4f5bbffc7b9..55903a3c36a29ae09b82d291e72e6f43411005e9 100644 (file)
@@ -104,7 +104,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
         | ty::Error(_) => true,
 
         // [T; N] and [T] have same properties as T.
-        ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty),
+        ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty),
 
         // (T1..Tn) and closures have same properties as T1..Tn --
         // check if *any* of those are trivial.
index 3c9e1bbcef26deffa1783a25ed9f7078065e5901..6a2bd9ce1ea91d3043d04b07a38048fb20c1e35c 100644 (file)
@@ -140,8 +140,8 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         ControlFlow::CONTINUE
     }
 
-    fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match ct.val {
+    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        match ct.val() {
             ty::ConstKind::Bound(debruijn, _) if debruijn >= self.outer_index => {
                 self.escaping =
                     self.escaping.max(debruijn.as_usize() - self.outer_index.as_usize());
@@ -188,7 +188,7 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         }
 
         if let Some(ty) = self.cache.get(&ty) {
-            return Ok(ty);
+            return Ok(*ty);
         }
 
         // See note in `rustc_trait_selection::traits::project` about why we
@@ -324,8 +324,8 @@ fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
 
     fn try_fold_const(
         &mut self,
-        constant: &'tcx ty::Const<'tcx>,
-    ) -> Result<&'tcx ty::Const<'tcx>, Self::Error> {
+        constant: ty::Const<'tcx>,
+    ) -> Result<ty::Const<'tcx>, Self::Error> {
         let constant = constant.try_super_fold_with(self)?;
         Ok(constant.eval(self.infcx.tcx, self.param_env))
     }
index 639884844b25d599208805359473fb4742292bbe..84bc7cdff28905f1742f022cca737c48b8efbae2 100644 (file)
@@ -983,7 +983,7 @@ fn confirm_builtin_unsize_candidate(
                     // Lifetimes aren't allowed to change during unsizing.
                     GenericArgKind::Lifetime(_) => None,
 
-                    GenericArgKind::Const(ct) => match ct.val {
+                    GenericArgKind::Const(ct) => match ct.val() {
                         ty::ConstKind::Param(p) => Some(p.index),
                         _ => None,
                     },
index 47427395b93b36adff83c8dda2f9034cc12346bf..64af875dd22bbb8a2024f88e824c79fd90e76dba 100644 (file)
@@ -36,7 +36,7 @@
 use rustc_middle::dep_graph::{DepKind, DepNodeIndex};
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::thir::abstract_const::NotConstEvaluatable;
-use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifyParams};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef};
@@ -643,7 +643,7 @@ fn evaluate_predicate_recursively<'o>(
                         //
                         // Let's just see where this breaks :shrug:
                         if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
-                            (c1.val, c2.val)
+                            (c1.val(), c2.val())
                         {
                             if self.infcx.try_unify_abstract_consts(a.shrink(), b.shrink()) {
                                 return Ok(EvaluatedToOk);
@@ -651,15 +651,15 @@ fn evaluate_predicate_recursively<'o>(
                         }
                     }
 
-                    let evaluate = |c: &'tcx ty::Const<'tcx>| {
-                        if let ty::ConstKind::Unevaluated(unevaluated) = c.val {
+                    let evaluate = |c: ty::Const<'tcx>| {
+                        if let ty::ConstKind::Unevaluated(unevaluated) = c.val() {
                             self.infcx
                                 .const_eval_resolve(
                                     obligation.param_env,
                                     unevaluated,
                                     Some(obligation.cause.span),
                                 )
-                                .map(|val| ty::Const::from_value(self.tcx(), val, c.ty))
+                                .map(|val| ty::Const::from_value(self.tcx(), val, c.ty()))
                         } else {
                             Ok(c)
                         }
@@ -2033,7 +2033,7 @@ fn collect_predicates_for_types(
             .skip_binder() // binder moved -\
             .iter()
             .flat_map(|ty| {
-                let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(ty); // <----/
+                let ty: ty::Binder<'tcx, Ty<'tcx>> = types.rebind(*ty); // <----/
 
                 self.infcx.commit_unconditionally(|_| {
                     let placeholder_ty = self.infcx.replace_bound_vars_with_placeholders(ty);
@@ -2172,14 +2172,9 @@ fn fast_reject_trait_refs(
                             self.tcx(),
                             obligation_ty,
                             SimplifyParams::Yes,
-                            StripReferences::No,
-                        );
-                        let simplified_impl_ty = fast_reject::simplify_type(
-                            self.tcx(),
-                            impl_ty,
-                            SimplifyParams::No,
-                            StripReferences::No,
                         );
+                        let simplified_impl_ty =
+                            fast_reject::simplify_type(self.tcx(), impl_ty, SimplifyParams::No);
 
                         simplified_obligation_ty.is_some()
                             && simplified_impl_ty.is_some()
index b098e8590da01e19f50afa446e817de4691578ee..38a6220082ff6318678f9c8aaaf6f2f4307a5e00 100644 (file)
@@ -510,7 +510,7 @@ fn report_conflicting_impls(
     for (mut p, _) in predicates {
         if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() {
             if Some(poly_trait_ref.def_id()) == sized_trait {
-                types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder());
+                types_without_default_bounds.remove(&poly_trait_ref.self_ty().skip_binder());
                 continue;
             }
 
index 5ee8b45e66b5c07934d95fca6668c7b571680659..497ac207bbe4f3a226d277165e722a61ed10e9ee 100644 (file)
@@ -2,7 +2,7 @@
 
 use crate::traits;
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 
@@ -49,12 +49,7 @@ impl ChildrenExt<'_> for Children {
     /// Insert an impl into this set of children without comparing to any existing impls.
     fn insert_blindly(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
-        if let Some(st) = fast_reject::simplify_type(
-            tcx,
-            trait_ref.self_ty(),
-            SimplifyParams::No,
-            StripReferences::No,
-        ) {
+        if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No) {
             debug!("insert_blindly: impl_def_id={:?} st={:?}", impl_def_id, st);
             self.non_blanket_impls.entry(st).or_default().push(impl_def_id)
         } else {
@@ -69,12 +64,7 @@ fn insert_blindly(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
     fn remove_existing(&mut self, tcx: TyCtxt<'_>, impl_def_id: DefId) {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
         let vec: &mut Vec<DefId>;
-        if let Some(st) = fast_reject::simplify_type(
-            tcx,
-            trait_ref.self_ty(),
-            SimplifyParams::No,
-            StripReferences::No,
-        ) {
+        if let Some(st) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No) {
             debug!("remove_existing: impl_def_id={:?} st={:?}", impl_def_id, st);
             vec = self.non_blanket_impls.get_mut(&st).unwrap();
         } else {
@@ -322,12 +312,7 @@ fn insert(
 
         let mut parent = trait_def_id;
         let mut last_lint = None;
-        let simplified = fast_reject::simplify_type(
-            tcx,
-            trait_ref.self_ty(),
-            SimplifyParams::No,
-            StripReferences::No,
-        );
+        let simplified = fast_reject::simplify_type(tcx, trait_ref.self_ty(), SimplifyParams::No);
 
         // Descend the specialization tree, where `parent` is the current parent node.
         loop {
index 493cb199f114485d544538a14e22f1e8dbd7d41e..2dd3b77a73cdff8273ae00059e965b5bc0579611 100644 (file)
@@ -41,7 +41,7 @@ pub fn obligations<'a, 'tcx>(
             .into()
         }
         GenericArgKind::Const(ct) => {
-            match ct.val {
+            match ct.val() {
                 ty::ConstKind::Infer(infer) => {
                     let resolved = infcx.shallow_resolve(infer);
                     if resolved == infer {
@@ -49,7 +49,9 @@ pub fn obligations<'a, 'tcx>(
                         return None;
                     }
 
-                    infcx.tcx.mk_const(ty::Const { val: ty::ConstKind::Infer(resolved), ty: ct.ty })
+                    infcx
+                        .tcx
+                        .mk_const(ty::ConstS { val: ty::ConstKind::Infer(resolved), ty: ct.ty() })
                 }
                 _ => ct,
             }
@@ -198,7 +200,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
     trait_ref: &ty::TraitRef<'tcx>,
     item: Option<&hir::Item<'tcx>>,
     cause: &mut traits::ObligationCause<'tcx>,
-    pred: &ty::Predicate<'tcx>,
+    pred: ty::Predicate<'tcx>,
 ) {
     debug!(
         "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}",
@@ -319,7 +321,7 @@ fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elabo
                 trait_ref,
                 item,
                 &mut cause,
-                &obligation.predicate,
+                obligation.predicate,
             );
             traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate)
         };
@@ -442,7 +444,7 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                 GenericArgKind::Lifetime(_) => continue,
 
                 GenericArgKind::Const(constant) => {
-                    match constant.val {
+                    match constant.val() {
                         ty::ConstKind::Unevaluated(uv) => {
                             let obligations = self.nominal_obligations(uv.def.did, uv.substs);
                             self.out.extend(obligations);
@@ -464,9 +466,9 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                             if resolved != infer {
                                 let cause = self.cause(traits::MiscObligation);
 
-                                let resolved_constant = self.infcx.tcx.mk_const(ty::Const {
+                                let resolved_constant = self.infcx.tcx.mk_const(ty::ConstS {
                                     val: ty::ConstKind::Infer(resolved),
-                                    ..*constant
+                                    ty: constant.ty(),
                                 });
                                 self.out.push(traits::Obligation::with_depth(
                                     cause,
index 3f51442277f5940f16c493959088ab8ec224587f..51b66e1bb6503c08bde62e38a5ea014af4fc4b71 100644 (file)
 use std::fmt;
 use std::sync::Arc;
 
-use crate::chalk::lowering::{self, LowerInto};
+use crate::chalk::lowering::LowerInto;
 
 pub struct RustIrDatabase<'tcx> {
     pub(crate) interner: RustInterner<'tcx>,
-    pub(crate) reempty_placeholder: ty::Region<'tcx>,
 }
 
 impl fmt::Debug for RustIrDatabase<'_> {
@@ -40,12 +39,9 @@ fn where_clauses_for(
         bound_vars: SubstsRef<'tcx>,
     ) -> Vec<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>> {
         let predicates = self.interner.tcx.predicates_defined_on(def_id).predicates;
-        let mut regions_substitutor =
-            lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
         predicates
             .iter()
             .map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars))
-            .map(|wc| wc.fold_with(&mut regions_substitutor))
             .filter_map(|wc| LowerInto::<
                     Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>
                     >::lower_into(wc, self.interner)).collect()
@@ -287,9 +283,6 @@ fn impl_datum(
 
         let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl");
         let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars);
-        let mut regions_substitutor =
-            lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
-        let trait_ref = trait_ref.fold_with(&mut regions_substitutor);
 
         let where_clauses = self.where_clauses_for(def_id, bound_vars);
 
@@ -335,9 +328,6 @@ fn impls_for_trait(
 
             let self_ty = trait_ref.self_ty();
             let self_ty = self_ty.subst(self.interner.tcx, bound_vars);
-            let mut regions_substitutor =
-                lowering::RegionsSubstitutor::new(self.interner.tcx, self.reempty_placeholder);
-            let self_ty = self_ty.fold_with(&mut regions_substitutor);
             let lowered_ty = self_ty.lower_into(self.interner);
 
             parameters[0].assert_ty_ref(self.interner).could_match(
@@ -556,11 +546,11 @@ fn well_known_trait_id(
             Fn => lang_items.fn_trait(),
             FnMut => lang_items.fn_mut_trait(),
             FnOnce => lang_items.fn_once_trait(),
+            Generator => lang_items.gen_trait(),
             Unsize => lang_items.unsize_trait(),
             Unpin => lang_items.unpin_trait(),
             CoerceUnsized => lang_items.coerce_unsized_trait(),
             DiscriminantKind => lang_items.discriminant_kind_trait(),
-            Generator => lang_items.generator_return(),
         };
         def_id.map(chalk_ir::TraitId)
     }
@@ -684,28 +674,18 @@ fn fn_def_variance(
         let variances = self.interner.tcx.variances_of(def_id.0);
         chalk_ir::Variances::from_iter(
             self.interner,
-            variances.iter().map(|v| match v {
-                ty::Variance::Invariant => chalk_ir::Variance::Invariant,
-                ty::Variance::Covariant => chalk_ir::Variance::Covariant,
-                ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
-                ty::Variance::Bivariant => unimplemented!(),
-            }),
+            variances.iter().map(|v| v.lower_into(self.interner)),
         )
     }
 
     fn adt_variance(
         &self,
-        def_id: chalk_ir::AdtId<RustInterner<'tcx>>,
+        adt_id: chalk_ir::AdtId<RustInterner<'tcx>>,
     ) -> chalk_ir::Variances<RustInterner<'tcx>> {
-        let variances = self.interner.tcx.variances_of(def_id.0.did);
+        let variances = self.interner.tcx.variances_of(adt_id.0.did);
         chalk_ir::Variances::from_iter(
             self.interner,
-            variances.iter().map(|v| match v {
-                ty::Variance::Invariant => chalk_ir::Variance::Invariant,
-                ty::Variance::Covariant => chalk_ir::Variance::Covariant,
-                ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
-                ty::Variance::Bivariant => unimplemented!(),
-            }),
+            variances.iter().map(|v| v.lower_into(self.interner)),
         )
     }
 }
@@ -731,11 +711,11 @@ fn bound_vars_for_item<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> SubstsRef<'tcx
                 var: ty::BoundVar::from_usize(substs.len()),
                 kind: ty::BrAnon(substs.len() as u32),
             };
-            tcx.mk_region(ty::RegionKind::ReLateBound(ty::INNERMOST, br)).into()
+            tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
         }
 
         ty::GenericParamDefKind::Const { .. } => tcx
-            .mk_const(ty::Const {
+            .mk_const(ty::ConstS {
                 val: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)),
                 ty: tcx.type_of(param.def_id),
             })
@@ -755,7 +735,7 @@ fn binders_for<'tcx>(
                 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
             }
             ty::subst::GenericArgKind::Const(c) => {
-                chalk_ir::VariableKind::Const(c.ty.lower_into(interner))
+                chalk_ir::VariableKind::Const(c.ty().lower_into(interner))
             }
         }),
     )
index 67d0ba39667d31127bb910d1283bace99b87356c..9d810d0881b5f8351fb7694a02aa6378ef231991 100644 (file)
@@ -35,7 +35,7 @@
 use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner};
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_middle::ty::{self, Binder, Region, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor};
+use rustc_middle::ty::{self, Binder, Region, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 use rustc_span::def_id::DefId;
 
 use chalk_ir::{FnSig, ForeignDefId};
@@ -188,12 +188,18 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::GoalData<RustInte
                 chalk_ir::DomainGoal::ObjectSafe(chalk_ir::TraitId(t)),
             ),
 
+            ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => {
+                chalk_ir::GoalData::SubtypeGoal(chalk_ir::SubtypeGoal {
+                    a: a.lower_into(interner),
+                    b: b.lower_into(interner),
+                })
+            }
+
             // FIXME(chalk): other predicates
             //
             // We can defer this, but ultimately we'll want to express
             // some of these in terms of chalk operations.
             ty::PredicateKind::ClosureKind(..)
-            | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..) => {
@@ -383,7 +389,7 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> Ty<'tcx> {
             TyKind::Array(ty, c) => {
                 let ty = ty.lower_into(interner);
                 let c = c.lower_into(interner);
-                ty::Array(ty, interner.tcx.mk_const(c))
+                ty::Array(ty, c)
             }
             TyKind::FnDef(id, substitution) => ty::FnDef(id.0, substitution.lower_into(interner)),
             TyKind::Closure(closure, substitution) => {
@@ -443,30 +449,30 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> Ty<'tcx> {
 
 impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime<RustInterner<'tcx>>> for Region<'tcx> {
     fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Lifetime<RustInterner<'tcx>> {
-        use rustc_middle::ty::RegionKind::*;
-
-        match self {
-            ReEarlyBound(_) => {
+        match *self {
+            ty::ReEarlyBound(_) => {
                 panic!("Should have already been substituted.");
             }
-            ReLateBound(db, br) => chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(
+            ty::ReLateBound(db, br) => chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(
                 chalk_ir::DebruijnIndex::new(db.as_u32()),
                 br.var.as_usize(),
             ))
             .intern(interner),
-            ReFree(_) => unimplemented!(),
-            ReStatic => chalk_ir::LifetimeData::Static.intern(interner),
-            ReVar(_) => unimplemented!(),
-            RePlaceholder(placeholder_region) => {
+            ty::ReFree(_) => unimplemented!(),
+            ty::ReStatic => chalk_ir::LifetimeData::Static.intern(interner),
+            ty::ReVar(_) => unimplemented!(),
+            ty::RePlaceholder(placeholder_region) => {
                 chalk_ir::LifetimeData::Placeholder(chalk_ir::PlaceholderIndex {
                     ui: chalk_ir::UniverseIndex { counter: placeholder_region.universe.index() },
                     idx: 0,
                 })
                 .intern(interner)
             }
-            ReEmpty(_) => unimplemented!(),
-            // FIXME(chalk): need to handle ReErased
-            ReErased => unimplemented!(),
+            ty::ReEmpty(ui) => {
+                chalk_ir::LifetimeData::Empty(chalk_ir::UniverseIndex { counter: ui.index() })
+                    .intern(interner)
+            }
+            ty::ReErased => chalk_ir::LifetimeData::Erased.intern(interner),
         }
     }
 }
@@ -474,7 +480,7 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Lifetime<RustInte
 impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime<RustInterner<'tcx>> {
     fn lower_into(self, interner: RustInterner<'tcx>) -> Region<'tcx> {
         let kind = match self.data(interner) {
-            chalk_ir::LifetimeData::BoundVar(var) => ty::RegionKind::ReLateBound(
+            chalk_ir::LifetimeData::BoundVar(var) => ty::ReLateBound(
                 ty::DebruijnIndex::from_u32(var.debruijn.depth()),
                 ty::BoundRegion {
                     var: ty::BoundVar::from_usize(var.index),
@@ -482,18 +488,16 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> Region<'tcx> {
                 },
             ),
             chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(),
-            chalk_ir::LifetimeData::Placeholder(p) => {
-                ty::RegionKind::RePlaceholder(ty::Placeholder {
-                    universe: ty::UniverseIndex::from_usize(p.ui.counter),
-                    name: ty::BoundRegionKind::BrAnon(p.idx as u32),
-                })
-            }
-            chalk_ir::LifetimeData::Static => ty::RegionKind::ReStatic,
-            chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(),
+            chalk_ir::LifetimeData::Placeholder(p) => ty::RePlaceholder(ty::Placeholder {
+                universe: ty::UniverseIndex::from_usize(p.ui.counter),
+                name: ty::BoundRegionKind::BrAnon(p.idx as u32),
+            }),
+            chalk_ir::LifetimeData::Static => return interner.tcx.lifetimes.re_static,
             chalk_ir::LifetimeData::Empty(ui) => {
-                ty::RegionKind::ReEmpty(ty::UniverseIndex::from_usize(ui.counter))
+                ty::ReEmpty(ty::UniverseIndex::from_usize(ui.counter))
             }
-            chalk_ir::LifetimeData::Erased => ty::RegionKind::ReErased,
+            chalk_ir::LifetimeData::Erased => return interner.tcx.lifetimes.re_erased,
+            chalk_ir::LifetimeData::Phantom(void, _) => match *void {},
         };
         interner.tcx.mk_region(kind)
     }
@@ -501,8 +505,8 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> Region<'tcx> {
 
 impl<'tcx> LowerInto<'tcx, chalk_ir::Const<RustInterner<'tcx>>> for ty::Const<'tcx> {
     fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Const<RustInterner<'tcx>> {
-        let ty = self.ty.lower_into(interner);
-        let value = match self.val {
+        let ty = self.ty().lower_into(interner);
+        let value = match self.val() {
             ty::ConstKind::Value(val) => {
                 chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: val })
             }
@@ -528,7 +532,7 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> ty::Const<'tcx> {
             chalk_ir::ConstValue::Placeholder(_p) => unimplemented!(),
             chalk_ir::ConstValue::Concrete(c) => ty::ConstKind::Value(c.interned),
         };
-        ty::Const { ty, val }
+        interner.tcx.mk_const(ty::ConstS { ty, val })
     }
 }
 
@@ -564,7 +568,7 @@ fn lower_into(self, interner: RustInterner<'tcx>) -> ty::subst::GenericArg<'tcx>
             }
             chalk_ir::GenericArgData::Const(c) => {
                 let c: ty::Const<'tcx> = c.lower_into(interner);
-                interner.tcx.mk_const(c).into()
+                c.into()
             }
         }
     }
@@ -788,6 +792,16 @@ fn lower_into(self, _interner: RustInterner<'tcx>) -> chalk_solve::rust_ir::Pola
         }
     }
 }
+impl<'tcx> LowerInto<'tcx, chalk_ir::Variance> for ty::Variance {
+    fn lower_into(self, _interner: RustInterner<'tcx>) -> chalk_ir::Variance {
+        match self {
+            ty::Variance::Covariant => chalk_ir::Variance::Covariant,
+            ty::Variance::Invariant => chalk_ir::Variance::Invariant,
+            ty::Variance::Contravariant => chalk_ir::Variance::Contravariant,
+            ty::Variance::Bivariant => unimplemented!(),
+        }
+    }
+}
 
 impl<'tcx> LowerInto<'tcx, chalk_solve::rust_ir::AliasEqBound<RustInterner<'tcx>>>
     for ty::ProjectionPredicate<'tcx>
@@ -897,8 +911,8 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
     }
 
     fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match r {
-            ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind {
+        match *r {
+            ty::ReLateBound(index, br) if index == self.binder_index => match br.kind {
                 ty::BoundRegionKind::BrNamed(def_id, _name) => {
                     if !self.named_parameters.iter().any(|d| *d == def_id) {
                         self.named_parameters.push(def_id);
@@ -959,12 +973,12 @@ fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'
     }
 
     fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
-        match r {
-            ty::ReLateBound(index, br) if *index == self.binder_index => match br.kind {
+        match *r {
+            ty::ReLateBound(index, br) if index == self.binder_index => match br.kind {
                 ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) {
                     Some(idx) => {
                         let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) };
-                        return self.tcx.mk_region(RegionKind::ReLateBound(*index, new_br));
+                        return self.tcx.mk_region(ty::ReLateBound(index, new_br));
                     }
                     None => panic!("Missing `BrNamed`."),
                 },
@@ -1016,10 +1030,6 @@ fn fold_binder<T: TypeFoldable<'tcx>>(&mut self, t: Binder<'tcx, T>) -> Binder<'
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
         match *t.kind() {
-            // FIXME(chalk): currently we convert params to placeholders starting at
-            // index `0`. To support placeholders, we'll actually need to do a
-            // first pass to collect placeholders. Then we can insert params after.
-            ty::Placeholder(_) => unimplemented!(),
             ty::Param(param) => match self.list.iter().position(|r| r == &param) {
                 Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType {
                     universe: ty::UniverseIndex::from_usize(0),
@@ -1035,29 +1045,29 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
                     }))
                 }
             },
-
             _ => t.super_fold_with(self),
         }
     }
 
     fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
-        match r {
-            // FIXME(chalk) - jackh726 - this currently isn't hit in any tests.
-            // This covers any region variables in a goal, right?
+        match *r {
+            // FIXME(chalk) - jackh726 - this currently isn't hit in any tests,
+            // since canonicalization will already change these to canonical
+            // variables (ty::ReLateBound).
             ty::ReEarlyBound(_re) => match self.named_regions.get(&_re.def_id) {
                 Some(idx) => {
                     let br = ty::BoundRegion {
                         var: ty::BoundVar::from_u32(*idx),
                         kind: ty::BrAnon(*idx),
                     };
-                    self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
+                    self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
                 }
                 None => {
                     let idx = self.named_regions.len() as u32;
                     let br =
                         ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) };
                     self.named_regions.insert(_re.def_id, idx);
-                    self.tcx.mk_region(RegionKind::ReLateBound(self.binder_index, br))
+                    self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
                 }
             },
 
@@ -1066,6 +1076,39 @@ fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
     }
 }
 
+crate struct ReverseParamsSubstitutor<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
+}
+
+impl<'tcx> ReverseParamsSubstitutor<'tcx> {
+    crate fn new(
+        tcx: TyCtxt<'tcx>,
+        params: rustc_data_structures::fx::FxHashMap<usize, rustc_middle::ty::ParamTy>,
+    ) -> Self {
+        Self { tcx, params }
+    }
+}
+
+impl<'tcx> TypeFolder<'tcx> for ReverseParamsSubstitutor<'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
+        match *t.kind() {
+            ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::ROOT, name }) => {
+                match self.params.get(&name.as_usize()) {
+                    Some(param) => self.tcx.mk_ty(ty::Param(*param)),
+                    None => t,
+                }
+            }
+
+            _ => t.super_fold_with(self),
+        }
+    }
+}
+
 /// Used to collect `Placeholder`s.
 crate struct PlaceholdersCollector {
     universe_index: ty::UniverseIndex,
@@ -1097,7 +1140,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
     }
 
     fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match r {
+        match *r {
             ty::RePlaceholder(p) if p.universe == self.universe_index => {
                 if let ty::BoundRegionKind::BrAnon(anon) = p.name {
                     self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon);
@@ -1110,32 +1153,3 @@ fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         r.super_visit_with(self)
     }
 }
-
-/// Used to substitute specific `Regions`s with placeholders.
-crate struct RegionsSubstitutor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    reempty_placeholder: ty::Region<'tcx>,
-}
-
-impl<'tcx> RegionsSubstitutor<'tcx> {
-    crate fn new(tcx: TyCtxt<'tcx>, reempty_placeholder: ty::Region<'tcx>) -> Self {
-        RegionsSubstitutor { tcx, reempty_placeholder }
-    }
-}
-
-impl<'tcx> TypeFolder<'tcx> for RegionsSubstitutor<'tcx> {
-    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
-        match r {
-            ty::ReEmpty(ui) => {
-                assert_eq!(ui.as_usize(), 0);
-                self.reempty_placeholder
-            }
-
-            _ => r.super_fold_with(self),
-        }
-    }
-}
index 09bfdabf4737357871a7fad22d2bfdd7f6f8577b..3c2a266dab9bcf996a555c754e4ee480b54cc1e6 100644 (file)
@@ -22,9 +22,8 @@
 use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal};
 
 use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase;
-use crate::chalk::lowering::{
-    LowerInto, ParamsSubstitutor, PlaceholdersCollector, RegionsSubstitutor,
-};
+use crate::chalk::lowering::LowerInto;
+use crate::chalk::lowering::{ParamsSubstitutor, PlaceholdersCollector, ReverseParamsSubstitutor};
 
 use chalk_solve::Solution;
 
     let mut placeholders_collector = PlaceholdersCollector::new();
     obligation.visit_with(&mut placeholders_collector);
 
-    let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder {
-        universe: ty::UniverseIndex::ROOT,
-        name: ty::BoundRegionKind::BrAnon(placeholders_collector.next_anon_region_placeholder + 1),
-    }));
-
     let mut params_substitutor =
         ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder);
     let obligation = obligation.fold_with(&mut params_substitutor);
-    // FIXME(chalk): we really should be substituting these back in the solution
-    let _params: FxHashMap<usize, ParamTy> = params_substitutor.params;
-
-    let mut regions_substitutor = RegionsSubstitutor::new(tcx, reempty_placeholder);
-    let obligation = obligation.fold_with(&mut regions_substitutor);
+    let params: FxHashMap<usize, ParamTy> = params_substitutor.params;
 
     let max_universe = obligation.max_universe.index();
 
@@ -96,7 +86,8 @@
 
     use chalk_solve::Solver;
     let mut solver = chalk_engine::solve::SLGSolver::new(32, None);
-    let db = ChalkRustIrDatabase { interner, reempty_placeholder };
+    let db = ChalkRustIrDatabase { interner };
+    debug!(?lowered_goal);
     let solution = solver.solve(&db, &lowered_goal);
     debug!(?obligation, ?solution, "evaluate goal");
 
         use rustc_middle::infer::canonical::CanonicalVarInfo;
 
         let mut var_values: IndexVec<BoundVar, GenericArg<'tcx>> = IndexVec::new();
+        let mut reverse_param_substitutor = ReverseParamsSubstitutor::new(tcx, params);
         subst.as_slice(interner).iter().for_each(|p| {
-            var_values.push(p.lower_into(interner));
+            var_values.push(p.lower_into(interner).fold_with(&mut reverse_param_substitutor));
         });
         let variables: Vec<_> = binders
             .iter(interner)
index 672e149b5fc96662969c3886a9e54123634caab1..455fc46a42e84476f0a70d05cfdaae0e055939b8 100644 (file)
@@ -192,7 +192,7 @@ fn dtorck_constraint_for_ty<'tcx>(
         ty::Array(ety, _) | ty::Slice(ety) => {
             // single-element containers, behave like their element
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
-                dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ety, constraints)
+                dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, *ety, constraints)
             })?;
         }
 
@@ -278,9 +278,9 @@ fn dtorck_constraint_for_ty<'tcx>(
                 tcx.at(span).adt_dtorck_constraint(def.did)?;
             // FIXME: we can try to recursively `dtorck_constraint_on_ty`
             // there, but that needs some way to handle cycles.
-            constraints.dtorck_types.extend(dtorck_types.subst(tcx, substs));
-            constraints.outlives.extend(outlives.subst(tcx, substs));
-            constraints.overflows.extend(overflows.subst(tcx, substs));
+            constraints.dtorck_types.extend(dtorck_types.iter().map(|t| t.subst(tcx, substs)));
+            constraints.outlives.extend(outlives.iter().map(|t| t.subst(tcx, substs)));
+            constraints.overflows.extend(overflows.iter().map(|t| t.subst(tcx, substs)));
         }
 
         // Objects must be alive in order for their destructor
@@ -308,7 +308,7 @@ fn dtorck_constraint_for_ty<'tcx>(
 crate fn adt_dtorck_constraint(
     tcx: TyCtxt<'_>,
     def_id: DefId,
-) -> Result<DtorckConstraint<'_>, NoSolution> {
+) -> Result<&DtorckConstraint<'_>, NoSolution> {
     let def = tcx.adt_def(def_id);
     let span = tcx.def_span(def_id);
     debug!("dtorck_constraint: {:?}", def);
@@ -324,7 +324,7 @@ fn dtorck_constraint_for_ty<'tcx>(
             overflows: vec![],
         };
         debug!("dtorck_constraint: {:?} => {:?}", def, result);
-        return Ok(result);
+        return Ok(tcx.arena.alloc(result));
     }
 
     let mut result = DtorckConstraint::empty();
@@ -337,7 +337,7 @@ fn dtorck_constraint_for_ty<'tcx>(
 
     debug!("dtorck_constraint: {:?} => {:?}", def, result);
 
-    Ok(result)
+    Ok(tcx.arena.alloc(result))
 }
 
 fn dedup_dtorck_constraint(c: &mut DtorckConstraint<'_>) {
index 46c2f7e4cf2ed2ada9587a72a69ff03ec8b77f54..a4aa965ec95333edee98c9a80e18aad5d8eff579 100644 (file)
@@ -39,7 +39,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq +
                 // always only region relations, and we are about to
                 // erase those anyway:
                 debug_assert_eq!(
-                    normalized_obligations.iter().find(|p| not_outlives_predicate(&p.predicate)),
+                    normalized_obligations.iter().find(|p| not_outlives_predicate(p.predicate)),
                     None,
                 );
 
@@ -57,7 +57,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq +
     })
 }
 
-fn not_outlives_predicate<'tcx>(p: &ty::Predicate<'tcx>) -> bool {
+fn not_outlives_predicate<'tcx>(p: ty::Predicate<'tcx>) -> bool {
     match p.kind().skip_binder() {
         ty::PredicateKind::RegionOutlives(..) | ty::PredicateKind::TypeOutlives(..) => false,
         ty::PredicateKind::Trait(..)
index e7cc0f69e9f952804cb7870e8677a03678e3a384..91c4398c178ca293c261442067830357e851afb8 100644 (file)
@@ -90,8 +90,8 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
     }
 
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match r {
-            ty::ReLateBound(index, br) if *index == self.binder_index => {
+        match *r {
+            ty::ReLateBound(index, br) if index == self.binder_index => {
                 match self.vars.entry(br.var.as_u32()) {
                     Entry::Vacant(entry) => {
                         entry.insert(ty::BoundVariableKind::Region(br.kind));
index 1717959acc1586b0164df16a510d29a9a8b90efa..b08f8f6230837685c2898fb7e22467eba9597ce4 100644 (file)
@@ -92,7 +92,7 @@ fn are_inner_types_recursive<'tcx>(
             seen,
             shadow_seen,
             representable_cache,
-            ty,
+            *ty,
             force_result,
         ),
         ty::Adt(def, substs) => {
@@ -255,7 +255,7 @@ fn is_type_structurally_recursive<'tcx>(
     force_result: &mut bool,
 ) -> Representability {
     debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
-    if let Some(representability) = representable_cache.get(ty) {
+    if let Some(representability) = representable_cache.get(&ty) {
         debug!(
             "is_type_structurally_recursive: {:?} {:?} - (cached) {:?}",
             ty, sp, representability
index b882a940d40c3609eb82ea6afb5f93296b0ca0ad..e44f80d5ac3f2e9b2ec5c18e6051886364e17cc8 100644 (file)
@@ -410,7 +410,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> {
 
     let self_ty = trait_ref.self_ty();
     let self_ty_matches = match self_ty.kind() {
-        ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(),
+        ty::Dynamic(ref data, re) if re.is_static() => data.principal().is_none(),
         _ => false,
     };
 
@@ -474,7 +474,7 @@ pub fn conservative_is_privately_uninhabited_raw<'tcx>(
                 Some(0) | None => false,
                 // If the array is definitely non-empty, it's uninhabited if
                 // the type of its elements is uninhabited.
-                Some(1..) => tcx.conservative_is_privately_uninhabited(param_env.and(ty)),
+                Some(1..) => tcx.conservative_is_privately_uninhabited(param_env.and(*ty)),
             }
         }
         ty::Ref(..) => {
index ec6fb622d32aa40c9f7d097115ed143fd1b609e3..e26f0033156bcb2e46358bd96e0931c709f228cc 100644 (file)
@@ -400,9 +400,11 @@ pub enum InferTy {
 /// they carry no values.
 impl UnifyKey for TyVid {
     type Value = ();
+    #[inline]
     fn index(&self) -> u32 {
         self.as_u32()
     }
+    #[inline]
     fn from_index(i: u32) -> TyVid {
         TyVid::from_u32(i)
     }
@@ -419,6 +421,7 @@ impl UnifyKey for IntVid {
     fn index(&self) -> u32 {
         self.index
     }
+    #[inline]
     fn from_index(i: u32) -> IntVid {
         IntVid { index: i }
     }
@@ -431,9 +434,11 @@ impl EqUnifyValue for FloatVarValue {}
 
 impl UnifyKey for FloatVid {
     type Value = Option<FloatVarValue>;
+    #[inline]
     fn index(&self) -> u32 {
         self.index
     }
+    #[inline]
     fn from_index(i: u32) -> FloatVid {
         FloatVid { index: i }
     }
index 3e2d7fc3820503b088f352a4229335e8e2910c1e..96f920499832784b0c7b0405ee9c574975da155f 100644 (file)
@@ -83,7 +83,7 @@ fn ct_infer(
         ty: Ty<'tcx>,
         param: Option<&ty::GenericParamDef>,
         span: Span,
-    ) -> &'tcx Const<'tcx>;
+    ) -> Const<'tcx>;
 
     /// Projecting an associated type from a (potentially)
     /// higher-ranked trait reference is more complicated, because of
@@ -887,15 +887,10 @@ fn trait_defines_associated_type_named(&self, trait_def_id: DefId, assoc_name: I
             .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
             .is_some()
     }
-    fn trait_defines_associated_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
+    fn trait_defines_associated_const_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
         self.tcx()
             .associated_items(trait_def_id)
-            .find_by_name_and_kinds(
-                self.tcx(),
-                assoc_name,
-                &[ty::AssocKind::Type, ty::AssocKind::Const],
-                trait_def_id,
-            )
+            .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Const, trait_def_id)
             .is_some()
     }
 
@@ -1145,13 +1140,13 @@ fn add_predicates_for_ast_type_binding(
 
         // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
         // of calling `filter_by_name_and_kind`.
-        let assoc_item = tcx
-            .associated_items(candidate.def_id())
-            .filter_by_name_unhygienic(assoc_ident.name)
-            .find(|i| {
-                (i.kind == ty::AssocKind::Type || i.kind == ty::AssocKind::Const)
-                    && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
-            })
+        let find_item_of_kind = |kind| {
+            tcx.associated_items(candidate.def_id())
+                .filter_by_name_unhygienic(assoc_ident.name)
+                .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident)
+        };
+        let assoc_item = find_item_of_kind(ty::AssocKind::Type)
+            .or_else(|| find_item_of_kind(ty::AssocKind::Const))
             .expect("missing associated type");
 
         if !assoc_item.vis.is_accessible_from(def_scope, tcx) {
@@ -1433,7 +1428,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
                         // `trait_object_dummy_self`, so check for that.
                         let references_self = match pred.skip_binder().term {
                             ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
-                            ty::Term::Const(c) => c.ty.walk().any(|arg| arg == dummy_self.into()),
+                            ty::Term::Const(c) => c.ty().walk().any(|arg| arg == dummy_self.into()),
                         };
 
                         // If the projection output contains `Self`, force the user to
@@ -1657,11 +1652,14 @@ fn one_bound_for_assoc_type<I>(
         I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
     {
         let mut matching_candidates = all_candidates()
-            .filter(|r| self.trait_defines_associated_named(r.def_id(), assoc_name));
-
-        let bound = match matching_candidates.next() {
-            Some(bound) => bound,
-            None => {
+            .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
+        let mut const_candidates = all_candidates()
+            .filter(|r| self.trait_defines_associated_const_named(r.def_id(), assoc_name));
+
+        let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) {
+            (Some(bound), _) => (bound, matching_candidates.next()),
+            (None, Some(bound)) => (bound, const_candidates.next()),
+            (None, None) => {
                 self.complain_about_assoc_type_not_found(
                     all_candidates,
                     &ty_param_name(),
@@ -1671,10 +1669,9 @@ fn one_bound_for_assoc_type<I>(
                 return Err(ErrorReported);
             }
         };
-
         debug!("one_bound_for_assoc_type: bound = {:?}", bound);
 
-        if let Some(bound2) = matching_candidates.next() {
+        if let Some(bound2) = next_cand {
             debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
 
             let is_equality = is_equality();
@@ -1759,6 +1756,7 @@ fn one_bound_for_assoc_type<I>(
                 return Err(ErrorReported);
             }
         }
+
         Ok(bound)
     }
 
@@ -1807,7 +1805,7 @@ pub fn associated_path_to_ty(
         // Find the type of the associated item, and the trait where the associated
         // item is declared.
         let bound = match (&qself_ty.kind(), qself_res) {
-            (_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => {
+            (_, Res::SelfTy { trait_: Some(_), alias_to: Some((impl_def_id, _)) }) => {
                 // `Self` in an impl of a trait -- we have a concrete self type and a
                 // trait reference.
                 let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
@@ -1828,7 +1826,8 @@ pub fn associated_path_to_ty(
             }
             (
                 &ty::Param(_),
-                Res::SelfTy(Some(param_did), None) | Res::Def(DefKind::TyParam, param_did),
+                Res::SelfTy { trait_: Some(param_did), alias_to: None }
+                | Res::Def(DefKind::TyParam, param_did),
             ) => self.find_bound_for_assoc_item(param_did.expect_local(), assoc_ident, span)?,
             _ => {
                 if variant_resolution.is_some() {
@@ -1893,14 +1892,17 @@ pub fn associated_path_to_ty(
 
         // We have already adjusted the item name above, so compare with `ident.normalize_to_macros_2_0()` instead
         // of calling `filter_by_name_and_kind`.
-        let item = tcx
-            .associated_items(trait_did)
-            .in_definition_order()
-            .find(|i| {
-                i.kind.namespace() == Namespace::TypeNS
-                    && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
-            })
-            .expect("missing associated type");
+        let item = tcx.associated_items(trait_did).in_definition_order().find(|i| {
+            i.kind.namespace() == Namespace::TypeNS
+                && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
+        });
+        // Assume that if it's not matched, there must be a const defined with the same name
+        // but it was used in a type position.
+        let Some(item) = item else {
+            let msg = format!("found associated const `{assoc_ident}` when type was expected");
+            tcx.sess.struct_span_err(span, &msg).emit();
+            return Err(ErrorReported);
+        };
 
         let ty = self.projected_ty_from_poly_trait_ref(span, item.def_id, assoc_segment, bound);
         let ty = self.normalize_ty(span, ty);
@@ -2269,19 +2271,38 @@ pub fn res_to_ty(
                 let index = generics.param_def_id_to_index[&def_id];
                 tcx.mk_ty_param(index, tcx.hir().name(hir_id))
             }
-            Res::SelfTy(Some(_), None) => {
+            Res::SelfTy { trait_: Some(_), alias_to: None } => {
                 // `Self` in trait or type alias.
                 assert_eq!(opt_self_ty, None);
                 self.prohibit_generics(path.segments);
                 tcx.types.self_param
             }
-            Res::SelfTy(_, Some((def_id, forbid_generic))) => {
+            Res::SelfTy { trait_: _, alias_to: Some((def_id, forbid_generic)) } => {
                 // `Self` in impl (we know the concrete type).
                 assert_eq!(opt_self_ty, None);
                 self.prohibit_generics(path.segments);
                 // Try to evaluate any array length constants.
-                let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id));
-                if forbid_generic && normalized_ty.needs_subst() {
+                let ty = tcx.at(span).type_of(def_id);
+                // HACK(min_const_generics): Forbid generic `Self` types
+                // here as we can't easily do that during nameres.
+                //
+                // We do this before normalization as we otherwise allow
+                // ```rust
+                // trait AlwaysApplicable { type Assoc; }
+                // impl<T: ?Sized> AlwaysApplicable for T { type Assoc = usize; }
+                //
+                // trait BindsParam<T> {
+                //     type ArrayTy;
+                // }
+                // impl<T> BindsParam<T> for <T as AlwaysApplicable>::Assoc {
+                //    type ArrayTy = [u8; Self::MAX];
+                // }
+                // ```
+                // Note that the normalization happens in the param env of
+                // the anon const, which is empty. This is why the
+                // `AlwaysApplicable` impl needs a `T: ?Sized` bound for
+                // this to compile if we were to normalize here.
+                if forbid_generic && ty.needs_subst() {
                     let mut err = tcx.sess.struct_span_err(
                         path.span,
                         "generic `Self` types are currently not permitted in anonymous constants",
@@ -2296,7 +2317,7 @@ pub fn res_to_ty(
                     err.emit();
                     tcx.ty_error()
                 } else {
-                    normalized_ty
+                    self.normalize_ty(span, ty)
                 }
             }
             Res::Def(DefKind::AssocTy, def_id) => {
@@ -2653,7 +2674,7 @@ fn compute_object_lifetime_bound(
 
         // If any of the derived region bounds are 'static, that is always
         // the best choice.
-        if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) {
+        if derived_region_bounds.iter().any(|r| r.is_static()) {
             return Some(tcx.lifetimes.re_static);
         }
 
index 405e4e8594a3ac60bd3d3210a49f57b73b35a4dc..3701b255b756bfe48be2cacad3b9cae6b5e7551b 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_hir::{self as hir, ExprKind};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::traits::Obligation;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyS};
+use rustc_middle::ty::{self, ToPredicate, Ty};
 use rustc_span::{MultiSpan, Span};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{
@@ -505,7 +505,7 @@ fn find_block_span(
     pub(crate) fn opt_suggest_box_span(
         &self,
         span: Span,
-        outer_ty: &'tcx TyS<'tcx>,
+        outer_ty: Ty<'tcx>,
         orig_expected: Expectation<'tcx>,
     ) -> Option<Span> {
         match (orig_expected, self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty))) {
index 0fea0afb572c9368f41cda8b8ccd6d1427c44b16..f64a90ed10e22a3ea2a8137967c3d855cdf6ecb6 100644 (file)
@@ -269,7 +269,7 @@ fn try_overloaded_call_traits(
                         },
                     };
                     autoref = Some(Adjustment {
-                        kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
+                        kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
                         target: method.sig.inputs()[0],
                     });
                 }
@@ -628,7 +628,7 @@ pub fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) {
                 for (method_arg_ty, self_arg_ty) in
                     iter::zip(method_sig.inputs().iter().skip(1), self.fn_sig.inputs())
                 {
-                    fcx.demand_eqtype(self.call_expr.span, &self_arg_ty, &method_arg_ty);
+                    fcx.demand_eqtype(self.call_expr.span, *self_arg_ty, *method_arg_ty);
                 }
 
                 fcx.demand_eqtype(self.call_expr.span, method_sig.output(), self.fn_sig.output());
index a397ee771af59c51c3cd51b2f9261f2d3f181c81..56b6c09069027bcba1dfaba683b554b6656f4e55 100644 (file)
@@ -328,16 +328,28 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                 err.emit();
             }
             CastError::CastToChar => {
-                type_error_struct!(
+                let mut err = type_error_struct!(
                     fcx.tcx.sess,
                     self.span,
                     self.expr_ty,
                     E0604,
                     "only `u8` can be cast as `char`, not `{}`",
                     self.expr_ty
-                )
-                .span_label(self.span, "invalid cast")
-                .emit();
+                );
+                err.span_label(self.span, "invalid cast");
+                if self.expr_ty.is_numeric() {
+                    err.span_help(
+                        self.span,
+                        if self.expr_ty == fcx.tcx.types.i8 {
+                            "try casting from `u8` instead"
+                        } else if self.expr_ty == fcx.tcx.types.u32 {
+                            "try `char::from_u32` instead"
+                        } else {
+                            "try `char::from_u32` instead (via a `u32`)"
+                        },
+                    );
+                }
+                err.emit();
             }
             CastError::NonScalar => {
                 let mut err = type_error_struct!(
@@ -357,7 +369,7 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                             .try_coerce(
                                 self.expr,
                                 fcx.tcx.mk_ref(
-                                    &ty::RegionKind::ReErased,
+                                    fcx.tcx.lifetimes.re_erased,
                                     TypeAndMut { ty: expr_ty, mutbl },
                                 ),
                                 self.cast_ty,
@@ -407,7 +419,7 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
                         .try_coerce(
                             self.expr,
                             fcx.tcx.mk_ref(
-                                &ty::RegionKind::ReErased,
+                                fcx.tcx.lifetimes.re_erased,
                                 TypeAndMut { ty: self.expr_ty, mutbl },
                             ),
                             self.cast_ty,
@@ -873,7 +885,7 @@ fn check_ref_cast(
                     });
 
                 // this will report a type mismatch if needed
-                fcx.demand_eqtype(self.span, ety, m_cast.ty);
+                fcx.demand_eqtype(self.span, *ety, m_cast.ty);
                 return Ok(CastKind::ArrayPtrCast);
             }
         }
index 18a0a8767d45bf786d6ace91f4db58fd06d12465..fba8292b46711dbc168513610687507de6690e2c 100644 (file)
@@ -17,7 +17,7 @@
 use rustc_middle::ty::layout::MAX_SIMD_LANES;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, RegionKind, Ty, TyCtxt};
+use rustc_middle::ty::{self, OpaqueTypeKey, ParamEnv, Ty, TyCtxt};
 use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS};
 use rustc_span::symbol::sym;
 use rustc_span::{self, MultiSpan, Span};
@@ -269,7 +269,7 @@ pub(super) fn check_fn<'a, 'tcx>(
                             ty::Adt(ref adt, _) => {
                                 adt.did == panic_info_did
                                     && mutbl == hir::Mutability::Not
-                                    && *region != RegionKind::ReStatic
+                                    && !region.is_static()
                             }
                             _ => false,
                         },
@@ -382,10 +382,15 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
                     tcx.sess,
                     field_span,
                     E0740,
-                    "unions may not contain fields that need dropping"
+                    "unions cannot contain fields that may need dropping"
+                )
+                .note(
+                    "a type is guaranteed not to need dropping \
+                    when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type",
                 )
                 .multipart_suggestion_verbose(
-                    "wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped",
+                    "when the type does not implement `Copy`, \
+                    wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped",
                     vec![
                         (ty_span.shrink_to_lo(), format!("std::mem::ManuallyDrop<")),
                         (ty_span.shrink_to_hi(), ">".into()),
@@ -469,8 +474,8 @@ impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
 
         fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             debug!("FindParentLifetimeVisitor: r={:?}", r);
-            if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r {
-                if *index < self.0.parent_count as u32 {
+            if let ty::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = *r {
+                if index < self.0.parent_count as u32 {
                     return ControlFlow::Break(FoundParentLifetime);
                 } else {
                     return ControlFlow::CONTINUE;
@@ -480,8 +485,8 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             r.super_visit_with(self)
         }
 
-        fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-            if let ty::ConstKind::Unevaluated(..) = c.val {
+        fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+            if let ty::ConstKind::Unevaluated(..) = c.val() {
                 // FIXME(#72219) We currently don't detect lifetimes within substs
                 // which would violate this check. Even though the particular substitution is not used
                 // within the const, this should still be fixed.
@@ -522,7 +527,12 @@ fn nested_visit_map(&mut self) -> Self::Map {
         fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
             match arg.kind {
                 hir::TyKind::Path(hir::QPath::Resolved(None, path)) => match &path.segments {
-                    [PathSegment { res: Some(Res::SelfTy(_, impl_ref)), .. }] => {
+                    [
+                        PathSegment {
+                            res: Some(Res::SelfTy { trait_: _, alias_to: impl_ref }),
+                            ..
+                        },
+                    ] => {
                         let impl_ty_name =
                             impl_ref.map(|(def_id, _)| self.tcx.def_path_str(def_id));
                         self.selftys.push((path.span, impl_ty_name));
index e88099afa03539ce855f6e40d2320a40c968677c..3c626837ef1a327b73cf74c2e7e31a27236932a5 100644 (file)
@@ -450,7 +450,7 @@ fn sig_of_closure_with_mismatched_number_of_arguments(
             .skip_binder()
             .inputs()
             .iter()
-            .map(|ty| ArgKind::from_expected_ty(ty, None))
+            .map(|ty| ArgKind::from_expected_ty(*ty, None))
             .collect();
         let (closure_span, found_args) = match self.get_fn_like_arguments(expr_map_node) {
             Some((sp, args)) => (Some(sp), args),
index 3668ecd234c64e1c8b216af4f6d07e653ba8038b..be7ac006926a9fc5201b24f41f59681b166c3949 100644 (file)
@@ -142,7 +142,7 @@ fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx>
     where
         F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
     {
-        self.unify(&a, &b)
+        self.unify(a, b)
             .and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations))
     }
 
@@ -472,7 +472,7 @@ fn coerce_borrowed_pointer(
             }
         };
         adjustments.push(Adjustment {
-            kind: Adjust::Borrow(AutoBorrow::Ref(r_borrow, mutbl)),
+            kind: Adjust::Borrow(AutoBorrow::Ref(*r_borrow, mutbl)),
             target: ty,
         });
 
index 74910234b7edcbe1215fbe6973a636acad8f00bc..38449c2a76a5be4a473d0922d226afd14cc22899 100644 (file)
@@ -377,9 +377,9 @@ fn compare_predicate_entailment<'tcx>(
                 &mut diag,
                 &cause,
                 trait_err_span.map(|sp| (sp, "type in trait".to_owned())),
-                Some(infer::ValuePairs::Types(ExpectedFound {
-                    expected: trait_fty,
-                    found: impl_fty,
+                Some(infer::ValuePairs::Terms(ExpectedFound {
+                    expected: trait_fty.into(),
+                    found: impl_fty.into(),
                 })),
                 &terr,
                 false,
@@ -1068,9 +1068,9 @@ fn compare_const_param_types<'tcx>(
                 &mut diag,
                 &cause,
                 trait_c_span.map(|span| (span, "type in trait".to_owned())),
-                Some(infer::ValuePairs::Types(ExpectedFound {
-                    expected: trait_ty,
-                    found: impl_ty,
+                Some(infer::ValuePairs::Terms(ExpectedFound {
+                    expected: trait_ty.into(),
+                    found: impl_ty.into(),
                 })),
                 &terr,
                 false,
@@ -1306,7 +1306,7 @@ pub fn check_type_bounds<'tcx>(
         GenericParamDefKind::Const { .. } => {
             let bound_var = ty::BoundVariableKind::Const;
             bound_vars.push(bound_var);
-            tcx.mk_const(ty::Const {
+            tcx.mk_const(ty::ConstS {
                 ty: tcx.type_of(param.def_id),
                 val: ty::ConstKind::Bound(
                     ty::INNERMOST,
@@ -1378,7 +1378,14 @@ pub fn check_type_bounds<'tcx>(
         let mut selcx = traits::SelectionContext::new(&infcx);
 
         let impl_ty_hir_id = tcx.hir().local_def_id_to_hir_id(impl_ty.def_id.expect_local());
-        let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id);
+        let normalize_cause = ObligationCause::new(
+            impl_ty_span,
+            impl_ty_hir_id,
+            ObligationCauseCode::CheckAssociatedTypeBounds {
+                impl_item_def_id: impl_ty.def_id,
+                trait_item_def_id: trait_ty.def_id,
+            },
+        );
         let mk_cause = |span: Span| {
             let code = if span.is_dummy() {
                 traits::MiscObligation
index 2409346298da98c4c0c85dfe15c138cb27ea2bfc..d0e96e7538cf046de0341566083cf4d57d90530e 100644 (file)
@@ -734,7 +734,7 @@ pub fn check_ref(
                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr),
                 _,
                 &ty::Ref(_, checked, _),
-            ) if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() => {
+            ) if self.infcx.can_sub(self.param_env, checked, expected).is_ok() => {
                 // We have `&T`, check if what was expected was `T`. If so,
                 // we may want to suggest removing a `&`.
                 if sm.is_imported(expr.span) {
index 89866c20b61d6ee1b17d0adc5aa3eefcb3ec95c2..22d2022902f01b5ee6747524be70e6e9af9fb10a 100644 (file)
@@ -362,9 +362,9 @@ fn regions(
 
     fn consts(
         &mut self,
-        a: &'tcx ty::Const<'tcx>,
-        b: &'tcx ty::Const<'tcx>,
-    ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> {
+        a: ty::Const<'tcx>,
+        b: ty::Const<'tcx>,
+    ) -> RelateResult<'tcx, ty::Const<'tcx>> {
         debug!("SimpleEqRelation::consts(a={:?}, b={:?})", a, b);
         ty::relate::super_relate_consts(self, a, b)
     }
index 82cda5a2f2e738fdee2b2c9c3571127c76b31e90..4869d193d8056863059ef02d0abf4309fa15676d 100644 (file)
@@ -421,9 +421,9 @@ fn check_expr_addr_of(
                         // Places may legitimately have unsized types.
                         // For example, dereferences of a fat pointer and
                         // the last field of a struct can be unsized.
-                        ExpectHasType(ty)
+                        ExpectHasType(*ty)
                     } else {
-                        Expectation::rvalue_hint(self, ty)
+                        Expectation::rvalue_hint(self, *ty)
                     }
                 }
                 _ => NoExpectation,
@@ -1318,10 +1318,7 @@ fn check_expr_struct(
         base_expr: &'tcx Option<&'tcx hir::Expr<'tcx>>,
     ) -> Ty<'tcx> {
         // Find the relevant variant
-        let (variant, adt_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, expr.hir_id)
-        {
-            variant_ty
-        } else {
+        let Some((variant, adt_ty)) = self.check_struct_path(qpath, expr.hir_id) else {
             self.check_struct_fields_on_error(fields, base_expr);
             return self.tcx.ty_error();
         };
@@ -1587,10 +1584,10 @@ fn report_missing_fields(
     ) {
         let len = remaining_fields.len();
 
-        let mut displayable_field_names =
-            remaining_fields.keys().map(|ident| ident.as_str()).collect::<Vec<_>>();
-
-        displayable_field_names.sort();
+        let mut displayable_field_names: Vec<&str> =
+            remaining_fields.keys().map(|ident| ident.as_str()).collect();
+        // sorting &str primitives here, sort_unstable is ok
+        displayable_field_names.sort_unstable();
 
         let mut truncated_fields_error = String::new();
         let remaining_fields_names = match &displayable_field_names[..] {
@@ -2181,7 +2178,7 @@ fn maybe_suggest_array_indexing(
         expr: &hir::Expr<'_>,
         base: &hir::Expr<'_>,
         field: Ident,
-        len: &ty::Const<'tcx>,
+        len: ty::Const<'tcx>,
     ) {
         if let (Some(len), Ok(user_index)) =
             (len.try_eval_usize(self.tcx, self.param_env), field.as_str().parse::<u64>())
@@ -2216,7 +2213,7 @@ fn suggest_first_deref_field(
     fn no_such_field_err(
         &self,
         field: Ident,
-        expr_t: &'tcx ty::TyS<'tcx>,
+        expr_t: Ty<'tcx>,
         id: HirId,
     ) -> DiagnosticBuilder<'_> {
         let span = field.span;
@@ -2233,7 +2230,7 @@ fn no_such_field_err(
         );
 
         // try to add a suggestion in case the field is a nested field of a field of the Adt
-        if let Some((fields, substs)) = self.get_field_candidates(span, &expr_t) {
+        if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) {
             for candidate_field in fields.iter() {
                 if let Some(field_path) = self.check_for_nested_field(
                     span,
@@ -2312,7 +2309,7 @@ fn check_for_nested_field(
 
             field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
             let field_ty = candidate_field.ty(self.tcx, subst);
-            if let Some((nested_fields, subst)) = self.get_field_candidates(span, &field_ty) {
+            if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) {
                 for field in nested_fields.iter() {
                     let accessible = field.vis.is_accessible_from(id, self.tcx);
                     if accessible {
@@ -2449,7 +2446,7 @@ fn check_expr_asm_operand(&self, expr: &'tcx hir::Expr<'tcx>, is_input: bool) {
         // allows them to be inferred based on how they are used later in the
         // function.
         if is_input {
-            let ty = self.structurally_resolved_type(expr.span, &ty);
+            let ty = self.structurally_resolved_type(expr.span, ty);
             match *ty.kind() {
                 ty::FnDef(..) => {
                     let fnptr_ty = self.tcx.mk_fn_ptr(ty.fn_sig(self.tcx));
index e5da33d113e7c48e95ab6e626d4e0dc8ff0711f8..7214cdf3312a78998c9374b15ae800f7cc6ca265 100644 (file)
@@ -70,7 +70,7 @@ pub(super) fn type_inference_fallback(&self) -> bool {
         // unconstrained opaque type variables, in addition to performing
         // other kinds of fallback.
         for ty in &self.unsolved_variables() {
-            fallback_has_occurred |= self.fallback_opaque_type_vars(ty);
+            fallback_has_occurred |= self.fallback_opaque_type_vars(*ty);
         }
 
         // See if we can make any more progress.
@@ -176,7 +176,7 @@ fn fallback_opaque_type_vars(&self, ty: Ty<'tcx>) -> bool {
             .type_var_origin(ty)
             .map(|origin| origin.span)
             .unwrap_or(rustc_span::DUMMY_SP);
-        let oty = self.inner.borrow().opaque_types_vars.get(ty).copied();
+        let oty = self.inner.borrow().opaque_types_vars.get(&ty).copied();
         if let Some(opaque_ty) = oty {
             debug!(
                 "fallback_opaque_type_vars(ty={:?}): falling back to opaque type {:?}",
index 0f9803b969fb74521feef9aefcbfe1b950845721..96bbc2800d50a212d833827a13b32568146891a2 100644 (file)
@@ -498,14 +498,14 @@ pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
         ty
     }
 
-    pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> &'tcx ty::Const<'tcx> {
+    pub fn array_length_to_const(&self, length: &hir::ArrayLen) -> ty::Const<'tcx> {
         match length {
             &hir::ArrayLen::Infer(_, span) => self.ct_infer(self.tcx.types.usize, None, span),
             hir::ArrayLen::Body(anon_const) => self.to_const(anon_const),
         }
     }
 
-    pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> {
+    pub fn to_const(&self, ast_c: &hir::AnonConst) -> ty::Const<'tcx> {
         let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id);
         let c = ty::Const::from_anon_const(self.tcx, const_def_id);
         self.register_wf_obligation(
@@ -520,7 +520,7 @@ pub fn const_arg_to_const(
         &self,
         ast_c: &hir::AnonConst,
         param_def_id: DefId,
-    ) -> &'tcx ty::Const<'tcx> {
+    ) -> ty::Const<'tcx> {
         let const_def = ty::WithOptConstParam {
             did: self.tcx.hir().local_def_id(ast_c.hir_id),
             const_param_did: Some(param_def_id),
@@ -605,7 +605,7 @@ pub fn field_ty(
         field: &'tcx ty::FieldDef,
         substs: SubstsRef<'tcx>,
     ) -> Ty<'tcx> {
-        self.normalize_associated_types_in(span, &field.ty(self.tcx, substs))
+        self.normalize_associated_types_in(span, field.ty(self.tcx, substs))
     }
 
     pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
@@ -756,7 +756,7 @@ pub(in super::super) fn expected_inputs_for_expected_output(
                 // is polymorphic) and the expected return type.
                 // No argument expectations are produced if unification fails.
                 let origin = self.misc(call_span);
-                let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret);
+                let ures = self.at(&origin, self.param_env).sup(ret_ty, formal_ret);
 
                 // FIXME(#27336) can't use ? here, Try::from_error doesn't default
                 // to identity so the resulting type is not constrained.
index 1b93017c5aa47da19c12768a35acc8543491debe..d05dd517f1ea32ab68d9737805309b5680d9dbcc 100644 (file)
@@ -578,7 +578,7 @@ pub fn check_struct_path(
                 _ => bug!("unexpected type: {:?}", ty),
             },
             Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
-            | Res::SelfTy(..) => match ty.kind() {
+            | Res::SelfTy { .. } => match ty.kind() {
                 ty::Adt(adt, substs) if !adt.is_enum() => {
                     Some((adt.non_enum_variant(), adt.did, substs))
                 }
index 3a81af03162862f8c8d99024fd92681fd8cb7acb..222c14d0d47b9ef244ead29af396dff2a667064a 100644 (file)
@@ -239,7 +239,7 @@ fn ct_infer(
         ty: Ty<'tcx>,
         param: Option<&ty::GenericParamDef>,
         span: Span,
-    ) -> &'tcx Const<'tcx> {
+    ) -> Const<'tcx> {
         if let Some(param) = param {
             if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
                 return ct;
@@ -282,7 +282,7 @@ 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_associated_types_in(span, &ty)
+            self.normalize_associated_types_in(span, ty)
         }
     }
 
index e30871e4347c14f99ecacc2f3b11bd9ded5878df..576dc6f127cbda11e8674189937c4824c5c72fc9 100644 (file)
@@ -92,7 +92,7 @@ fn declare(&mut self, decl: Declaration<'tcx>) {
         debug!(
             "local variable {:?} is assigned type {}",
             decl.pat,
-            self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&decl.hir_id).unwrap().decl_ty)
+            self.fcx.ty_to_string(self.fcx.locals.borrow().get(&decl.hir_id).unwrap().decl_ty)
         );
     }
 }
@@ -137,7 +137,7 @@ fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) {
             debug!(
                 "pattern binding {} is assigned to {} with type {:?}",
                 ident,
-                self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
+                self.fcx.ty_to_string(self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty),
                 var_ty
             );
         }
index c6b92db88ae8a933529f7ca4fdf00ca4ace77ec6..d360f34ae709c53e79cae9d75271b8ed07056c38 100644 (file)
 
 mod drop_ranges;
 
-// FIXME(eholk): This flag is here to give a quick way to disable drop tracking in case we find
-// unexpected breakages while it's still new. It should be removed before too long. For example,
-// see #93161.
-const ENABLE_DROP_TRACKING: bool = false;
-
 struct InteriorVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
@@ -82,7 +77,7 @@ fn record(
                                 yield_data.expr_and_pat_count, self.expr_count, source_span
                             );
 
-                            if ENABLE_DROP_TRACKING
+                            if self.fcx.sess().opts.debugging_opts.drop_tracking
                                 && self
                                     .drop_ranges
                                     .is_dropped_at(hir_id, yield_data.expr_and_pat_count)
@@ -160,7 +155,7 @@ fn record(
 
                 self.types.insert(ty::GeneratorInteriorTypeCause {
                     span: source_span,
-                    ty: &ty,
+                    ty,
                     scope_span,
                     yield_span: yield_data.span,
                     expr: expr.map(|e| e.hir_id),
@@ -208,7 +203,7 @@ pub fn resolve_interior<'a, 'tcx>(
     };
     intravisit::walk_body(&mut visitor, body);
 
-    // Check that we visited the same amount of expressions and the RegionResolutionVisitor
+    // Check that we visited the same amount of expressions as the RegionResolutionVisitor
     let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
     assert_eq!(region_expr_count, visitor.expr_count);
 
@@ -421,7 +416,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
                 let tcx = self.fcx.tcx;
                 let ref_ty = tcx.mk_ref(
                     // Use `ReErased` as `resolve_interior` is going to replace all the regions anyway.
-                    tcx.mk_region(ty::RegionKind::ReErased),
+                    tcx.mk_region(ty::ReErased),
                     ty::TypeAndMut { ty, mutbl: hir::Mutability::Not },
                 );
                 self.record(
index 4b8f01e3535bde8cb7516385fb14c55629fac60a..c4e7d6a199e83d0659d428435156e449968a898a 100644 (file)
@@ -37,7 +37,7 @@ pub fn compute_drop_ranges<'a, 'tcx>(
     def_id: DefId,
     body: &'tcx Body<'tcx>,
 ) -> DropRanges {
-    if super::ENABLE_DROP_TRACKING {
+    if fcx.sess().opts.debugging_opts.drop_tracking {
         let consumed_borrowed_places = find_consumed_and_borrowed(fcx, def_id, body);
 
         let num_exprs = fcx.tcx.region_scope_tree(def_id).body_expr_count(body.id()).unwrap_or(0);
@@ -116,6 +116,18 @@ fn hir_id(&self) -> HirId {
             TrackedValue::Variable(hir_id) | TrackedValue::Temporary(hir_id) => *hir_id,
         }
     }
+
+    fn from_place_with_projections_allowed(place_with_id: &PlaceWithHirId<'_>) -> Self {
+        match place_with_id.place.base {
+            PlaceBase::Rvalue | PlaceBase::StaticItem => {
+                TrackedValue::Temporary(place_with_id.hir_id)
+            }
+            PlaceBase::Local(hir_id)
+            | PlaceBase::Upvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id }, .. }) => {
+                TrackedValue::Variable(hir_id)
+            }
+        }
+    }
 }
 
 /// Represents a reason why we might not be able to convert a HirId or Place
@@ -142,15 +154,7 @@ fn try_from(place_with_id: &PlaceWithHirId<'_>) -> Result<Self, Self::Error> {
             return Err(TrackedValueConversionError::PlaceProjectionsNotSupported);
         }
 
-        match place_with_id.place.base {
-            PlaceBase::Rvalue | PlaceBase::StaticItem => {
-                Ok(TrackedValue::Temporary(place_with_id.hir_id))
-            }
-            PlaceBase::Local(hir_id)
-            | PlaceBase::Upvar(ty::UpvarId { var_path: ty::UpvarPath { hir_id }, .. }) => {
-                Ok(TrackedValue::Variable(hir_id))
-            }
-        }
+        Ok(TrackedValue::from_place_with_projections_allowed(place_with_id))
     }
 }
 
index d7d52ab823cee0f54d689dfd61c8c7e70a1f599a..e2a4d9c1b3af7075aa70dbaed456eade45ed6e31 100644 (file)
@@ -4,7 +4,7 @@
 };
 use hir::{
     intravisit::{self, Visitor},
-    Body, Expr, ExprKind, Guard, HirId,
+    Body, Expr, ExprKind, Guard, HirId, LoopIdError,
 };
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
@@ -85,6 +85,7 @@ struct DropRangeVisitor<'a, 'tcx> {
     expr_index: PostOrderId,
     tcx: TyCtxt<'tcx>,
     typeck_results: &'a TypeckResults<'tcx>,
+    label_stack: Vec<(Option<rustc_ast::Label>, PostOrderId)>,
 }
 
 impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
@@ -101,7 +102,15 @@ fn new(
             hir,
             num_exprs,
         );
-        Self { hir, places, drop_ranges, expr_index: PostOrderId::from_u32(0), typeck_results, tcx }
+        Self {
+            hir,
+            places,
+            drop_ranges,
+            expr_index: PostOrderId::from_u32(0),
+            typeck_results,
+            tcx,
+            label_stack: vec![],
+        }
     }
 
     fn record_drop(&mut self, value: TrackedValue) {
@@ -209,6 +218,60 @@ fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
             self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
         }
     }
+
+    /// Map a Destination to an equivalent expression node
+    ///
+    /// The destination field of a Break or Continue expression can target either an
+    /// expression or a block. The drop range analysis, however, only deals in
+    /// expression nodes, so blocks that might be the destination of a Break or Continue
+    /// will not have a PostOrderId.
+    ///
+    /// If the destination is an expression, this function will simply return that expression's
+    /// hir_id. If the destination is a block, this function will return the hir_id of last
+    /// expression in the block.
+    fn find_target_expression_from_destination(
+        &self,
+        destination: hir::Destination,
+    ) -> Result<HirId, LoopIdError> {
+        destination.target_id.map(|target| {
+            let node = self.hir.get(target);
+            match node {
+                hir::Node::Expr(_) => target,
+                hir::Node::Block(b) => find_last_block_expression(b),
+                hir::Node::Param(..)
+                | hir::Node::Item(..)
+                | hir::Node::ForeignItem(..)
+                | hir::Node::TraitItem(..)
+                | hir::Node::ImplItem(..)
+                | hir::Node::Variant(..)
+                | hir::Node::Field(..)
+                | hir::Node::AnonConst(..)
+                | hir::Node::Stmt(..)
+                | hir::Node::PathSegment(..)
+                | hir::Node::Ty(..)
+                | hir::Node::TraitRef(..)
+                | hir::Node::Binding(..)
+                | hir::Node::Pat(..)
+                | hir::Node::Arm(..)
+                | hir::Node::Local(..)
+                | hir::Node::Ctor(..)
+                | hir::Node::Lifetime(..)
+                | hir::Node::GenericParam(..)
+                | hir::Node::Visibility(..)
+                | hir::Node::Crate(..)
+                | hir::Node::Infer(..) => bug!("Unsupported branch target: {:?}", node),
+            }
+        })
+    }
+}
+
+fn find_last_block_expression(block: &hir::Block<'_>) -> HirId {
+    block.expr.map_or_else(
+        // If there is no tail expression, there will be at least one statement in the
+        // block because the block contains a break or continue statement.
+        || block.stmts.last().unwrap().hir_id,
+        |expr| expr.hir_id,
+    )
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
@@ -320,8 +383,9 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
                 });
             }
 
-            ExprKind::Loop(body, ..) => {
+            ExprKind::Loop(body, label, ..) => {
                 let loop_begin = self.expr_index + 1;
+                self.label_stack.push((label, loop_begin));
                 if body.stmts.is_empty() && body.expr.is_none() {
                     // For empty loops we won't have updated self.expr_index after visiting the
                     // body, meaning we'd get an edge from expr_index to expr_index + 1, but
@@ -331,10 +395,31 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
                     self.visit_block(body);
                     self.drop_ranges.add_control_edge(self.expr_index, loop_begin);
                 }
+                self.label_stack.pop();
             }
-            ExprKind::Break(hir::Destination { target_id: Ok(target), .. }, ..)
-            | ExprKind::Continue(hir::Destination { target_id: Ok(target), .. }, ..) => {
-                self.drop_ranges.add_control_edge_hir_id(self.expr_index, target);
+            // Find the loop entry by searching through the label stack for either the last entry
+            // (if label is none), or the first entry where the label matches this one. The Loop
+            // case maintains this stack mapping labels to the PostOrderId for the loop entry.
+            ExprKind::Continue(hir::Destination { label, .. }, ..) => self
+                .label_stack
+                .iter()
+                .rev()
+                .find(|(loop_label, _)| label.is_none() || *loop_label == label)
+                .map_or((), |(_, target)| {
+                    self.drop_ranges.add_control_edge(self.expr_index, *target)
+                }),
+
+            ExprKind::Break(destination, ..) => {
+                // destination either points to an expression or to a block. We use
+                // find_target_expression_from_destination to use the last expression of the block
+                // if destination points to a block.
+                //
+                // We add an edge to the hir_id of the expression/block we are breaking out of, and
+                // then in process_deferred_edges we will map this hir_id to its PostOrderId, which
+                // will refer to the end of the block due to the post order traversal.
+                self.find_target_expression_from_destination(destination).map_or((), |target| {
+                    self.drop_ranges.add_control_edge_hir_id(self.expr_index, target)
+                })
             }
 
             ExprKind::Call(f, args) => {
@@ -359,11 +444,9 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
             | ExprKind::Binary(..)
             | ExprKind::Block(..)
             | ExprKind::Box(..)
-            | ExprKind::Break(..)
             | ExprKind::Cast(..)
             | ExprKind::Closure(..)
             | ExprKind::ConstBlock(..)
-            | ExprKind::Continue(..)
             | ExprKind::DropTemps(..)
             | ExprKind::Err
             | ExprKind::Field(..)
@@ -462,11 +545,13 @@ fn reinit_at(&mut self, value: TrackedValue, location: PostOrderId) {
     /// Should be called after visiting the HIR but before solving the control flow, otherwise some
     /// edges will be missed.
     fn process_deferred_edges(&mut self) {
+        trace!("processing deferred edges. post_order_map={:#?}", self.post_order_map);
         let mut edges = vec![];
         swap(&mut edges, &mut self.deferred_edges);
         edges.into_iter().for_each(|(from, to)| {
-            let to = *self.post_order_map.get(&to).expect("Expression ID not found");
             trace!("Adding deferred edge from {:?} to {:?}", from, to);
+            let to = *self.post_order_map.get(&to).expect("Expression ID not found");
+            trace!("target edge PostOrderId={:?}", to);
             self.add_control_edge(from, to)
         });
     }
index 059a135a6fb6517018424292aa9ee3858e2614c8..9a308586afff3a723ef738794aac89547a8f2e52 100644 (file)
@@ -96,9 +96,9 @@ fn borrow(
         _diag_expr_id: HirId,
         _bk: rustc_middle::ty::BorrowKind,
     ) {
-        place_with_id
-            .try_into()
-            .map_or(false, |tracked_value| self.places.borrowed.insert(tracked_value));
+        self.places
+            .borrowed
+            .insert(TrackedValue::from_place_with_projections_allowed(place_with_id));
     }
 
     fn mutate(
index 27c39934ba8e9f66448ff6a3e81adc075e149dff..fdc3ba17e3ccf4284e4727e3a2e8b3f4b477a74b 100644 (file)
@@ -185,7 +185,7 @@ fn adjust_self_ty(
 
                 if unsize {
                     let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
-                        self.tcx.mk_slice(elem_ty)
+                        self.tcx.mk_slice(*elem_ty)
                     } else {
                         bug!(
                             "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
@@ -201,8 +201,8 @@ fn adjust_self_ty(
             }
             Some(probe::AutorefOrPtrAdjustment::ToConstPtr) => {
                 target = match target.kind() {
-                    ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
-                        assert_eq!(*mutbl, hir::Mutability::Mut);
+                    &ty::RawPtr(ty::TypeAndMut { ty, mutbl }) => {
+                        assert_eq!(mutbl, hir::Mutability::Mut);
                         self.tcx.mk_ptr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty })
                     }
                     other => panic!("Cannot adjust receiver type {:?} to const ptr", other),
index d2dc21d84f6f112e125f90b301b7e803508c4934..e5ef52e0324e795b76ef40b9f1db3913a23a18e2 100644 (file)
@@ -227,7 +227,7 @@ pub fn lookup_method(
             if let ty::Ref(region, t_type, mutability) = self_ty.kind() {
                 let trait_type = self
                     .tcx
-                    .mk_ref(region, ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() });
+                    .mk_ref(*region, ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() });
                 // We probe again to see if there might be a borrow mutability discrepancy.
                 match self.lookup_probe(
                     span,
index 3815fd1992bf318b6806873052bfc84a554df097..c429e0f165370227d3b1dd2d3ace973b91757bc3 100644 (file)
@@ -9,7 +9,6 @@
 use crate::hir::def_id::DefId;
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::Namespace;
@@ -59,7 +58,7 @@ struct ProbeContext<'a, 'tcx> {
     /// This is the OriginalQueryValues for the steps queries
     /// that are answered in steps.
     orig_steps_var_values: OriginalQueryValues<'tcx>,
-    steps: Lrc<Vec<CandidateStep<'tcx>>>,
+    steps: &'tcx [CandidateStep<'tcx>],
 
     inherent_candidates: Vec<Candidate<'tcx>>,
     extension_candidates: Vec<Candidate<'tcx>>,
@@ -364,7 +363,7 @@ fn probe_op<OP, R>(
                     param_env_and_self_ty, self_ty
                 );
                 MethodAutoderefStepsResult {
-                    steps: Lrc::new(vec![CandidateStep {
+                    steps: infcx.tcx.arena.alloc_from_iter([CandidateStep {
                         self_ty: self.make_query_response_ignoring_pending_obligations(
                             canonical_inference_vars,
                             self_ty,
@@ -516,7 +515,7 @@ fn method_autoderef_steps<'tcx>(
                 steps.push(CandidateStep {
                     self_ty: infcx.make_query_response_ignoring_pending_obligations(
                         inference_vars,
-                        infcx.tcx.mk_slice(elem_ty),
+                        infcx.tcx.mk_slice(*elem_ty),
                     ),
                     autoderefs: dereferences,
                     // this could be from an unsafe deref if we had
@@ -533,8 +532,8 @@ fn method_autoderef_steps<'tcx>(
         debug!("method_autoderef_steps: steps={:?} opt_bad_ty={:?}", steps, opt_bad_ty);
 
         MethodAutoderefStepsResult {
-            steps: Lrc::new(steps),
-            opt_bad_ty: opt_bad_ty.map(Lrc::new),
+            steps: tcx.arena.alloc_from_iter(steps),
+            opt_bad_ty: opt_bad_ty.map(|ty| &*tcx.arena.alloc(ty)),
             reached_recursion_limit: autoderef.reached_recursion_limit(),
         }
     })
@@ -548,7 +547,7 @@ fn new(
         method_name: Option<Ident>,
         return_type: Option<Ty<'tcx>>,
         orig_steps_var_values: OriginalQueryValues<'tcx>,
-        steps: Lrc<Vec<CandidateStep<'tcx>>>,
+        steps: &'tcx [CandidateStep<'tcx>],
         is_suggestion: IsSuggestion,
         scope_expr_id: hir::HirId,
     ) -> ProbeContext<'a, 'tcx> {
@@ -605,8 +604,7 @@ fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool) {
     }
 
     fn assemble_inherent_candidates(&mut self) {
-        let steps = Lrc::clone(&self.steps);
-        for step in steps.iter() {
+        for step in self.steps.iter() {
             self.assemble_probe(&step.self_ty);
         }
     }
@@ -1249,7 +1247,7 @@ fn pick_const_ptr_method(
         }
 
         let ty = match self_ty.kind() {
-            ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }) => ty,
+            &ty::RawPtr(ty::TypeAndMut { ty, mutbl: hir::Mutability::Mut }) => ty,
             _ => return None,
         };
 
index 58ea197d3e94041c7b6157a24c1e2d4d6c013cb9..a523ba286ec8401746cc25ec29546cb85965a4ac 100644 (file)
@@ -9,8 +9,10 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, Node, QPath};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams, StripReferences};
+use rustc_middle::traits::util::supertraits;
+use rustc_middle::ty::fast_reject::{simplify_type, SimplifyParams};
 use rustc_middle::ty::print::with_crate_prefix;
+use rustc_middle::ty::ToPolyTraitRef;
 use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
@@ -40,7 +42,19 @@ fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
                     Err(..) => return false,
                 };
 
+                // This conditional prevents us from asking to call errors and unresolved types.
+                // It might seem that we can use `predicate_must_hold_modulo_regions`,
+                // but since a Dummy binder is used to fill in the FnOnce trait's arguments,
+                // type resolution always gives a "maybe" here.
+                if self.autoderef(span, ty).any(|(ty, _)| {
+                    info!("check deref {:?} error", ty);
+                    matches!(ty.kind(), ty::Error(_) | ty::Infer(_))
+                }) {
+                    return false;
+                }
+
                 self.autoderef(span, ty).any(|(ty, _)| {
+                    info!("check deref {:?} impl FnOnce", ty);
                     self.probe(|_| {
                         let fn_once_substs = tcx.mk_substs_trait(
                             ty,
@@ -703,7 +717,7 @@ fn report_function<T: std::fmt::Display>(
                     let mut bound_spans = vec![];
 
                     let mut collect_type_param_suggestions =
-                        |self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| {
+                        |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::Trait(p)) =
                                 (self_ty.kind(), parent_pred.kind().skip_binder())
@@ -892,7 +906,7 @@ fn report_function<T: std::fmt::Display>(
                         .filter(|(pred, _, _parent_pred)| !skip_list.contains(&pred))
                         .filter_map(|(pred, parent_pred, _cause)| {
                             format_pred(*pred).map(|(p, self_ty)| {
-                                collect_type_param_suggestions(self_ty, pred, &p);
+                                collect_type_param_suggestions(self_ty, *pred, &p);
                                 match parent_pred {
                                     None => format!("`{}`", &p),
                                     Some(parent_pred) => match format_pred(*parent_pred) {
@@ -900,7 +914,7 @@ fn report_function<T: std::fmt::Display>(
                                         Some((parent_p, _)) => {
                                             collect_type_param_suggestions(
                                                 self_ty,
-                                                parent_pred,
+                                                *parent_pred,
                                                 &p,
                                             );
                                             format!("`{}`\nwhich is required by `{}`", p, parent_p)
@@ -1086,8 +1100,8 @@ trait bound{s}",
                 if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() {
                     if needs_mut {
                         let trait_type = self.tcx.mk_ref(
-                            region,
-                            ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() },
+                            *region,
+                            ty::TypeAndMut { ty: *t_type, mutbl: mutability.invert() },
                         );
                         err.note(&format!("you need `{}` instead of `{}`", trait_type, rcvr_ty));
                     }
@@ -1196,9 +1210,9 @@ fn suggest_derive(
                 Some(adt) if adt.did.is_local() => adt,
                 _ => continue,
             };
-            let can_derive = match self.tcx.get_diagnostic_name(trait_pred.def_id()) {
-                Some(sym::Default) => !adt.is_enum(),
-                Some(
+            if let Some(diagnostic_name) = self.tcx.get_diagnostic_name(trait_pred.def_id()) {
+                let can_derive = match diagnostic_name {
+                    sym::Default => !adt.is_enum(),
                     sym::Eq
                     | sym::PartialEq
                     | sym::Ord
@@ -1206,16 +1220,30 @@ fn suggest_derive(
                     | sym::Clone
                     | sym::Copy
                     | sym::Hash
-                    | sym::Debug,
-                ) => true,
-                _ => false,
-            };
-            if can_derive {
-                derives.push((
-                    format!("{}", trait_pred.self_ty()),
-                    self.tcx.def_span(adt.did),
-                    format!("{}", trait_pred.trait_ref.print_only_trait_name()),
-                ));
+                    | sym::Debug => true,
+                    _ => false,
+                };
+                if can_derive {
+                    let self_name = trait_pred.self_ty().to_string();
+                    let self_span = self.tcx.def_span(adt.did);
+                    if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() {
+                        for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref())
+                        {
+                            if let Some(parent_diagnostic_name) =
+                                self.tcx.get_diagnostic_name(super_trait.def_id())
+                            {
+                                derives.push((
+                                    self_name.clone(),
+                                    self_span.clone(),
+                                    parent_diagnostic_name.to_string(),
+                                ));
+                            }
+                        }
+                    }
+                    derives.push((self_name, self_span, diagnostic_name.to_string()));
+                } else {
+                    traits.push(self.tcx.def_span(trait_pred.def_id()));
+                }
             } else {
                 traits.push(self.tcx.def_span(trait_pred.def_id()));
             }
@@ -1462,13 +1490,13 @@ fn suggest_traits_to_import(
             // just this list.
             for (rcvr_ty, post) in &[
                 (rcvr_ty, ""),
-                (self.tcx.mk_mut_ref(&ty::ReErased, rcvr_ty), "&mut "),
-                (self.tcx.mk_imm_ref(&ty::ReErased, rcvr_ty), "&"),
+                (self.tcx.mk_mut_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&mut "),
+                (self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, rcvr_ty), "&"),
             ] {
                 if let Ok(pick) = self.lookup_probe(
                     span,
                     item_name,
-                    rcvr_ty,
+                    *rcvr_ty,
                     rcvr,
                     crate::check::method::probe::ProbeScope::AllTraits,
                 ) {
@@ -1487,10 +1515,10 @@ fn suggest_traits_to_import(
                     break;
                 }
                 for (rcvr_ty, pre) in &[
-                    (self.tcx.mk_lang_item(rcvr_ty, LangItem::OwnedBox), "Box::new"),
-                    (self.tcx.mk_lang_item(rcvr_ty, LangItem::Pin), "Pin::new"),
-                    (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Arc), "Arc::new"),
-                    (self.tcx.mk_diagnostic_item(rcvr_ty, sym::Rc), "Rc::new"),
+                    (self.tcx.mk_lang_item(*rcvr_ty, LangItem::OwnedBox), "Box::new"),
+                    (self.tcx.mk_lang_item(*rcvr_ty, LangItem::Pin), "Pin::new"),
+                    (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"),
+                    (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"),
                 ] {
                     if let Some(new_rcvr_t) = *rcvr_ty {
                         if let Ok(pick) = self.lookup_probe(
@@ -1663,7 +1691,7 @@ fn suggest_traits_to_import(
                 let table_owner = table.borrow().hir_owner;
                 let generics = self.tcx.generics_of(table_owner.to_def_id());
                 let type_param = generics.type_param(param, self.tcx);
-                let hir = &self.tcx.hir();
+                let hir = self.tcx.hir();
                 if let Some(def_id) = type_param.def_id.as_local() {
                     let id = hir.local_def_id_to_hir_id(def_id);
                     // Get the `hir::Param` to verify whether it already has any bounds.
@@ -1748,8 +1776,7 @@ fn suggest_traits_to_import(
                 // FIXME: Even though negative bounds are not implemented, we could maybe handle
                 // cases where a positive bound implies a negative impl.
                 (candidates, Vec::new())
-            } else if let Some(simp_rcvr_ty) =
-                simplify_type(self.tcx, rcvr_ty, SimplifyParams::Yes, StripReferences::No)
+            } else if let Some(simp_rcvr_ty) = simplify_type(self.tcx, rcvr_ty, SimplifyParams::Yes)
             {
                 let mut potential_candidates = Vec::new();
                 let mut explicitly_negative = Vec::new();
@@ -1763,12 +1790,8 @@ fn suggest_traits_to_import(
                         })
                         .any(|imp_did| {
                             let imp = self.tcx.impl_trait_ref(imp_did).unwrap();
-                            let imp_simp = simplify_type(
-                                self.tcx,
-                                imp.self_ty(),
-                                SimplifyParams::Yes,
-                                StripReferences::No,
-                            );
+                            let imp_simp =
+                                simplify_type(self.tcx, imp.self_ty(), SimplifyParams::Yes);
                             imp_simp.map_or(false, |s| s == simp_rcvr_ty)
                         })
                     {
@@ -1819,7 +1842,7 @@ fn suggest_traits_to_import(
                 [] => {}
                 [trait_info] => {
                     let msg = format!(
-                        "the trait `{}` defines an item `{}`, but is explicitely unimplemented",
+                        "the trait `{}` defines an item `{}`, but is explicitly unimplemented",
                         self.tcx.def_path_str(trait_info.def_id),
                         item_name
                     );
@@ -1827,7 +1850,7 @@ fn suggest_traits_to_import(
                 }
                 trait_infos => {
                     let mut msg = format!(
-                        "the following traits define an item `{}`, but are explicitely unimplemented:",
+                        "the following traits define an item `{}`, but are explicitly unimplemented:",
                         item_name
                     );
                     for trait_info in trait_infos {
index 74516acbfcff34187cf5dba5acf3ae0175d181e0..dd49d6f489259695639bba5fd8c08a64dbc899f8 100644 (file)
@@ -221,7 +221,7 @@ fn check_overloaded_binop(
                             },
                         };
                         let autoref = Adjustment {
-                            kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
+                            kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
                             target: method.sig.inputs()[0],
                         };
                         self.apply_adjustments(lhs_expr, vec![autoref]);
@@ -238,7 +238,7 @@ fn check_overloaded_binop(
                             },
                         };
                         let autoref = Adjustment {
-                            kind: Adjust::Borrow(AutoBorrow::Ref(region, mutbl)),
+                            kind: Adjust::Borrow(AutoBorrow::Ref(*region, mutbl)),
                             target: method.sig.inputs()[1],
                         };
                         // HACK(eddyb) Bypass checks due to reborrows being in
@@ -399,8 +399,8 @@ fn check_overloaded_binop(
                     }
                 };
                 if let Ref(_, rty, _) = lhs_ty.kind() {
-                    if self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span)
-                        && self.lookup_op_method(rty, &[rhs_ty], Op::Binary(op, is_assign)).is_ok()
+                    if self.infcx.type_is_copy_modulo_regions(self.param_env, *rty, lhs_expr.span)
+                        && self.lookup_op_method(*rty, &[rhs_ty], Op::Binary(op, is_assign)).is_ok()
                     {
                         if let Ok(lstring) = source_map.span_to_snippet(lhs_expr.span) {
                             let msg = &format!(
@@ -452,7 +452,7 @@ fn check_overloaded_binop(
                                     self.tcx,
                                     self.body_id,
                                     &mut err,
-                                    ty,
+                                    *ty,
                                     rhs_ty,
                                     missing_trait,
                                     p,
@@ -878,7 +878,7 @@ enum Op {
 /// Dereferences a single level of immutable referencing.
 fn deref_ty_if_possible<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> {
     match ty.kind() {
-        ty::Ref(_, ty, hir::Mutability::Not) => ty,
+        ty::Ref(_, ty, hir::Mutability::Not) => *ty,
         _ => ty,
     }
 }
index 62cd9c64a4a7c8205af4600d1fc14fca32a1fb00..e034adde1be86e1887ed089e52ef7f6b5f9298da 100644 (file)
@@ -1935,7 +1935,7 @@ fn check_array_pat_len(
         element_ty: Ty<'tcx>,
         arr_ty: Ty<'tcx>,
         slice: Option<&'tcx Pat<'tcx>>,
-        len: &ty::Const<'tcx>,
+        len: ty::Const<'tcx>,
         min_len: u64,
     ) -> (Option<Ty<'tcx>>, Ty<'tcx>) {
         if let Some(len) = len.try_eval_usize(self.tcx, self.param_env) {
@@ -2029,34 +2029,42 @@ fn error_expected_array_or_slice(&self, span: Span, expected_ty: Ty<'tcx>, ti: T
                 err.help("the semantics of slice patterns changed recently; see issue #62254");
             }
         } else if Autoderef::new(&self.infcx, self.param_env, self.body_id, span, expected_ty, span)
-            .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..)))
+            .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
         {
             if let (Some(span), true) = (ti.span, ti.origin_expr) {
                 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-                    let applicability = match self.resolve_vars_if_possible(ti.expected).kind() {
-                        ty::Adt(adt_def, _)
-                            if self.tcx.is_diagnostic_item(sym::Option, adt_def.did)
-                                || self.tcx.is_diagnostic_item(sym::Result, adt_def.did) =>
-                        {
-                            // Slicing won't work here, but `.as_deref()` might (issue #91328).
-                            err.span_suggestion(
-                                span,
-                                "consider using `as_deref` here",
-                                format!("{}.as_deref()", snippet),
-                                Applicability::MaybeIncorrect,
-                            );
-                            None
-                        }
-                        // FIXME: instead of checking for Vec only, we could check whether the
-                        // type implements `Deref<Target=X>`; see
-                        // https://github.com/rust-lang/rust/pull/91343#discussion_r761466979
-                        ty::Adt(adt_def, _)
-                            if self.tcx.is_diagnostic_item(sym::Vec, adt_def.did) =>
-                        {
-                            Some(Applicability::MachineApplicable)
+                    let applicability = Autoderef::new(
+                        &self.infcx,
+                        self.param_env,
+                        self.body_id,
+                        span,
+                        self.resolve_vars_if_possible(ti.expected),
+                        span,
+                    )
+                    .find_map(|(ty, _)| {
+                        match ty.kind() {
+                            ty::Adt(adt_def, _)
+                                if self.tcx.is_diagnostic_item(sym::Option, adt_def.did)
+                                    || self.tcx.is_diagnostic_item(sym::Result, adt_def.did) =>
+                            {
+                                // Slicing won't work here, but `.as_deref()` might (issue #91328).
+                                err.span_suggestion(
+                                    span,
+                                    "consider using `as_deref` here",
+                                    format!("{}.as_deref()", snippet),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                Some(None)
+                            }
+
+                            ty::Slice(..) | ty::Array(..) => {
+                                Some(Some(Applicability::MachineApplicable))
+                            }
+
+                            _ => None,
                         }
-                        _ => Some(Applicability::MaybeIncorrect),
-                    };
+                    })
+                    .unwrap_or(Some(Applicability::MaybeIncorrect));
 
                     if let Some(applicability) = applicability {
                         err.span_suggestion(
index d01e21bcb23602511ad9341ded7af8a4b28aa657..318979b462759413fad36d629de06aa229041fef 100644 (file)
@@ -31,7 +31,7 @@ pub(super) fn lookup_derefing(
             self.apply_adjustments(
                 oprnd_expr,
                 vec![Adjustment {
-                    kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)),
+                    kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)),
                     target: method.sig.inputs()[0],
                 }],
             );
@@ -142,7 +142,7 @@ fn try_index_step(
             if unsize {
                 // We only unsize arrays here.
                 if let ty::Array(element_ty, _) = adjusted_ty.kind() {
-                    self_ty = self.tcx.mk_slice(element_ty);
+                    self_ty = self.tcx.mk_slice(*element_ty);
                 } else {
                     continue;
                 }
@@ -165,9 +165,9 @@ fn try_index_step(
                 let mut adjustments = self.adjust_steps(autoderef);
                 if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() {
                     adjustments.push(Adjustment {
-                        kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)),
+                        kind: Adjust::Borrow(AutoBorrow::Ref(*region, AutoBorrowMutability::Not)),
                         target: self.tcx.mk_ref(
-                            region,
+                            *region,
                             ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: adjusted_ty },
                         ),
                     });
@@ -432,9 +432,10 @@ fn convert_place_op_to_mutable(
                         // not the case today.
                         allow_two_phase_borrow: AllowTwoPhase::No,
                     };
-                    adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(region, mutbl));
-                    adjustment.target =
-                        self.tcx.mk_ref(region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
+                    adjustment.kind = Adjust::Borrow(AutoBorrow::Ref(*region, mutbl));
+                    adjustment.target = self
+                        .tcx
+                        .mk_ref(*region, ty::TypeAndMut { ty: source, mutbl: mutbl.into() });
                 }
                 source = adjustment.target;
             }
index 4e50fbf56b2d27bbddfd3e7d7a7bc18f80eec61c..513e8576f2d1936882fbfe59a76469e39ed49523 100644 (file)
@@ -689,7 +689,7 @@ fn link_region_from_node_type(
         let rptr_ty = self.resolve_node_type(id);
         if let ty::Ref(r, _, _) = rptr_ty.kind() {
             debug!("rptr_ty={}", rptr_ty);
-            self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed);
+            self.link_region(span, *r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed);
         }
     }
 
index becae6c9dc920ad7ee67dcdcf406cebc18326b36..949d857bff46288302154e0c80ea49e6e63f19be 100644 (file)
@@ -966,7 +966,7 @@ fn compute_2229_migrations_for_trait(
                     self.tcx,
                     ty,
                     max_capture_info.capture_kind,
-                    Some(&ty::ReErased),
+                    Some(self.tcx.lifetimes.re_erased),
                 )
             }
         };
@@ -997,7 +997,7 @@ fn compute_2229_migrations_for_trait(
                 self.tcx,
                 capture.place.ty(),
                 capture.info.capture_kind,
-                Some(&ty::ReErased),
+                Some(self.tcx.lifetimes.re_erased),
             );
 
             // Checks if a capture implements any of the auto traits
@@ -1499,7 +1499,7 @@ fn init_capture_kind_for_place(
             // If the data will be moved out of this place, then the place will be truncated
             // at the first Deref in `adjust_upvar_borrow_kind_for_consume` and then moved into
             // the closure.
-            hir::CaptureBy::Value if !place.deref_tys().any(ty::TyS::is_ref) => {
+            hir::CaptureBy::Value if !place.deref_tys().any(Ty::is_ref) => {
                 ty::UpvarCapture::ByValue
             }
             hir::CaptureBy::Value | hir::CaptureBy::Ref => ty::UpvarCapture::ByRef(ty::ImmBorrow),
@@ -1653,7 +1653,8 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
         match p.kind {
             ProjectionKind::Field(..) => match ty.kind() {
                 ty::Adt(def, _) if def.repr.packed() => {
-                    match tcx.layout_of(param_env.and(p.ty)) {
+                    // We erase regions here because they cannot be hashed
+                    match tcx.layout_of(param_env.and(tcx.erase_regions(p.ty))) {
                         Ok(layout) if layout.align.abi.bytes() == 1 => {
                             // if the alignment is 1, the type can't be further
                             // disaligned.
@@ -1812,7 +1813,7 @@ fn borrow(
         );
 
         // Raw pointers don't inherit mutability
-        if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
+        if place_with_id.place.deref_tys().any(Ty::is_unsafe_ptr) {
             capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow);
         }
 
index 71f45320e49520192185a5a885662a2c8a09e4bf..55757251e26fdb1c5acd34182b89d07f71f68356 100644 (file)
@@ -3,7 +3,7 @@
 use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
 
 use rustc_ast as ast;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -258,251 +258,186 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                 .emit();
         }
     }
-
-    check_gat_where_clauses(tcx, trait_item, encl_trait_def_id);
 }
 
 /// Require that the user writes where clauses on GATs for the implicit
 /// outlives bounds involving trait parameters in trait functions and
 /// lifetimes passed as GAT substs. See `self-outlives-lint` test.
 ///
-/// This trait will be our running example. We are currently WF checking the `Item` item...
-///
-/// ```rust
-/// trait LendingIterator {
-///   type Item<'me>; // <-- WF checking this trait item
-///
-///   fn next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
+/// We use the following trait as an example throughout this function:
+/// ```rust,ignore (this code fails due to this lint)
+/// trait IntoIter {
+///     type Iter<'a>: Iterator<Item = Self::Item<'a>>;
+///     type Item<'a>;
+///     fn into_iter<'a>(&'a self) -> Self::Iter<'a>;
 /// }
 /// ```
-fn check_gat_where_clauses(
-    tcx: TyCtxt<'_>,
-    trait_item: &hir::TraitItem<'_>,
-    encl_trait_def_id: DefId,
-) {
-    let item = tcx.associated_item(trait_item.def_id);
-    // If the current trait item isn't a type, it isn't a GAT
-    if !matches!(item.kind, ty::AssocKind::Type) {
-        return;
-    }
-    let generics: &ty::Generics = tcx.generics_of(trait_item.def_id);
-    // If the current associated type doesn't have any (own) params, it's not a GAT
-    // FIXME(jackh726): we can also warn in the more general case
-    if generics.params.len() == 0 {
-        return;
-    }
-    let associated_items: &ty::AssocItems<'_> = tcx.associated_items(encl_trait_def_id);
-    let mut clauses: Option<FxHashSet<ty::Predicate<'_>>> = None;
-    // For every function in this trait...
-    // In our example, this would be the `next` method
-    for item in
-        associated_items.in_definition_order().filter(|item| matches!(item.kind, ty::AssocKind::Fn))
-    {
-        // The clauses we that we would require from this function
-        let mut function_clauses = FxHashSet::default();
-
-        let id = hir::HirId::make_owner(item.def_id.expect_local());
-        let param_env = tcx.param_env(item.def_id.expect_local());
-
-        let sig = tcx.fn_sig(item.def_id);
-        // Get the signature using placeholders. In our example, this would
-        // convert the late-bound 'a into a free region.
-        let sig = tcx.liberate_late_bound_regions(item.def_id, sig);
-        // Collect the arguments that are given to this GAT in the return type
-        // of  the function signature. In our example, the GAT in the return
-        // type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments.
-        let (regions, types) =
-            GATSubstCollector::visit(tcx, trait_item.def_id.to_def_id(), sig.output());
-
-        // If both regions and types are empty, then this GAT isn't in the
-        // return type, and we shouldn't try to do clause analysis
-        // (particularly, doing so would end up with an empty set of clauses,
-        // since the current method would require none, and we take the
-        // intersection of requirements of all methods)
-        if types.is_empty() && regions.is_empty() {
-            continue;
-        }
-
-        // The types we can assume to be well-formed. In our example, this
-        // would be &'a mut Self, from the first argument.
-        let mut wf_tys = FxHashSet::default();
-        wf_tys.extend(sig.inputs());
-
-        // For each region argument (e.g., 'a in our example), check for a
-        // relationship to the type arguments (e.g., Self). If there is an
-        // outlives relationship (`Self: 'a`), then we want to ensure that is
-        // reflected in a where clause on the GAT itself.
-        for (region, region_idx) in &regions {
-            // Ignore `'static` lifetimes for the purpose of this lint: it's
-            // because we know it outlives everything and so doesn't give meaninful
-            // clues
-            if let ty::ReStatic = region {
+fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRef]) {
+    // Associates every GAT's def_id to a list of possibly missing bounds detected by this lint.
+    let mut required_bounds_by_item = FxHashMap::default();
+
+    // Loop over all GATs together, because if this lint suggests adding a where-clause bound
+    // to one GAT, it might then require us to an additional bound on another GAT.
+    // In our `IntoIter` example, we discover a missing `Self: 'a` bound on `Iter<'a>`, which
+    // then in a second loop adds a `Self: 'a` bound to `Item` due to the relationship between
+    // those GATs.
+    loop {
+        let mut should_continue = false;
+        for gat_item in associated_items {
+            let gat_def_id = gat_item.id.def_id;
+            let gat_item = tcx.associated_item(gat_def_id);
+            // If this item is not an assoc ty, or has no substs, then it's not a GAT
+            if gat_item.kind != ty::AssocKind::Type {
                 continue;
             }
-            for (ty, ty_idx) in &types {
-                // In our example, requires that Self: 'a
-                if ty_known_to_outlive(tcx, id, param_env, &wf_tys, *ty, *region) {
-                    debug!(?ty_idx, ?region_idx);
-                    debug!("required clause: {} must outlive {}", ty, region);
-                    // Translate into the generic parameters of the GAT. In
-                    // our example, the type was Self, which will also be
-                    // Self in the GAT.
-                    let ty_param = generics.param_at(*ty_idx, tcx);
-                    let ty_param = tcx.mk_ty(ty::Param(ty::ParamTy {
-                        index: ty_param.index,
-                        name: ty_param.name,
-                    }));
-                    // Same for the region. In our example, 'a corresponds
-                    // to the 'me parameter.
-                    let region_param = generics.param_at(*region_idx, tcx);
-                    let region_param =
-                        tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
-                            def_id: region_param.def_id,
-                            index: region_param.index,
-                            name: region_param.name,
-                        }));
-                    // The predicate we expect to see. (In our example,
-                    // `Self: 'me`.)
-                    let clause = ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
-                        ty_param,
-                        region_param,
-                    ));
-                    let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
-                    function_clauses.insert(clause);
-                }
-            }
-        }
-
-        // For each region argument (e.g., 'a in our example), also check for a
-        // relationship to the other region arguments. If there is an
-        // outlives relationship, then we want to ensure that is
-        // reflected in a where clause on the GAT itself.
-        for (region_a, region_a_idx) in &regions {
-            // Ignore `'static` lifetimes for the purpose of this lint: it's
-            // because we know it outlives everything and so doesn't give meaninful
-            // clues
-            if let ty::ReStatic = region_a {
+            let gat_generics = tcx.generics_of(gat_def_id);
+            // FIXME(jackh726): we can also warn in the more general case
+            if gat_generics.params.is_empty() {
                 continue;
             }
-            for (region_b, region_b_idx) in &regions {
-                if region_a == region_b {
-                    continue;
-                }
-                if let ty::ReStatic = region_b {
+
+            // Gather the bounds with which all other items inside of this trait constrain the GAT.
+            // This is calculated by taking the intersection of the bounds that each item
+            // constrains the GAT with individually.
+            let mut new_required_bounds: Option<FxHashSet<ty::Predicate<'_>>> = None;
+            for item in associated_items {
+                let item_def_id = item.id.def_id;
+                // Skip our own GAT, since it does not constrain itself at all.
+                if item_def_id == gat_def_id {
                     continue;
                 }
 
-                if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) {
-                    debug!(?region_a_idx, ?region_b_idx);
-                    debug!("required clause: {} must outlive {}", region_a, region_b);
-                    // Translate into the generic parameters of the GAT.
-                    let region_a_param = generics.param_at(*region_a_idx, tcx);
-                    let region_a_param =
-                        tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
-                            def_id: region_a_param.def_id,
-                            index: region_a_param.index,
-                            name: region_a_param.name,
-                        }));
-                    // Same for the region.
-                    let region_b_param = generics.param_at(*region_b_idx, tcx);
-                    let region_b_param =
-                        tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
-                            def_id: region_b_param.def_id,
-                            index: region_b_param.index,
-                            name: region_b_param.name,
-                        }));
-                    // The predicate we expect to see.
-                    let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
-                        region_a_param,
-                        region_b_param,
-                    ));
-                    let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
-                    function_clauses.insert(clause);
+                let item_hir_id = item.id.hir_id();
+                let param_env = tcx.param_env(item_def_id);
+
+                let item_required_bounds = match item.kind {
+                    // In our example, this corresponds to `into_iter` method
+                    hir::AssocItemKind::Fn { .. } => {
+                        // For methods, we check the function signature's return type for any GATs
+                        // to constrain. In the `into_iter` case, we see that the return type
+                        // `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
+                        let sig: ty::FnSig<'_> = tcx.liberate_late_bound_regions(
+                            item_def_id.to_def_id(),
+                            tcx.fn_sig(item_def_id),
+                        );
+                        gather_gat_bounds(
+                            tcx,
+                            param_env,
+                            item_hir_id,
+                            sig.output(),
+                            // We also assume that all of the function signature's parameter types
+                            // are well formed.
+                            &sig.inputs().iter().copied().collect(),
+                            gat_def_id,
+                            gat_generics,
+                        )
+                    }
+                    // In our example, this corresponds to the `Iter` and `Item` associated types
+                    hir::AssocItemKind::Type => {
+                        // If our associated item is a GAT with missing bounds, add them to
+                        // the param-env here. This allows this GAT to propagate missing bounds
+                        // to other GATs.
+                        let param_env = augment_param_env(
+                            tcx,
+                            param_env,
+                            required_bounds_by_item.get(&item_def_id),
+                        );
+                        gather_gat_bounds(
+                            tcx,
+                            param_env,
+                            item_hir_id,
+                            tcx.explicit_item_bounds(item_def_id)
+                                .iter()
+                                .copied()
+                                .collect::<Vec<_>>(),
+                            &FxHashSet::default(),
+                            gat_def_id,
+                            gat_generics,
+                        )
+                    }
+                    hir::AssocItemKind::Const => None,
+                };
+
+                if let Some(item_required_bounds) = item_required_bounds {
+                    // Take the intersection of the required bounds for this GAT, and
+                    // the item_required_bounds which are the ones implied by just
+                    // this item alone.
+                    // This is why we use an Option<_>, since we need to distinguish
+                    // the empty set of bounds from the _uninitialized_ set of bounds.
+                    if let Some(new_required_bounds) = &mut new_required_bounds {
+                        new_required_bounds.retain(|b| item_required_bounds.contains(b));
+                    } else {
+                        new_required_bounds = Some(item_required_bounds);
+                    }
                 }
             }
-        }
 
-        // Imagine we have:
-        // ```
-        // trait Foo {
-        //   type Bar<'me>;
-        //   fn gimme(&self) -> Self::Bar<'_>;
-        //   fn gimme_default(&self) -> Self::Bar<'static>;
-        // }
-        // ```
-        // We only want to require clauses on `Bar` that we can prove from *all* functions (in this
-        // case, `'me` can be `static` from `gimme_default`)
-        match clauses.as_mut() {
-            Some(clauses) => {
-                clauses.drain_filter(|p| !function_clauses.contains(p));
-            }
-            None => {
-                clauses = Some(function_clauses);
+            if let Some(new_required_bounds) = new_required_bounds {
+                let required_bounds = required_bounds_by_item.entry(gat_def_id).or_default();
+                if new_required_bounds.into_iter().any(|p| required_bounds.insert(p)) {
+                    // Iterate until our required_bounds no longer change
+                    // Since they changed here, we should continue the loop
+                    should_continue = true;
+                }
             }
         }
+        // We know that this loop will eventually halt, since we only set `should_continue` if the
+        // `required_bounds` for this item grows. Since we are not creating any new region or type
+        // variables, the set of all region and type bounds that we could ever insert are limited
+        // by the number of unique types and regions we observe in a given item.
+        if !should_continue {
+            break;
+        }
     }
 
-    // If there are any clauses that aren't provable, emit an error
-    let clauses = clauses.unwrap_or_default();
-    debug!(?clauses);
-    if !clauses.is_empty() {
-        let param_env = tcx.param_env(trait_item.def_id);
+    for (gat_def_id, required_bounds) in required_bounds_by_item {
+        let gat_item_hir = tcx.hir().expect_trait_item(gat_def_id);
+        debug!(?required_bounds);
+        let param_env = tcx.param_env(gat_def_id);
+        let gat_hir = gat_item_hir.hir_id();
 
-        let mut clauses: Vec<_> = clauses
+        let mut unsatisfied_bounds: Vec<_> = required_bounds
             .into_iter()
             .filter(|clause| match clause.kind().skip_binder() {
                 ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => {
-                    !region_known_to_outlive(
-                        tcx,
-                        trait_item.hir_id(),
-                        param_env,
-                        &FxHashSet::default(),
-                        a,
-                        b,
-                    )
+                    !region_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b)
                 }
                 ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(a, b)) => {
-                    !ty_known_to_outlive(
-                        tcx,
-                        trait_item.hir_id(),
-                        param_env,
-                        &FxHashSet::default(),
-                        a,
-                        b,
-                    )
+                    !ty_known_to_outlive(tcx, gat_hir, param_env, &FxHashSet::default(), a, b)
                 }
                 _ => bug!("Unexpected PredicateKind"),
             })
-            .map(|clause| format!("{}", clause))
+            .map(|clause| clause.to_string())
             .collect();
 
         // We sort so that order is predictable
-        clauses.sort();
+        unsatisfied_bounds.sort();
 
-        if !clauses.is_empty() {
-            let plural = if clauses.len() > 1 { "s" } else { "" };
+        if !unsatisfied_bounds.is_empty() {
+            let plural = if unsatisfied_bounds.len() > 1 { "s" } else { "" };
             let mut err = tcx.sess.struct_span_err(
-                trait_item.span,
-                &format!("missing required bound{} on `{}`", plural, trait_item.ident),
+                gat_item_hir.span,
+                &format!("missing required bound{} on `{}`", plural, gat_item_hir.ident),
             );
 
             let suggestion = format!(
                 "{} {}",
-                if !trait_item.generics.where_clause.predicates.is_empty() {
+                if !gat_item_hir.generics.where_clause.predicates.is_empty() {
                     ","
                 } else {
                     " where"
                 },
-                clauses.join(", "),
+                unsatisfied_bounds.join(", "),
             );
             err.span_suggestion(
-                trait_item.generics.where_clause.tail_span_for_suggestion(),
+                gat_item_hir.generics.where_clause.tail_span_for_suggestion(),
                 &format!("add the required where clause{}", plural),
                 suggestion,
                 Applicability::MachineApplicable,
             );
 
-            let bound = if clauses.len() > 1 { "these bounds are" } else { "this bound is" };
+            let bound =
+                if unsatisfied_bounds.len() > 1 { "these bounds are" } else { "this bound is" };
             err.note(&format!(
                 "{} currently required to ensure that impls have maximum flexibility",
                 bound
@@ -518,6 +453,143 @@ fn check_gat_where_clauses(
     }
 }
 
+/// Add a new set of predicates to the caller_bounds of an existing param_env.
+fn augment_param_env<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    new_predicates: Option<&FxHashSet<ty::Predicate<'tcx>>>,
+) -> ty::ParamEnv<'tcx> {
+    let Some(new_predicates) = new_predicates else {
+        return param_env;
+    };
+
+    if new_predicates.is_empty() {
+        return param_env;
+    }
+
+    let bounds =
+        tcx.mk_predicates(param_env.caller_bounds().iter().chain(new_predicates.iter().cloned()));
+    // FIXME(compiler-errors): Perhaps there is a case where we need to normalize this
+    // i.e. traits::normalize_param_env_or_error
+    ty::ParamEnv::new(bounds, param_env.reveal(), param_env.constness())
+}
+
+/// We use the following trait as an example throughout this function.
+/// Specifically, let's assume that `to_check` here is the return type
+/// of `into_iter`, and the GAT we are checking this for is `Iter`.
+/// ```rust,ignore (this code fails due to this lint)
+/// trait IntoIter {
+///     type Iter<'a>: Iterator<Item = Self::Item<'a>>;
+///     type Item<'a>;
+///     fn into_iter<'a>(&'a self) -> Self::Iter<'a>;
+/// }
+/// ```
+fn gather_gat_bounds<'tcx, T: TypeFoldable<'tcx>>(
+    tcx: TyCtxt<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    item_hir: hir::HirId,
+    to_check: T,
+    wf_tys: &FxHashSet<Ty<'tcx>>,
+    gat_def_id: LocalDefId,
+    gat_generics: &'tcx ty::Generics,
+) -> Option<FxHashSet<ty::Predicate<'tcx>>> {
+    // The bounds we that we would require from `to_check`
+    let mut bounds = FxHashSet::default();
+
+    let (regions, types) = GATSubstCollector::visit(tcx, gat_def_id.to_def_id(), to_check);
+
+    // If both regions and types are empty, then this GAT isn't in the
+    // set of types we are checking, and we shouldn't try to do clause analysis
+    // (particularly, doing so would end up with an empty set of clauses,
+    // since the current method would require none, and we take the
+    // intersection of requirements of all methods)
+    if types.is_empty() && regions.is_empty() {
+        return None;
+    }
+
+    for (region_a, region_a_idx) in &regions {
+        // Ignore `'static` lifetimes for the purpose of this lint: it's
+        // because we know it outlives everything and so doesn't give meaninful
+        // clues
+        if let ty::ReStatic = **region_a {
+            continue;
+        }
+        // For each region argument (e.g., `'a` in our example), check for a
+        // relationship to the type arguments (e.g., `Self`). If there is an
+        // outlives relationship (`Self: 'a`), then we want to ensure that is
+        // reflected in a where clause on the GAT itself.
+        for (ty, ty_idx) in &types {
+            // In our example, requires that `Self: 'a`
+            if ty_known_to_outlive(tcx, item_hir, param_env, &wf_tys, *ty, *region_a) {
+                debug!(?ty_idx, ?region_a_idx);
+                debug!("required clause: {} must outlive {}", ty, region_a);
+                // Translate into the generic parameters of the GAT. In
+                // our example, the type was `Self`, which will also be
+                // `Self` in the GAT.
+                let ty_param = gat_generics.param_at(*ty_idx, tcx);
+                let ty_param = tcx
+                    .mk_ty(ty::Param(ty::ParamTy { index: ty_param.index, name: ty_param.name }));
+                // Same for the region. In our example, 'a corresponds
+                // to the 'me parameter.
+                let region_param = gat_generics.param_at(*region_a_idx, tcx);
+                let region_param =
+                    tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+                        def_id: region_param.def_id,
+                        index: region_param.index,
+                        name: region_param.name,
+                    }));
+                // The predicate we expect to see. (In our example,
+                // `Self: 'me`.)
+                let clause =
+                    ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty_param, region_param));
+                let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
+                bounds.insert(clause);
+            }
+        }
+
+        // For each region argument (e.g., `'a` in our example), also check for a
+        // relationship to the other region arguments. If there is an outlives
+        // relationship, then we want to ensure that is reflected in the where clause
+        // on the GAT itself.
+        for (region_b, region_b_idx) in &regions {
+            // Again, skip `'static` because it outlives everything. Also, we trivially
+            // know that a region outlives itself.
+            if ty::ReStatic == **region_b || region_a == region_b {
+                continue;
+            }
+            if region_known_to_outlive(tcx, item_hir, param_env, &wf_tys, *region_a, *region_b) {
+                debug!(?region_a_idx, ?region_b_idx);
+                debug!("required clause: {} must outlive {}", region_a, region_b);
+                // Translate into the generic parameters of the GAT.
+                let region_a_param = gat_generics.param_at(*region_a_idx, tcx);
+                let region_a_param =
+                    tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+                        def_id: region_a_param.def_id,
+                        index: region_a_param.index,
+                        name: region_a_param.name,
+                    }));
+                // Same for the region.
+                let region_b_param = gat_generics.param_at(*region_b_idx, tcx);
+                let region_b_param =
+                    tcx.mk_region(ty::RegionKind::ReEarlyBound(ty::EarlyBoundRegion {
+                        def_id: region_b_param.def_id,
+                        index: region_b_param.index,
+                        name: region_b_param.name,
+                    }));
+                // The predicate we expect to see.
+                let clause = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
+                    region_a_param,
+                    region_b_param,
+                ));
+                let clause = tcx.mk_predicate(ty::Binder::dummy(clause));
+                bounds.insert(clause);
+            }
+        }
+    }
+
+    Some(bounds)
+}
+
 /// Given a known `param_env` and a set of well formed types, can we prove that
 /// `ty` outlives `region`.
 fn ty_known_to_outlive<'tcx>(
@@ -569,7 +641,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
     wf_tys: &FxHashSet<Ty<'tcx>>,
     add_constraints: impl for<'a> FnOnce(
         &'a InferCtxt<'a, 'tcx>,
-        &'a Vec<(&'tcx ty::RegionKind, GenericKind<'tcx>)>,
+        &'a Vec<(ty::Region<'tcx>, GenericKind<'tcx>)>,
     ),
 ) -> bool {
     // Unfortunately, we have to use a new `InferCtxt` each call, because
@@ -1027,6 +1099,11 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
 
         FxHashSet::default()
     });
+
+    // Only check traits, don't check trait aliases
+    if let hir::ItemKind::Trait(_, _, _, _, items) = item.kind {
+        check_gat_where_clauses(tcx, items);
+    }
 }
 
 /// Checks all associated type defaults of trait `trait_def_id`.
@@ -1298,8 +1375,8 @@ fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                     ControlFlow::BREAK
                 }
 
-                fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-                    if let ty::ConstKind::Param(param) = c.val {
+                fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+                    if let ty::ConstKind::Param(param) = c.val() {
                         self.params.insert(param.index);
                     }
                     c.super_visit_with(self)
index ec88bdf4a370f8a8508d9da6f24e7e827aebdbeb..3843e7e54bec4cca7e056ef73663ca7c3965c2b4 100644 (file)
@@ -720,7 +720,7 @@ fn report_type_error(&self, t: Ty<'tcx>) {
         }
     }
 
-    fn report_const_error(&self, c: &'tcx ty::Const<'tcx>) {
+    fn report_const_error(&self, c: ty::Const<'tcx>) {
         if !self.tcx.sess.has_errors() {
             self.infcx
                 .emit_inference_failure_err(
@@ -751,7 +751,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         }
     }
     fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        if let ty::ReLateBound(..) = r { r } else { self.tcx.lifetimes.re_erased }
+        if r.is_late_bound() { r } else { self.tcx.lifetimes.re_erased }
     }
 }
 
@@ -783,14 +783,14 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
         self.tcx.lifetimes.re_erased
     }
 
-    fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
+    fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
         match self.infcx.fully_resolve(ct) {
             Ok(ct) => self.infcx.tcx.erase_regions(ct),
             Err(_) => {
                 debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
                 self.report_const_error(ct);
                 self.replaced_with_error = true;
-                self.tcx().const_error(ct.ty)
+                self.tcx().const_error(ct.ty())
             }
         }
     }
index dff6b7b58a0f9986520e9a37e544ae18ce653ae6..401ba188728c17e3cd0b8607607c7d6d61b3ab69 100644 (file)
@@ -147,7 +147,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
         use ty::TyKind::*;
         match (source.kind(), target.kind()) {
             (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b))
-                if infcx.at(&cause, param_env).eq(r_a, r_b).is_ok() && mutbl_a == *mutbl_b => {}
+                if infcx.at(&cause, param_env).eq(r_a, *r_b).is_ok() && mutbl_a == *mutbl_b => {}
             (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (),
             (&Adt(def_a, substs_a), &Adt(def_b, substs_b))
                 if def_a.is_struct() && def_b.is_struct() =>
index 777bd640669ce8f1c33d8e192457a7925dd86847..9bb310037965555f0d784fd1c50242d23561aae8 100644 (file)
@@ -301,7 +301,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         }
     }
     fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match r {
+        match *r {
             ty::ReEarlyBound(p) => {
                 if self.seen.insert(p.index) {
                     ControlFlow::CONTINUE
@@ -312,8 +312,8 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             _ => ControlFlow::Break(NotUniqueParam::NotParam(r.into())),
         }
     }
-    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match c.val {
+    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        match c.val() {
             ty::ConstKind::Param(p) => {
                 if self.seen.insert(p.index) {
                     ControlFlow::CONTINUE
index cf519a9ab32747be49555c008f9f7893c10aba2d..4c9f21d0d4ae191b57fc8d89f0bb3b5b0b88251e 100644 (file)
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 //! "Collection" is the process of determining the type and other external
 //! details of each item in Rust. Collection is specifically concerned
 //! with *inter-procedural* things -- for example, for a function
@@ -388,13 +389,8 @@ fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
         self.tcx().ty_error_with_message(span, "bad placeholder type")
     }
 
-    fn ct_infer(
-        &self,
-        ty: Ty<'tcx>,
-        _: Option<&ty::GenericParamDef>,
-        span: Span,
-    ) -> &'tcx Const<'tcx> {
-        let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r {
+    fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
+        let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match *r {
             ty::ReErased => self.tcx.lifetimes.re_static,
             _ => r,
         });
@@ -1695,7 +1691,7 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         kind: ty::GenericParamDefKind::Lifetime,
     }));
 
-    let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id);
+    let object_lifetime_defaults = tcx.object_lifetime_defaults(hir_id.owner);
 
     // Now create the real type and const parameters.
     let type_start = own_start - has_self as u32 + params.len() as u32;
@@ -1877,7 +1873,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
                 Some(ty) => {
                     let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
                     // Typeck doesn't expect erased regions to be returned from `type_of`.
-                    let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match r {
+                    let fn_sig = tcx.fold_regions(fn_sig, &mut false, |r, _| match *r {
                         ty::ReErased => tcx.lifetimes.re_static,
                         _ => r,
                     });
@@ -2394,7 +2390,7 @@ impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
         fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
             let def_id = self.tcx.hir().local_def_id(c.hir_id);
             let ct = ty::Const::from_anon_const(self.tcx, def_id);
-            if let ty::ConstKind::Unevaluated(uv) = ct.val {
+            if let ty::ConstKind::Unevaluated(uv) = ct.val() {
                 assert_eq!(uv.promoted, None);
                 let span = self.tcx.hir().span(c.hir_id);
                 self.preds.insert((
@@ -2591,7 +2587,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
             }
         };
         for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) {
-            check(input, ty)
+            check(input, *ty)
         }
         if let hir::FnRetTy::Return(ref ty) = decl.output {
             check(ty, fty.output().skip_binder())
@@ -2778,6 +2774,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         }
     }
 
+    // The panic_no_unwind function called by TerminatorKind::Abort will never
+    // unwind. If the panic handler that it invokes unwind then it will simply
+    // call the panic handler again.
+    if Some(id) == tcx.lang_items().panic_no_unwind() {
+        codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
+    }
+
     let supported_target_features = tcx.supported_target_features(LOCAL_CRATE);
 
     let mut inline_span = None;
@@ -2849,7 +2852,42 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
         } else if attr.has_name(sym::rustc_std_internal_symbol) {
             codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
         } else if attr.has_name(sym::used) {
-            codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
+            let inner = attr.meta_item_list();
+            match inner.as_deref() {
+                Some([item]) if item.has_name(sym::linker) => {
+                    if !tcx.features().used_with_arg {
+                        feature_err(
+                            &tcx.sess.parse_sess,
+                            sym::used_with_arg,
+                            attr.span,
+                            "`#[used(linker)]` is currently unstable",
+                        )
+                        .emit();
+                    }
+                    codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED_LINKER;
+                }
+                Some([item]) if item.has_name(sym::compiler) => {
+                    if !tcx.features().used_with_arg {
+                        feature_err(
+                            &tcx.sess.parse_sess,
+                            sym::used_with_arg,
+                            attr.span,
+                            "`#[used(compiler)]` is currently unstable",
+                        )
+                        .emit();
+                    }
+                    codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
+                }
+                Some(_) => {
+                    tcx.sess
+                        .struct_span_err(
+                            attr.span,
+                            "expected `used`, `used(compiler)` or `used(linker)`",
+                        )
+                        .emit();
+                }
+                None => codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED,
+            }
         } else if attr.has_name(sym::cmse_nonsecure_entry) {
             if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) {
                 struct_span_err!(
index 5cb0d309ff4ee020073f606b143ecaf103f37844..90555b213c1cab86a6ce974be718f5bceca2058a 100644 (file)
@@ -514,8 +514,9 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                               })
                       }) =>
                 {
-                  // FIXME(associated_const_equality) when does this unwrap fail? I have no idea what case it would.
-                  let trait_def_id = trait_ref.trait_def_id().unwrap();
+                  let Some(trait_def_id) = trait_ref.trait_def_id() else {
+                    return tcx.ty_error_with_message(DUMMY_SP, "Could not find trait");
+                  };
                   let assoc_items = tcx.associated_items(trait_def_id);
                   let assoc_item = assoc_items.find_by_name_and_kind(
                     tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(),
@@ -638,7 +639,7 @@ fn check(&mut self, def_id: LocalDefId) {
                         err.emit();
                     }
                 } else {
-                    self.found = Some((span, concrete_type));
+                    self.found = Some((span, *concrete_type));
                 }
             }
         }
@@ -828,7 +829,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
     }
 
     // Typeck doesn't expect erased regions to be returned from `type_of`.
-    tcx.fold_regions(ty, &mut false, |r, _| match r {
+    tcx.fold_regions(ty, &mut false, |r, _| match *r {
         ty::ReErased => tcx.lifetimes.re_static,
         _ => r,
     })
index a0c8fc822dffd88769c78094b71dda48211d0125..909c99adab5d2d91f6162e86d206896e145f8e3b 100644 (file)
@@ -79,11 +79,11 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
         ControlFlow::CONTINUE
     }
 
-    fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        match c.val {
+    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
+        match c.val() {
             ty::ConstKind::Unevaluated(..) if !self.include_nonconstraining => {
                 // Constant expressions are not injective
-                return c.ty.visit_with(self);
+                return c.ty().visit_with(self);
             }
             ty::ConstKind::Param(data) => {
                 self.parameters.push(Parameter::from(data));
index 7d1aedc86008b7b60bfe90703b02a9f75afc3180..7b709b302f630a0b0369f32c5f9c9f84acf4e7fc 100644 (file)
@@ -180,6 +180,6 @@ fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
         self.tcx
     }
     fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> {
-        if let ty::ReLateBound(..) = r { &ty::ReErased } else { r }
+        if r.is_late_bound() { self.tcx.lifetimes.re_erased } else { r }
     }
 }
index d87e670a8fb5a7bf912ea64031a9b1a5d70e4944..92f88a15ee4163c3f66868ee076f07d76b54657b 100644 (file)
@@ -269,7 +269,7 @@ fn check_static_lifetimes<'tcx>(
     parent_substs: &Vec<GenericArg<'tcx>>,
     span: Span,
 ) {
-    if tcx.any_free_region_meets(parent_substs, |r| *r == ty::ReStatic) {
+    if tcx.any_free_region_meets(parent_substs, |r| r.is_static()) {
         tcx.sess.struct_span_err(span, "cannot specialize on `'static` lifetime").emit();
     }
 }
index 7b004fa086bf3a1bbda36fd1793663d073245f79..d415e37ff0116435c67d6a0acf30a6c5d762c9d1 100644 (file)
 fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
     match (decl.c_variadic, abi) {
         // The function has the correct calling convention, or isn't a "C-variadic" function.
-        (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl) => {}
+        (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {}
         // The function is a "C-variadic" function with an incorrect calling convention.
         (true, _) => {
             let mut err = struct_span_err!(
index 2c2d2be8bb5141e9eac2f9c9073b64164243074b..1bbd6d29294a60e62fe6e067177d036f3da50c45 100644 (file)
@@ -192,7 +192,7 @@ fn expr_ty(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
         if let Some(vec) = self.typeck_results.pat_adjustments().get(pat.hir_id) {
             if let Some(first_ty) = vec.first() {
                 debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
-                return Ok(first_ty);
+                return Ok(*first_ty);
             }
         }
 
@@ -562,7 +562,7 @@ fn variant_index_for_adt(
             Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
             | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
             | Res::SelfCtor(..)
-            | Res::SelfTy(..) => {
+            | Res::SelfTy { .. } => {
                 // Structs and Unions have only have one variant.
                 Ok(VariantIdx::new(0))
             }
index 78a9cb33fbac5e95504ef1176165abc19ddf3812..139be8a42de7ed91dd6a187c5d6253432f0181fe 100644 (file)
@@ -105,14 +105,14 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
                     match kind1.unpack() {
                         GenericArgKind::Type(ty1) => Some((
                             ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
-                                ty::OutlivesPredicate(ty1, region2),
+                                ty::OutlivesPredicate(ty1, *region2),
                             ))
                             .to_predicate(tcx),
                             span,
                         )),
                         GenericArgKind::Lifetime(region1) => Some((
                             ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
-                                ty::OutlivesPredicate(region1, region2),
+                                ty::OutlivesPredicate(region1, *region2),
                             ))
                             .to_predicate(tcx),
                             span,
index 76ae2ee43566e9d0ac28a7cf6c49fca342159d70..54a5037b57578da53aef14b2d097af3ddc51556b 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, Region, RegionKind, Ty, TyCtxt};
+use rustc_middle::ty::{self, Region, Ty, TyCtxt};
 use rustc_span::Span;
 use smallvec::smallvec;
 use std::collections::BTreeMap;
@@ -133,7 +133,7 @@ pub fn insert_outlives_predicate<'tcx>(
 
 fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool {
     // First, screen for regions that might appear in a type header.
-    match region {
+    match *region {
         // These correspond to `T: 'a` relationships:
         //
         //     struct Foo<'a, T> {
@@ -141,7 +141,7 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool {
         //     }
         //
         // We care about these, so fall through.
-        RegionKind::ReEarlyBound(_) => true,
+        ty::ReEarlyBound(_) => true,
 
         // These correspond to `T: 'static` relationships which can be
         // rather surprising. We are therefore putting this behind a
@@ -150,7 +150,7 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool {
         //     struct Foo<'a, T> {
         //         field: &'static T, // this would generate a ReStatic
         //     }
-        RegionKind::ReStatic => tcx.sess.features_untracked().infer_static_outlives_requirements,
+        ty::ReStatic => tcx.sess.features_untracked().infer_static_outlives_requirements,
 
         // Late-bound regions can appear in `fn` types:
         //
@@ -160,19 +160,16 @@ fn is_free_region(tcx: TyCtxt<'_>, region: Region<'_>) -> bool {
         //
         // The type above might generate a `T: 'b` bound, but we can
         // ignore it.  We can't put it on the struct header anyway.
-        RegionKind::ReLateBound(..) => false,
+        ty::ReLateBound(..) => false,
 
         // This can appear in `where Self: ` bounds (#64855):
         //
         //     struct Bar<T>(<Self as Foo>::Type) where Self: ;
         //     struct Baz<'a>(&'a Self) where Self: ;
-        RegionKind::ReEmpty(_) => false,
+        ty::ReEmpty(_) => false,
 
         // These regions don't appear in types from type declarations:
-        RegionKind::ReErased
-        | RegionKind::ReVar(..)
-        | RegionKind::RePlaceholder(..)
-        | RegionKind::ReFree(..) => {
+        ty::ReErased | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReFree(..) => {
             bug!("unexpected region in outlives inference: {:?}", region);
         }
     }
index 7c504a0d89c59aa98b6348a0d7aa55a48bd9390d..1c8f848cf2893187c9ae70f14649cf75534b1e27 100644 (file)
@@ -401,12 +401,12 @@ fn add_constraints_from_substs(
     fn add_constraints_from_const(
         &mut self,
         current: &CurrentItem,
-        val: &ty::Const<'tcx>,
+        val: ty::Const<'tcx>,
         variance: VarianceTermPtr<'a>,
     ) {
         debug!("add_constraints_from_const(val={:?}, variance={:?})", val, variance);
 
-        match &val.val {
+        match &val.val() {
             ty::ConstKind::Unevaluated(uv) => {
                 self.add_constraints_from_invariant_substs(current, uv.substs, variance);
             }
index f24f8e81a7944ef4a49483a93abdfcb50d6ef037..ad48cc881f3e665252869c0b9b02b40450312ff4 100644 (file)
@@ -157,6 +157,9 @@ changelog-seen = 2
 # Whether to build the clang compiler.
 #clang = false
 
+# Custom CMake defines to set when building LLVM.
+#build-config = {}
+
 # =============================================================================
 # General build configuration options
 # =============================================================================
@@ -289,7 +292,7 @@ changelog-seen = 2
 #sanitizers = false
 
 # Build the profiler runtime (required when compiling with options that depend
-# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`).
+# on this runtime, such as `-C profile-generate` or `-C instrument-coverage`).
 #profiler = false
 
 # Indicates whether the native libraries linked into Cargo will be statically
@@ -671,7 +674,7 @@ changelog-seen = 2
 #sanitizers = build.sanitizers (bool)
 
 # Build the profiler runtime for this target(required when compiling with options that depend
-# on this runtime, such as `-C profile-generate` or `-Z instrument-coverage`).
+# on this runtime, such as `-C profile-generate` or `-C instrument-coverage`).
 # This option will override the same option under [build] section.
 #profiler = build.profiler (bool)
 
index d075658f51a3e7b3fb7c46df8619787e77b6b68b..9d4f9af91a5e19712ed254b4a88e6b9655b58e74 100644 (file)
@@ -348,7 +348,6 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
     // This is the magic symbol to call the global alloc error handler.  rustc generates
     // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
     // default implementations below (`__rdl_oom`) otherwise.
-    #[rustc_allocator_nounwind]
     fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
 }
 
@@ -367,7 +366,6 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
 #[stable(feature = "global_alloc", since = "1.28.0")]
 #[rustc_const_unstable(feature = "const_alloc_error", issue = "92523")]
 #[cfg(all(not(no_global_oom_handling), not(test)))]
-#[rustc_allocator_nounwind]
 #[cold]
 pub const fn handle_alloc_error(layout: Layout) -> ! {
     const fn ct_error(_: Layout) -> ! {
@@ -398,13 +396,13 @@ pub mod __alloc_error_handler {
 
     // if there is no `#[alloc_error_handler]`
     #[rustc_std_internal_symbol]
-    pub unsafe extern "C" fn __rdl_oom(size: usize, _align: usize) -> ! {
+    pub unsafe extern "C-unwind" fn __rdl_oom(size: usize, _align: usize) -> ! {
         panic!("memory allocation of {} bytes failed", size)
     }
 
     // if there is an `#[alloc_error_handler]`
     #[rustc_std_internal_symbol]
-    pub unsafe extern "C" fn __rg_oom(size: usize, align: usize) -> ! {
+    pub unsafe extern "C-unwind" fn __rg_oom(size: usize, align: usize) -> ! {
         let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
         extern "Rust" {
             #[lang = "oom"]
index cdb961d4cfbc5e697ebf49635231e5959aca84a3..67f5b386ecd7fd05a58f1baccabb51695e863853 100644 (file)
@@ -2052,6 +2052,8 @@ fn index(&self, key: &Q) -> &V {
 
 #[stable(feature = "std_collections_from_array", since = "1.56.0")]
 impl<K: Ord, V, const N: usize> From<[(K, V); N]> for BTreeMap<K, V> {
+    /// Converts a `[(K, V); N]` into a `BTreeMap<(K, V)>`.
+    ///
     /// ```
     /// use std::collections::BTreeMap;
     ///
index 31df4e98ed746884fca583ba22b16855cd476406..a4315be74e36c27bea4195f1d80574042e089a85 100644 (file)
@@ -1097,6 +1097,8 @@ fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> BTreeSet<T> {
 
 #[stable(feature = "std_collections_from_array", since = "1.56.0")]
 impl<T: Ord, const N: usize> From<[T; N]> for BTreeSet<T> {
+    /// Converts a `[T; N]` into a `BTreeSet<T>`.
+    ///
     /// ```
     /// use std::collections::BTreeSet;
     ///
index 4a07d5d4bed10aa2efb84907cde4c220a0972188..d81f24e72024d5ea7688ca30fd44e5cbffb8386b 100644 (file)
@@ -1953,6 +1953,8 @@ fn hash<H: Hasher>(&self, state: &mut H) {
 
 #[stable(feature = "std_collections_from_array", since = "1.56.0")]
 impl<T, const N: usize> From<[T; N]> for LinkedList<T> {
+    /// Converts a `[T; N]` into a `LinkedList<T>`.
+    ///
     /// ```
     /// use std::collections::LinkedList;
     ///
index a8a18d655855eb117585ae9b094b1084f1d9c53e..763175fc0451f07861189357e870bd8b91496e1b 100644 (file)
@@ -1,4 +1,4 @@
-//! A double-ended queue implemented with a growable ring buffer.
+//! A double-ended queue (deque) implemented with a growable ring buffer.
 //!
 //! This queue has *O*(1) amortized inserts and removals from both ends of the
 //! container. It also has *O*(1) indexing like a vector. The contained elements
@@ -156,7 +156,7 @@ fn drop(&mut self) {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> Default for VecDeque<T> {
-    /// Creates an empty `VecDeque<T>`.
+    /// Creates an empty deque.
     #[inline]
     fn default() -> VecDeque<T> {
         VecDeque::new()
@@ -483,14 +483,14 @@ unsafe fn handle_capacity_increase(&mut self, old_capacity: usize) {
 }
 
 impl<T> VecDeque<T> {
-    /// Creates an empty `VecDeque`.
+    /// Creates an empty deque.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let vector: VecDeque<u32> = VecDeque::new();
+    /// let deque: VecDeque<u32> = VecDeque::new();
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -499,14 +499,14 @@ pub fn new() -> VecDeque<T> {
         VecDeque::new_in(Global)
     }
 
-    /// Creates an empty `VecDeque` with space for at least `capacity` elements.
+    /// Creates an empty deque with space for at least `capacity` elements.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let vector: VecDeque<u32> = VecDeque::with_capacity(10);
+    /// let deque: VecDeque<u32> = VecDeque::with_capacity(10);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -517,14 +517,14 @@ pub fn with_capacity(capacity: usize) -> VecDeque<T> {
 }
 
 impl<T, A: Allocator> VecDeque<T, A> {
-    /// Creates an empty `VecDeque`.
+    /// Creates an empty deque.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let vector: VecDeque<u32> = VecDeque::new();
+    /// let deque: VecDeque<u32> = VecDeque::new();
     /// ```
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
@@ -532,14 +532,14 @@ pub fn new_in(alloc: A) -> VecDeque<T, A> {
         VecDeque::with_capacity_in(INITIAL_CAPACITY, alloc)
     }
 
-    /// Creates an empty `VecDeque` with space for at least `capacity` elements.
+    /// Creates an empty deque with space for at least `capacity` elements.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let vector: VecDeque<u32> = VecDeque::with_capacity(10);
+    /// let deque: VecDeque<u32> = VecDeque::with_capacity(10);
     /// ```
     #[unstable(feature = "allocator_api", issue = "32838")]
     pub fn with_capacity_in(capacity: usize, alloc: A) -> VecDeque<T, A> {
@@ -636,7 +636,7 @@ pub fn swap(&mut self, i: usize, j: usize) {
         unsafe { ptr::swap(self.ptr().add(ri), self.ptr().add(rj)) }
     }
 
-    /// Returns the number of elements the `VecDeque` can hold without
+    /// Returns the number of elements the deque can hold without
     /// reallocating.
     ///
     /// # Examples
@@ -654,7 +654,7 @@ pub fn capacity(&self) -> usize {
     }
 
     /// Reserves the minimum capacity for exactly `additional` more elements to be inserted in the
-    /// given `VecDeque`. Does nothing if the capacity is already sufficient.
+    /// given deque. Does nothing if the capacity is already sufficient.
     ///
     /// Note that the allocator may give the collection more space than it requests. Therefore
     /// capacity can not be relied upon to be precisely minimal. Prefer [`reserve`] if future
@@ -681,7 +681,7 @@ pub fn reserve_exact(&mut self, additional: usize) {
     }
 
     /// Reserves capacity for at least `additional` more elements to be inserted in the given
-    /// `VecDeque`. The collection may reserve more space to avoid frequent reallocations.
+    /// deque. The collection may reserve more space to avoid frequent reallocations.
     ///
     /// # Panics
     ///
@@ -714,7 +714,7 @@ pub fn reserve(&mut self, additional: usize) {
     }
 
     /// Tries to reserve the minimum capacity for exactly `additional` more elements to
-    /// be inserted in the given `VecDeque<T>`. After calling `try_reserve_exact`,
+    /// be inserted in the given deque. After calling `try_reserve_exact`,
     /// capacity will be greater than or equal to `self.len() + additional`.
     /// Does nothing if the capacity is already sufficient.
     ///
@@ -756,7 +756,7 @@ pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveE
     }
 
     /// Tries to reserve capacity for at least `additional` more elements to be inserted
-    /// in the given `VecDeque<T>`. The collection may reserve more space to avoid
+    /// in the given deque. The collection may reserve more space to avoid
     /// frequent reallocations. After calling `try_reserve`, capacity will be
     /// greater than or equal to `self.len() + additional`. Does nothing if
     /// capacity is already sufficient.
@@ -805,10 +805,10 @@ pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>
         Ok(())
     }
 
-    /// Shrinks the capacity of the `VecDeque` as much as possible.
+    /// Shrinks the capacity of the deque as much as possible.
     ///
     /// It will drop down as close as possible to the length but the allocator may still inform the
-    /// `VecDeque` that there is space for a few more elements.
+    /// deque that there is space for a few more elements.
     ///
     /// # Examples
     ///
@@ -826,7 +826,7 @@ pub fn shrink_to_fit(&mut self) {
         self.shrink_to(0);
     }
 
-    /// Shrinks the capacity of the `VecDeque` with a lower bound.
+    /// Shrinks the capacity of the deque with a lower bound.
     ///
     /// The capacity will remain at least as large as both the length
     /// and the supplied value.
@@ -909,10 +909,10 @@ pub fn shrink_to(&mut self, min_capacity: usize) {
         }
     }
 
-    /// Shortens the `VecDeque`, keeping the first `len` elements and dropping
+    /// Shortens the deque, keeping the first `len` elements and dropping
     /// the rest.
     ///
-    /// If `len` is greater than the `VecDeque`'s current length, this has no
+    /// If `len` is greater than the deque's current length, this has no
     /// effect.
     ///
     /// # Examples
@@ -1027,10 +1027,10 @@ pub fn iter_mut(&mut self) -> IterMut<'_, T> {
     }
 
     /// Returns a pair of slices which contain, in order, the contents of the
-    /// `VecDeque`.
+    /// deque.
     ///
     /// If [`make_contiguous`] was previously called, all elements of the
-    /// `VecDeque` will be in the first slice and the second slice will be empty.
+    /// deque will be in the first slice and the second slice will be empty.
     ///
     /// [`make_contiguous`]: VecDeque::make_contiguous
     ///
@@ -1039,18 +1039,18 @@ pub fn iter_mut(&mut self) -> IterMut<'_, T> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut vector = VecDeque::new();
+    /// let mut deque = VecDeque::new();
     ///
-    /// vector.push_back(0);
-    /// vector.push_back(1);
-    /// vector.push_back(2);
+    /// deque.push_back(0);
+    /// deque.push_back(1);
+    /// deque.push_back(2);
     ///
-    /// assert_eq!(vector.as_slices(), (&[0, 1, 2][..], &[][..]));
+    /// assert_eq!(deque.as_slices(), (&[0, 1, 2][..], &[][..]));
     ///
-    /// vector.push_front(10);
-    /// vector.push_front(9);
+    /// deque.push_front(10);
+    /// deque.push_front(9);
     ///
-    /// assert_eq!(vector.as_slices(), (&[9, 10][..], &[0, 1, 2][..]));
+    /// assert_eq!(deque.as_slices(), (&[9, 10][..], &[0, 1, 2][..]));
     /// ```
     #[inline]
     #[stable(feature = "deque_extras_15", since = "1.5.0")]
@@ -1062,10 +1062,10 @@ pub fn as_slices(&self) -> (&[T], &[T]) {
     }
 
     /// Returns a pair of slices which contain, in order, the contents of the
-    /// `VecDeque`.
+    /// deque.
     ///
     /// If [`make_contiguous`] was previously called, all elements of the
-    /// `VecDeque` will be in the first slice and the second slice will be empty.
+    /// deque will be in the first slice and the second slice will be empty.
     ///
     /// [`make_contiguous`]: VecDeque::make_contiguous
     ///
@@ -1074,17 +1074,17 @@ pub fn as_slices(&self) -> (&[T], &[T]) {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut vector = VecDeque::new();
+    /// let mut deque = VecDeque::new();
     ///
-    /// vector.push_back(0);
-    /// vector.push_back(1);
+    /// deque.push_back(0);
+    /// deque.push_back(1);
     ///
-    /// vector.push_front(10);
-    /// vector.push_front(9);
+    /// deque.push_front(10);
+    /// deque.push_front(9);
     ///
-    /// vector.as_mut_slices().0[0] = 42;
-    /// vector.as_mut_slices().1[0] = 24;
-    /// assert_eq!(vector.as_slices(), (&[42, 10][..], &[24, 1][..]));
+    /// deque.as_mut_slices().0[0] = 42;
+    /// deque.as_mut_slices().1[0] = 24;
+    /// assert_eq!(deque.as_slices(), (&[42, 10][..], &[24, 1][..]));
     /// ```
     #[inline]
     #[stable(feature = "deque_extras_15", since = "1.5.0")]
@@ -1097,34 +1097,34 @@ pub fn as_mut_slices(&mut self) -> (&mut [T], &mut [T]) {
         }
     }
 
-    /// Returns the number of elements in the `VecDeque`.
+    /// Returns the number of elements in the deque.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut v = VecDeque::new();
-    /// assert_eq!(v.len(), 0);
-    /// v.push_back(1);
-    /// assert_eq!(v.len(), 1);
+    /// let mut deque = VecDeque::new();
+    /// assert_eq!(deque.len(), 0);
+    /// deque.push_back(1);
+    /// assert_eq!(deque.len(), 1);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn len(&self) -> usize {
         count(self.tail, self.head, self.cap())
     }
 
-    /// Returns `true` if the `VecDeque` is empty.
+    /// Returns `true` if the deque is empty.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut v = VecDeque::new();
-    /// assert!(v.is_empty());
-    /// v.push_front(1);
-    /// assert!(!v.is_empty());
+    /// let mut deque = VecDeque::new();
+    /// assert!(deque.is_empty());
+    /// deque.push_front(1);
+    /// assert!(!deque.is_empty());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_empty(&self) -> bool {
@@ -1141,24 +1141,24 @@ fn range_tail_head<R>(&self, range: R) -> (usize, usize)
         (tail, head)
     }
 
-    /// Creates an iterator that covers the specified range in the `VecDeque`.
+    /// Creates an iterator that covers the specified range in the deque.
     ///
     /// # Panics
     ///
     /// Panics if the starting point is greater than the end point or if
-    /// the end point is greater than the length of the vector.
+    /// the end point is greater than the length of the deque.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let v: VecDeque<_> = [1, 2, 3].into();
-    /// let range = v.range(2..).copied().collect::<VecDeque<_>>();
+    /// let deque: VecDeque<_> = [1, 2, 3].into();
+    /// let range = deque.range(2..).copied().collect::<VecDeque<_>>();
     /// assert_eq!(range, [3]);
     ///
     /// // A full range covers all contents
-    /// let all = v.range(..);
+    /// let all = deque.range(..);
     /// assert_eq!(all.len(), 3);
     /// ```
     #[inline]
@@ -1176,29 +1176,29 @@ pub fn range<R>(&self, range: R) -> Iter<'_, T>
         }
     }
 
-    /// Creates an iterator that covers the specified mutable range in the `VecDeque`.
+    /// Creates an iterator that covers the specified mutable range in the deque.
     ///
     /// # Panics
     ///
     /// Panics if the starting point is greater than the end point or if
-    /// the end point is greater than the length of the vector.
+    /// the end point is greater than the length of the deque.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut v: VecDeque<_> = [1, 2, 3].into();
-    /// for v in v.range_mut(2..) {
+    /// let mut deque: VecDeque<_> = [1, 2, 3].into();
+    /// for v in deque.range_mut(2..) {
     ///   *v *= 2;
     /// }
-    /// assert_eq!(v, [1, 2, 6]);
+    /// assert_eq!(deque, [1, 2, 6]);
     ///
     /// // A full range covers all contents
-    /// for v in v.range_mut(..) {
+    /// for v in deque.range_mut(..) {
     ///   *v *= 2;
     /// }
-    /// assert_eq!(v, [2, 4, 12]);
+    /// assert_eq!(deque, [2, 4, 12]);
     /// ```
     #[inline]
     #[stable(feature = "deque_range", since = "1.51.0")]
@@ -1216,7 +1216,7 @@ pub fn range_mut<R>(&mut self, range: R) -> IterMut<'_, T>
     }
 
     /// Creates a draining iterator that removes the specified range in the
-    /// `VecDeque` and yields the removed items.
+    /// deque and yields the removed items.
     ///
     /// Note 1: The element range is removed even if the iterator is not
     /// consumed until the end.
@@ -1228,21 +1228,21 @@ pub fn range_mut<R>(&mut self, range: R) -> IterMut<'_, T>
     /// # Panics
     ///
     /// Panics if the starting point is greater than the end point or if
-    /// the end point is greater than the length of the vector.
+    /// the end point is greater than the length of the deque.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut v: VecDeque<_> = [1, 2, 3].into();
-    /// let drained = v.drain(2..).collect::<VecDeque<_>>();
+    /// let mut deque: VecDeque<_> = [1, 2, 3].into();
+    /// let drained = deque.drain(2..).collect::<VecDeque<_>>();
     /// assert_eq!(drained, [3]);
-    /// assert_eq!(v, [1, 2]);
+    /// assert_eq!(deque, [1, 2]);
     ///
     /// // A full range clears all contents
-    /// v.drain(..);
-    /// assert!(v.is_empty());
+    /// deque.drain(..);
+    /// assert!(deque.is_empty());
     /// ```
     #[inline]
     #[stable(feature = "drain", since = "1.6.0")]
@@ -1297,17 +1297,17 @@ pub fn drain<R>(&mut self, range: R) -> Drain<'_, T, A>
         unsafe { Drain::new(drain_head, head, iter, deque) }
     }
 
-    /// Clears the `VecDeque`, removing all values.
+    /// Clears the deque, removing all values.
     ///
     /// # Examples
     ///
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut v = VecDeque::new();
-    /// v.push_back(1);
-    /// v.clear();
-    /// assert!(v.is_empty());
+    /// let mut deque = VecDeque::new();
+    /// deque.push_back(1);
+    /// deque.clear();
+    /// assert!(deque.is_empty());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
@@ -1315,7 +1315,7 @@ pub fn clear(&mut self) {
         self.truncate(0);
     }
 
-    /// Returns `true` if the `VecDeque` contains an element equal to the
+    /// Returns `true` if the deque contains an element equal to the
     /// given value.
     ///
     /// # Examples
@@ -1323,13 +1323,13 @@ pub fn clear(&mut self) {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut vector: VecDeque<u32> = VecDeque::new();
+    /// let mut deque: VecDeque<u32> = VecDeque::new();
     ///
-    /// vector.push_back(0);
-    /// vector.push_back(1);
+    /// deque.push_back(0);
+    /// deque.push_back(1);
     ///
-    /// assert_eq!(vector.contains(&1), true);
-    /// assert_eq!(vector.contains(&10), false);
+    /// assert_eq!(deque.contains(&1), true);
+    /// assert_eq!(deque.contains(&10), false);
     /// ```
     #[stable(feature = "vec_deque_contains", since = "1.12.0")]
     pub fn contains(&self, x: &T) -> bool
@@ -1340,7 +1340,7 @@ pub fn contains(&self, x: &T) -> bool
         a.contains(x) || b.contains(x)
     }
 
-    /// Provides a reference to the front element, or `None` if the `VecDeque` is
+    /// Provides a reference to the front element, or `None` if the deque is
     /// empty.
     ///
     /// # Examples
@@ -1361,7 +1361,7 @@ pub fn front(&self) -> Option<&T> {
     }
 
     /// Provides a mutable reference to the front element, or `None` if the
-    /// `VecDeque` is empty.
+    /// deque is empty.
     ///
     /// # Examples
     ///
@@ -1384,7 +1384,7 @@ pub fn front_mut(&mut self) -> Option<&mut T> {
         self.get_mut(0)
     }
 
-    /// Provides a reference to the back element, or `None` if the `VecDeque` is
+    /// Provides a reference to the back element, or `None` if the deque is
     /// empty.
     ///
     /// # Examples
@@ -1405,7 +1405,7 @@ pub fn back(&self) -> Option<&T> {
     }
 
     /// Provides a mutable reference to the back element, or `None` if the
-    /// `VecDeque` is empty.
+    /// deque is empty.
     ///
     /// # Examples
     ///
@@ -1428,7 +1428,7 @@ pub fn back_mut(&mut self) -> Option<&mut T> {
         self.get_mut(self.len().wrapping_sub(1))
     }
 
-    /// Removes the first element and returns it, or `None` if the `VecDeque` is
+    /// Removes the first element and returns it, or `None` if the deque is
     /// empty.
     ///
     /// # Examples
@@ -1455,7 +1455,7 @@ pub fn pop_front(&mut self) -> Option<T> {
         }
     }
 
-    /// Removes the last element from the `VecDeque` and returns it, or `None` if
+    /// Removes the last element from the deque and returns it, or `None` if
     /// it is empty.
     ///
     /// # Examples
@@ -1480,7 +1480,7 @@ pub fn pop_back(&mut self) -> Option<T> {
         }
     }
 
-    /// Prepends an element to the `VecDeque`.
+    /// Prepends an element to the deque.
     ///
     /// # Examples
     ///
@@ -1505,7 +1505,7 @@ pub fn push_front(&mut self, value: T) {
         }
     }
 
-    /// Appends an element to the back of the `VecDeque`.
+    /// Appends an element to the back of the deque.
     ///
     /// # Examples
     ///
@@ -1535,7 +1535,7 @@ fn is_contiguous(&self) -> bool {
         self.tail <= self.head
     }
 
-    /// Removes an element from anywhere in the `VecDeque` and returns it,
+    /// Removes an element from anywhere in the deque and returns it,
     /// replacing it with the first element.
     ///
     /// This does not preserve ordering, but is *O*(1).
@@ -1570,8 +1570,8 @@ pub fn swap_remove_front(&mut self, index: usize) -> Option<T> {
         self.pop_front()
     }
 
-    /// Removes an element from anywhere in the `VecDeque` and returns it, replacing it with the
-    /// last element.
+    /// Removes an element from anywhere in the deque and returns it,
+    /// replacing it with the last element.
     ///
     /// This does not preserve ordering, but is *O*(1).
     ///
@@ -1605,14 +1605,14 @@ pub fn swap_remove_back(&mut self, index: usize) -> Option<T> {
         self.pop_back()
     }
 
-    /// Inserts an element at `index` within the `VecDeque`, shifting all elements with indices
-    /// greater than or equal to `index` towards the back.
+    /// Inserts an element at `index` within the deque, shifting all elements
+    /// with indices greater than or equal to `index` towards the back.
     ///
     /// Element at index 0 is the front of the queue.
     ///
     /// # Panics
     ///
-    /// Panics if `index` is greater than `VecDeque`'s length
+    /// Panics if `index` is greater than deque's length
     ///
     /// # Examples
     ///
@@ -1829,7 +1829,7 @@ pub fn insert(&mut self, index: usize, value: T) {
         }
     }
 
-    /// Removes and returns the element at `index` from the `VecDeque`.
+    /// Removes and returns the element at `index` from the deque.
     /// Whichever end is closer to the removal point will be moved to make
     /// room, and all the affected elements will be moved to new positions.
     /// Returns `None` if `index` is out of bounds.
@@ -2007,10 +2007,10 @@ pub fn remove(&mut self, index: usize) -> Option<T> {
         elem
     }
 
-    /// Splits the `VecDeque` into two at the given index.
+    /// Splits the deque into two at the given index.
     ///
     /// Returns a newly allocated `VecDeque`. `self` contains elements `[0, at)`,
-    /// and the returned `VecDeque` contains elements `[at, len)`.
+    /// and the returned deque contains elements `[at, len)`.
     ///
     /// Note that the capacity of `self` does not change.
     ///
@@ -2227,7 +2227,7 @@ fn grow(&mut self) {
         debug_assert!(!self.is_full());
     }
 
-    /// Modifies the `VecDeque` in-place so that `len()` is equal to `new_len`,
+    /// Modifies the deque in-place so that `len()` is equal to `new_len`,
     /// either by removing excess elements from the back or by appending
     /// elements generated by calling `generator` to the back.
     ///
@@ -2272,7 +2272,7 @@ pub fn resize_with(&mut self, new_len: usize, generator: impl FnMut() -> T) {
     ///
     /// Once the internal storage is contiguous, the [`as_slices`] and
     /// [`as_mut_slices`] methods will return the entire contents of the
-    /// `VecDeque` in a single slice.
+    /// deque in a single slice.
     ///
     /// [`as_slices`]: VecDeque::as_slices
     /// [`as_mut_slices`]: VecDeque::as_mut_slices
@@ -2524,7 +2524,7 @@ unsafe fn rotate_right_inner(&mut self, k: usize) {
         }
     }
 
-    /// Binary searches this sorted `VecDeque` for a given element.
+    /// Binary searches the sorted deque for a given element.
     ///
     /// If the value is found then [`Result::Ok`] is returned, containing the
     /// index of the matching element. If there are multiple matches, then any
@@ -2556,7 +2556,7 @@ unsafe fn rotate_right_inner(&mut self, k: usize) {
     /// assert!(matches!(r, Ok(1..=4)));
     /// ```
     ///
-    /// If you want to insert an item to a sorted `VecDeque`, while maintaining
+    /// If you want to insert an item to a sorted deque, while maintaining
     /// sort order:
     ///
     /// ```
@@ -2577,12 +2577,12 @@ pub fn binary_search(&self, x: &T) -> Result<usize, usize>
         self.binary_search_by(|e| e.cmp(x))
     }
 
-    /// Binary searches this sorted `VecDeque` with a comparator function.
+    /// Binary searches the sorted deque with a comparator function.
     ///
     /// The comparator function should implement an order consistent
-    /// with the sort order of the underlying `VecDeque`, returning an
-    /// order code that indicates whether its argument is `Less`,
-    /// `Equal` or `Greater` than the desired target.
+    /// with the sort order of the deque, returning an order code that
+    /// indicates whether its argument is `Less`, `Equal` or `Greater`
+    /// than the desired target.
     ///
     /// If the value is found then [`Result::Ok`] is returned, containing the
     /// index of the matching element. If there are multiple matches, then any
@@ -2630,9 +2630,9 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
         }
     }
 
-    /// Binary searches this sorted `VecDeque` with a key extraction function.
+    /// Binary searches the sorted deque with a key extraction function.
     ///
-    /// Assumes that the `VecDeque` is sorted by the key, for instance with
+    /// Assumes that the deque is sorted by the key, for instance with
     /// [`make_contiguous().sort_by_key()`] using the same key extraction function.
     ///
     /// If the value is found then [`Result::Ok`] is returned, containing the
@@ -2687,7 +2687,7 @@ pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize
     /// For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0
     /// (all odd numbers are at the start, all even at the end).
     ///
-    /// If this deque is not partitioned, the returned result is unspecified and meaningless,
+    /// If the deque is not partitioned, the returned result is unspecified and meaningless,
     /// as this method performs a kind of binary search.
     ///
     /// See also [`binary_search`], [`binary_search_by`], and [`binary_search_by_key`].
@@ -2724,7 +2724,7 @@ pub fn partition_point<P>(&self, mut pred: P) -> usize
 }
 
 impl<T: Clone, A: Allocator> VecDeque<T, A> {
-    /// Modifies the `VecDeque` in-place so that `len()` is equal to new_len,
+    /// Modifies the deque in-place so that `len()` is equal to new_len,
     /// either by removing excess elements from the back or by appending clones of `value`
     /// to the back.
     ///
@@ -2878,7 +2878,7 @@ impl<T, A: Allocator> IntoIterator for VecDeque<T, A> {
     type Item = T;
     type IntoIter = IntoIter<T, A>;
 
-    /// Consumes the `VecDeque` into a front-to-back iterator yielding elements by
+    /// Consumes the deque into a front-to-back iterator yielding elements by
     /// value.
     fn into_iter(self) -> IntoIter<T, A> {
         IntoIter::new(self)
@@ -3049,6 +3049,8 @@ fn from(mut other: VecDeque<T, A>) -> Self {
 
 #[stable(feature = "std_collections_from_array", since = "1.56.0")]
 impl<T, const N: usize> From<[T; N]> for VecDeque<T> {
+    /// Converts a `[T; N]` into a `VecDeque<T>`.
+    ///
     /// ```
     /// use std::collections::VecDeque;
     ///
index b4d16d74db48807c896e9437dae3d1124193b9e5..aeb7554f8e914ec1117b3cce8a35f9f16e40376b 100644 (file)
@@ -74,7 +74,7 @@
 //! identifier '=' expression
 //! ```
 //!
-//! For example, the following [`format!`] expressions all use named argument:
+//! For example, the following [`format!`] expressions all use named arguments:
 //!
 //! ```
 //! format!("{argument}", argument = "test");   // => "test"
index 5f866cc5f78630136ebb045605dd43606e28ea64..6da32df57efb761c654afbb068a99b8842de9883 100644 (file)
 #![feature(extend_one)]
 #![feature(fmt_internals)]
 #![feature(fn_traits)]
-#![feature(inherent_ascii_escape)]
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
 #![feature(layout_for_ptr)]
 #![feature(associated_type_bounds)]
 #![feature(box_syntax)]
 #![feature(cfg_sanitize)]
-#![feature(cfg_target_has_atomic)]
+#![cfg_attr(bootstrap, feature(cfg_target_has_atomic))]
 #![feature(const_deref)]
 #![feature(const_fn_trait_bound)]
 #![feature(const_mut_refs)]
 #![cfg_attr(test, feature(test))]
 #![feature(unboxed_closures)]
 #![feature(unsized_fn_params)]
+#![feature(c_unwind)]
 //
 // Rustdoc features:
 #![feature(doc_cfg)]
index 78bf28c843c7d385d4a720316c8543351600164b..3065169e5e2cbcc296c2fe748b9849d22f7b6c8c 100644 (file)
@@ -1203,6 +1203,41 @@ pub fn make_mut(this: &mut Self) -> &mut T {
         // reference to the allocation.
         unsafe { &mut this.ptr.as_mut().value }
     }
+
+    /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the
+    /// clone.
+    ///
+    /// Assuming `rc_t` is of type `Rc<T>`, this function is functionally equivalent to
+    /// `(*rc_t).clone()`, but will avoid cloning the inner value where possible.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(arc_unwrap_or_clone)]
+    /// # use std::{ptr, rc::Rc};
+    /// let inner = String::from("test");
+    /// let ptr = inner.as_ptr();
+    ///
+    /// let rc = Rc::new(inner);
+    /// let inner = Rc::unwrap_or_clone(rc);
+    /// // The inner value was not cloned
+    /// assert!(ptr::eq(ptr, inner.as_ptr()));
+    ///
+    /// let rc = Rc::new(inner);
+    /// let rc2 = rc.clone();
+    /// let inner = Rc::unwrap_or_clone(rc);
+    /// // Because there were 2 references, we had to clone the inner value.
+    /// assert!(!ptr::eq(ptr, inner.as_ptr()));
+    /// // `rc2` is the last reference, so when we unwrap it we get back
+    /// // the original `String`.
+    /// let inner = Rc::unwrap_or_clone(rc2);
+    /// assert!(ptr::eq(ptr, inner.as_ptr()));
+    /// ```
+    #[inline]
+    #[unstable(feature = "arc_unwrap_or_clone", issue = "93610")]
+    pub fn unwrap_or_clone(this: Self) -> T {
+        Rc::try_unwrap(this).unwrap_or_else(|rc| (*rc).clone())
+    }
 }
 
 impl Rc<dyn Any> {
index a5c4140e313872c0363ecd0814534d47d5fe0f03..f0397d08f95a8f4e03875c77c9eed85a197aff5c 100644 (file)
 pub use core::slice::ArrayChunksMut;
 #[unstable(feature = "array_windows", issue = "75027")]
 pub use core::slice::ArrayWindows;
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 pub use core::slice::EscapeAscii;
 #[stable(feature = "slice_get_slice", since = "1.28.0")]
 pub use core::slice::SliceIndex;
index 64f21d087da39d5d083d2c00efc5669160957b3e..7e7670aad6425fc1bc6476687a60c48ab6396961 100644 (file)
@@ -1477,6 +1477,41 @@ pub fn make_mut(this: &mut Self) -> &mut T {
         // either unique to begin with, or became one upon cloning the contents.
         unsafe { Self::get_mut_unchecked(this) }
     }
+
+    /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the
+    /// clone.
+    ///
+    /// Assuming `arc_t` is of type `Arc<T>`, this function is functionally equivalent to
+    /// `(*arc_t).clone()`, but will avoid cloning the inner value where possible.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(arc_unwrap_or_clone)]
+    /// # use std::{ptr, sync::Arc};
+    /// let inner = String::from("test");
+    /// let ptr = inner.as_ptr();
+    ///
+    /// let arc = Arc::new(inner);
+    /// let inner = Arc::unwrap_or_clone(arc);
+    /// // The inner value was not cloned
+    /// assert!(ptr::eq(ptr, inner.as_ptr()));
+    ///
+    /// let arc = Arc::new(inner);
+    /// let arc2 = arc.clone();
+    /// let inner = Arc::unwrap_or_clone(arc);
+    /// // Because there were 2 references, we had to clone the inner value.
+    /// assert!(!ptr::eq(ptr, inner.as_ptr()));
+    /// // `arc2` is the last reference, so when we unwrap it we get back
+    /// // the original `String`.
+    /// let inner = Arc::unwrap_or_clone(arc2);
+    /// assert!(ptr::eq(ptr, inner.as_ptr()));
+    /// ```
+    #[inline]
+    #[unstable(feature = "arc_unwrap_or_clone", issue = "93610")]
+    pub fn unwrap_or_clone(this: Self) -> T {
+        Arc::try_unwrap(this).unwrap_or_else(|arc| (*arc).clone())
+    }
 }
 
 impl<T: ?Sized> Arc<T> {
index bd3262b51d4807b1363a88b3b66d7519b050ea90..3dc3eee4133b6413f2bfaa4b4059b06cb585b426 100644 (file)
@@ -2906,10 +2906,6 @@ fn from(s: &mut [T]) -> Vec<T> {
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "vec_from_array", since = "1.44.0")]
 impl<T, const N: usize> From<[T; N]> for Vec<T> {
-    #[cfg(not(test))]
-    fn from(s: [T; N]) -> Vec<T> {
-        <[T]>::into_vec(box s)
-    }
     /// Allocate a `Vec<T>` and move `s`'s items into it.
     ///
     /// # Examples
@@ -2917,6 +2913,11 @@ fn from(s: &mut [T]) -> Vec<T> {
     /// ```
     /// assert_eq!(Vec::from([1, 2, 3]), vec![1, 2, 3]);
     /// ```
+    #[cfg(not(test))]
+    fn from(s: [T; N]) -> Vec<T> {
+        <[T]>::into_vec(box s)
+    }
+
     #[cfg(test)]
     fn from(s: [T; N]) -> Vec<T> {
         crate::slice::into_vec(box s)
index dcf51e3142a617924590b0f19b8739439c7fe10b..cbb86265233b0bdcc4578ffb210396b135d1f405 100644 (file)
@@ -29,6 +29,7 @@
 #![feature(binary_heap_as_slice)]
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
+#![feature(round_char_boundary)]
 #![feature(slice_group_by)]
 #![feature(slice_partition_dedup)]
 #![feature(string_remove_matches)]
index e92881b1049280cecac939629b3f1e4c4977a0b9..6b8be2506b64e5bc8d179eaae03798c003ce42f9 100644 (file)
@@ -2230,3 +2230,137 @@ fn utf8_chars() {
     assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok()));
     assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()));
 }
+
+#[test]
+fn utf8_char_counts() {
+    let strs = [("e", 1), ("é", 1), ("€", 1), ("\u{10000}", 1), ("eé€\u{10000}", 4)];
+    let mut reps =
+        [8, 64, 256, 512, 1024].iter().copied().flat_map(|n| n - 8..=n + 8).collect::<Vec<usize>>();
+    if cfg!(not(miri)) {
+        let big = 1 << 16;
+        reps.extend(big - 8..=big + 8);
+    }
+    let counts = if cfg!(miri) { 0..1 } else { 0..8 };
+    let padding = counts.map(|len| " ".repeat(len)).collect::<Vec<String>>();
+
+    for repeat in reps {
+        for (tmpl_str, tmpl_char_count) in strs {
+            for pad_start in &padding {
+                for pad_end in &padding {
+                    // Create a string with padding...
+                    let with_padding =
+                        format!("{}{}{}", pad_start, tmpl_str.repeat(repeat), pad_end);
+                    // ...and then skip past that padding. This should ensure
+                    // that we test several different alignments for both head
+                    // and tail.
+                    let si = pad_start.len();
+                    let ei = with_padding.len() - pad_end.len();
+                    let target = &with_padding[si..ei];
+
+                    assert!(!target.starts_with(" ") && !target.ends_with(" "));
+                    let expected_count = tmpl_char_count * repeat;
+                    assert_eq!(
+                        expected_count,
+                        target.chars().count(),
+                        "wrong count for `{:?}.repeat({})` (padding: `{:?}`)",
+                        tmpl_str,
+                        repeat,
+                        (pad_start.len(), pad_end.len()),
+                    );
+                }
+            }
+        }
+    }
+}
+
+#[test]
+fn floor_char_boundary() {
+    fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
+        for idx in arg {
+            assert_eq!(
+                s.floor_char_boundary(idx),
+                ret,
+                "{:?}.floor_char_boundary({:?}) != {:?}",
+                s,
+                idx,
+                ret
+            );
+        }
+    }
+
+    // edge case
+    check_many("", [0, 1, isize::MAX as usize, usize::MAX], 0);
+
+    // basic check
+    check_many("x", [0], 0);
+    check_many("x", [1, isize::MAX as usize, usize::MAX], 1);
+
+    // 1-byte chars
+    check_many("jp", [0], 0);
+    check_many("jp", [1], 1);
+    check_many("jp", 2..4, 2);
+
+    // 2-byte chars
+    check_many("ĵƥ", 0..2, 0);
+    check_many("ĵƥ", 2..4, 2);
+    check_many("ĵƥ", 4..6, 4);
+
+    // 3-byte chars
+    check_many("日本", 0..3, 0);
+    check_many("日本", 3..6, 3);
+    check_many("日本", 6..8, 6);
+
+    // 4-byte chars
+    check_many("🇯🇵", 0..4, 0);
+    check_many("🇯🇵", 4..8, 4);
+    check_many("🇯🇵", 8..10, 8);
+}
+
+#[test]
+fn ceil_char_boundary() {
+    fn check_many(s: &str, arg: impl IntoIterator<Item = usize>, ret: usize) {
+        for idx in arg {
+            assert_eq!(
+                s.ceil_char_boundary(idx),
+                ret,
+                "{:?}.ceil_char_boundary({:?}) != {:?}",
+                s,
+                idx,
+                ret
+            );
+        }
+    }
+
+    // edge case
+    check_many("", [0], 0);
+
+    // basic check
+    check_many("x", [0], 0);
+    check_many("x", [1], 1);
+
+    // 1-byte chars
+    check_many("jp", [0], 0);
+    check_many("jp", [1], 1);
+    check_many("jp", [2], 2);
+
+    // 2-byte chars
+    check_many("ĵƥ", 0..=0, 0);
+    check_many("ĵƥ", 1..=2, 2);
+    check_many("ĵƥ", 3..=4, 4);
+
+    // 3-byte chars
+    check_many("日本", 0..=0, 0);
+    check_many("日本", 1..=3, 3);
+    check_many("日本", 4..=6, 6);
+
+    // 4-byte chars
+    check_many("🇯🇵", 0..=0, 0);
+    check_many("🇯🇵", 1..=4, 4);
+    check_many("🇯🇵", 5..=8, 8);
+}
+
+#[test]
+#[should_panic]
+fn ceil_char_boundary_above_len_panic() {
+    let _ = "x".ceil_char_boundary(2);
+}
index 6bc4ba3cc0edf24dd75e18062d636c6debb1315b..6a0c6cd961d262a89994dab1cdb09588cc12a0f7 100644 (file)
@@ -6,6 +6,8 @@ repository = "https://github.com/rust-lang/rust.git"
 description = "The Rust Core Library"
 autotests = false
 autobenches = false
+# If you update this, be sure to update it in a bunch of other places too!
+# As of 2022, it was the ci/pgo.sh script and the core-no-fp-fmt-parse test.
 edition = "2021"
 
 [lib]
index 1527aa0bd6640c801db94af36b73e883cf15fdad..78865d81fb90c3f965e3d061d11d38f387fdb55f 100644 (file)
@@ -1,33 +1,10 @@
 use std::str;
 use test::{black_box, Bencher};
 
-const LOREM_SHORT: &str = "Lorem ipsum";
-
-const LOREM: &str = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.
-Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
-Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
-Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
-Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.
-At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur";
-
-const EMOJI: &str = "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗☺😚😙🥲😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😶‍🌫️😏😒🙄😬😮‍💨🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵😵‍💫🤯🤠🥳🥸😎🤓🧐😕😟🙁☹😮😯😲😳🥺😦😧😨😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬😈👿💀☠💩🤡👹👺👻👽👾🤖😺😸😹😻😼😽🙀😿😾🙈🙉🙊💋💌💘💝💖💗💓💞💕💟❣💔❤️‍🔥❤️‍🩹❤🧡💛💚💙💜🤎🖤🤍💯💢💥💫💦💨🕳💣💬👁️‍🗨️🗨🗯💭💤👋🤚🖐✋🖖👌🤌🤏✌🤞🤟🤘🤙👈👉👆🖕👇☝👍👎✊👊🤛🤜👏🙌👐🤲🤝🙏✍💅🤳💪🦾🦿🦵🦶👂🦻👃🧠🫀🫁🦷🦴👀👁👅👄👶🧒👦👧🧑👱👨🧔🧔‍♂️🧔‍♀️👨‍🦰👨‍🦱👨‍🦳👨‍🦲👩👩‍🦰🧑‍🦰👩‍🦱🧑‍🦱👩‍🦳🧑‍🦳👩‍🦲🧑‍🦲👱‍♀️👱‍♂️🧓👴👵🙍🙍‍♂️🙍‍♀️🙎🙎‍♂️🙎‍♀️🙅🙅‍♂️🙅‍♀️🙆🙆‍♂️🙆‍♀️💁💁‍♂️💁‍♀️🙋🙋‍♂️🙋‍♀️🧏🧏‍♂️🧏‍♀️🙇🙇‍♂️🙇‍♀️🤦🤦‍♂️🤦‍♀️🤷🤷‍♂️🤷‍♀️🧑‍⚕️👨‍⚕️👩‍⚕️🧑‍🎓👨‍🎓👩‍🎓🧑‍🏫👨‍🏫👩‍🏫🧑‍⚖️👨‍⚖️👩‍⚖️🧑‍🌾👨‍🌾👩‍🌾🧑‍🍳👨‍🍳👩‍🍳🧑‍🔧👨‍🔧👩‍🔧🧑‍🏭👨‍🏭👩‍🏭🧑‍💼👨‍💼👩‍💼🧑‍🔬👨‍🔬👩‍🔬🧑‍💻👨‍💻👩‍💻🧑‍🎤👨‍🎤👩‍🎤🧑‍🎨👨‍🎨👩‍🎨🧑‍✈️👨‍✈️👩‍✈️🧑‍🚀👨‍🚀👩‍🚀🧑‍🚒👨‍🚒👩‍🚒👮👮‍♂️👮‍♀️🕵🕵️‍♂️🕵️‍♀️💂💂‍♂️💂‍♀️🥷👷👷‍♂️👷‍♀️🤴👸👳👳‍♂️👳‍♀️👲🧕🤵🤵‍♂️🤵‍♀️👰👰‍♂️👰‍♀️🤰🤱👩‍🍼👨‍🍼🧑‍🍼👼🎅🤶🧑‍🎄🦸🦸‍♂️🦸‍♀️🦹🦹‍♂️🦹‍♀️🧙🧙‍♂️🧙‍♀️🧚🧚‍♂️🧚‍♀️🧛🧛‍♂️🧛‍♀️🧜🧜‍♂️🧜‍♀️🧝🧝‍♂️🧝‍♀️🧞🧞‍♂️🧞‍♀️🧟🧟‍♂️🧟‍♀️💆💆‍♂️💆‍♀️💇💇‍♂️💇‍♀️🚶🚶‍♂️🚶‍♀️🧍🧍‍♂️🧍‍♀️🧎🧎‍♂️🧎‍♀️🧑‍🦯👨‍🦯👩‍🦯🧑‍🦼👨‍🦼👩‍🦼🧑‍🦽👨‍🦽👩‍🦽🏃🏃‍♂️🏃‍♀️💃🕺🕴👯👯‍♂️👯‍♀️🧖🧖‍♂️🧖‍♀️🧗🧗‍♂️🧗‍♀️🤺🏇⛷🏂🏌🏌️‍♂️🏌️‍♀️🏄🏄‍♂️🏄‍♀️🚣🚣‍♂️🚣‍♀️🏊🏊‍♂️🏊‍♀️⛹⛹️‍♂️⛹️‍♀️🏋🏋️‍♂️🏋️‍♀️🚴🚴‍♂️🚴‍♀️🚵🚵‍♂️🚵‍♀️🤸🤸‍♂️🤸‍♀️🤼🤼‍♂️🤼‍♀️🤽🤽‍♂️🤽‍♀️🤾🤾‍♂️🤾‍♀️🤹🤹‍♂️🤹‍♀️🧘🧘‍♂️🧘‍♀️🛀🛌🧑‍🤝‍🧑👭👫👬💏👩‍❤️‍💋‍👨👨‍❤️‍💋‍👨👩‍❤️‍💋‍👩💑👩‍❤️‍👨👨‍❤️‍👨👩‍❤️‍👩👪👨‍👩‍👦👨‍👩‍👧👨‍👩‍👧‍👦👨‍👩‍👦‍👦👨‍👩‍👧‍👧👨‍👨‍👦👨‍👨‍👧👨‍👨‍👧‍👦👨‍👨‍👦‍👦👨‍👨‍👧‍👧👩‍👩‍👦👩‍👩‍👧👩‍👩‍👧‍👦👩‍👩‍👦‍👦👩‍👩‍👧‍👧👨‍👦👨‍👦‍👦👨‍👧👨‍👧‍👦👨‍👧‍👧👩‍👦👩‍👦‍👦👩‍👧👩‍👧‍👦👩‍👧‍👧🗣👤👥🫂👣🦰🦱🦳🦲🐵🐒🦍🦧🐶🐕🦮🐕‍🦺🐩🐺🦊🦝🐱🐈🐈‍⬛🦁🐯🐅🐆🐴🐎🦄🦓🦌🦬🐮🐂🐃🐄🐷🐖🐗🐽🐏🐑🐐🐪🐫🦙🦒🐘🦣🦏🦛🐭🐁🐀🐹🐰🐇🐿🦫🦔🦇🐻🐻‍❄️🐨🐼🦥🦦🦨🦘🦡🐾🦃🐔🐓🐣🐤🐥🐦🐧🕊🦅🦆🦢🦉🦤🪶🦩🦚🦜🐸🐊🐢🦎🐍🐲🐉🦕🦖🐳🐋🐬🦭🐟🐠🐡🦈🐙🐚🐌🦋🐛🐜🐝🪲🐞🦗🪳🕷🕸🦂🦟🪰🪱🦠💐🌸💮🏵🌹🥀🌺🌻🌼🌷🌱🪴🌲🌳🌴🌵🌾🌿☘🍀🍁🍂🍃🍇🍈🍉🍊🍋🍌🍍🥭🍎🍏🍐🍑🍒🍓🫐🥝🍅🫒🥥🥑🍆🥔🥕🌽🌶🫑🥒🥬🥦🧄🧅🍄🥜🌰🍞🥐🥖🫓🥨🥯🥞🧇🧀🍖🍗🥩🥓🍔🍟🍕🌭🥪🌮🌯🫔🥙🧆🥚🍳🥘🍲🫕🥣🥗🍿🧈🧂🥫🍱🍘🍙🍚🍛🍜🍝🍠🍢🍣🍤🍥🥮🍡🥟🥠🥡🦀🦞🦐🦑🦪🍦🍧🍨🍩🍪🎂🍰🧁🥧🍫🍬🍭🍮🍯🍼🥛☕🫖🍵🍶🍾🍷🍸🍹🍺🍻🥂🥃🥤🧋🧃🧉🧊🥢🍽🍴🥄🔪🏺🌍🌎🌏🌐🗺🗾🧭🏔⛰🌋🗻🏕🏖🏜🏝🏞🏟🏛🏗🧱🪨🪵🛖🏘🏚🏠🏡🏢🏣🏤🏥🏦🏨🏩🏪🏫🏬🏭🏯🏰💒🗼🗽⛪🕌🛕🕍⛩🕋⛲⛺🌁🌃🏙🌄🌅🌆🌇🌉♨🎠🎡🎢💈🎪🚂🚃🚄🚅🚆🚇🚈🚉🚊🚝🚞🚋🚌🚍🚎🚐🚑🚒🚓🚔🚕🚖🚗🚘🚙🛻🚚🚛🚜🏎🏍🛵🦽🦼🛺🚲🛴🛹🛼🚏🛣🛤🛢⛽🚨🚥🚦🛑🚧⚓⛵🛶🚤🛳⛴🛥🚢✈🛩🛫🛬🪂💺🚁🚟🚠🚡🛰🚀🛸🛎🧳⌛⏳⌚⏰⏱⏲🕰🕛🕧🕐🕜🕑🕝🕒🕞🕓🕟🕔🕠🕕🕡🕖🕢🕗🕣🕘🕤🕙🕥🕚🕦🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌡☀🌝🌞🪐⭐🌟🌠🌌☁⛅⛈🌤🌥🌦🌧🌨🌩🌪🌫🌬🌀🌈🌂☂☔⛱⚡❄☃⛄☄🔥💧🌊🎃🎄🎆🎇🧨✨🎈🎉🎊🎋🎍🎎🎏🎐🎑🧧🎀🎁🎗🎟🎫🎖🏆🏅🥇🥈🥉⚽⚾🥎🏀🏐🏈🏉🎾🥏🎳🏏🏑🏒🥍🏓🏸🥊🥋🥅⛳⛸🎣🤿🎽🎿🛷🥌🎯🪀🪁🎱🔮🪄🧿🎮🕹🎰🎲🧩🧸🪅🪆♠♥♦♣♟🃏🀄🎴🎭🖼🎨🧵🪡🧶🪢👓🕶🥽🥼🦺👔👕👖🧣🧤🧥🧦👗👘🥻🩱🩲🩳👙👚👛👜👝🛍🎒🩴👞👟🥾🥿👠👡🩰👢👑👒🎩🎓🧢🪖⛑📿💄💍💎🔇🔈🔉🔊📢📣📯🔔🔕🎼🎵🎶🎙🎚🎛🎤🎧📻🎷🪗🎸🎹🎺🎻🪕🥁";
-
-#[bench]
-fn str_char_count_lorem(b: &mut Bencher) {
-    b.iter(|| black_box(LOREM).chars().count());
-}
-
-#[bench]
-fn str_char_count_lorem_short(b: &mut Bencher) {
-    b.iter(|| black_box(LOREM_SHORT).chars().count());
-}
-
-#[bench]
-fn str_char_count_emoji(b: &mut Bencher) {
-    b.iter(|| black_box(EMOJI).chars().count());
-}
+mod char_count;
+mod corpora;
 
 #[bench]
 fn str_validate_emoji(b: &mut Bencher) {
-    b.iter(|| str::from_utf8(black_box(EMOJI.as_bytes())));
+    b.iter(|| str::from_utf8(black_box(corpora::emoji::LARGE.as_bytes())));
 }
diff --git a/library/core/benches/str/char_count.rs b/library/core/benches/str/char_count.rs
new file mode 100644 (file)
index 0000000..25d9b2e
--- /dev/null
@@ -0,0 +1,107 @@
+use super::corpora::*;
+use test::{black_box, Bencher};
+
+macro_rules! define_benches {
+    ($( fn $name: ident($arg: ident: &str) $body: block )+) => {
+        define_benches!(mod en_tiny, en::TINY, $($name $arg $body)+);
+        define_benches!(mod en_small, en::SMALL, $($name $arg $body)+);
+        define_benches!(mod en_medium, en::MEDIUM, $($name $arg $body)+);
+        define_benches!(mod en_large, en::LARGE, $($name $arg $body)+);
+        define_benches!(mod en_huge, en::HUGE, $($name $arg $body)+);
+
+        define_benches!(mod zh_tiny, zh::TINY, $($name $arg $body)+);
+        define_benches!(mod zh_small, zh::SMALL, $($name $arg $body)+);
+        define_benches!(mod zh_medium, zh::MEDIUM, $($name $arg $body)+);
+        define_benches!(mod zh_large, zh::LARGE, $($name $arg $body)+);
+        define_benches!(mod zh_huge, zh::HUGE, $($name $arg $body)+);
+
+        define_benches!(mod ru_tiny, ru::TINY, $($name $arg $body)+);
+        define_benches!(mod ru_small, ru::SMALL, $($name $arg $body)+);
+        define_benches!(mod ru_medium, ru::MEDIUM, $($name $arg $body)+);
+        define_benches!(mod ru_large, ru::LARGE, $($name $arg $body)+);
+        define_benches!(mod ru_huge, ru::HUGE, $($name $arg $body)+);
+
+        define_benches!(mod emoji_tiny, emoji::TINY, $($name $arg $body)+);
+        define_benches!(mod emoji_small, emoji::SMALL, $($name $arg $body)+);
+        define_benches!(mod emoji_medium, emoji::MEDIUM, $($name $arg $body)+);
+        define_benches!(mod emoji_large, emoji::LARGE, $($name $arg $body)+);
+        define_benches!(mod emoji_huge, emoji::HUGE, $($name $arg $body)+);
+    };
+    (mod $mod_name: ident, $input: expr, $($name: ident $arg: ident $body: block)+) => {
+        mod $mod_name {
+            use super::*;
+            $(
+                #[bench]
+                fn $name(bencher: &mut Bencher) {
+                    let input = $input;
+                    bencher.bytes = input.len() as u64;
+                    let mut input_s = input.to_string();
+                    bencher.iter(|| {
+                        let $arg: &str = &black_box(&mut input_s);
+                        black_box($body)
+                    })
+                }
+            )+
+        }
+    };
+}
+
+define_benches! {
+    fn case00_libcore(s: &str) {
+        libcore(s)
+    }
+
+    fn case01_filter_count_cont_bytes(s: &str) {
+        filter_count_cont_bytes(s)
+    }
+
+    fn case02_iter_increment(s: &str) {
+        iterator_increment(s)
+    }
+
+    fn case03_manual_char_len(s: &str) {
+        manual_char_len(s)
+    }
+}
+
+fn libcore(s: &str) -> usize {
+    s.chars().count()
+}
+
+#[inline]
+fn utf8_is_cont_byte(byte: u8) -> bool {
+    (byte as i8) < -64
+}
+
+fn filter_count_cont_bytes(s: &str) -> usize {
+    s.as_bytes().iter().filter(|&&byte| !utf8_is_cont_byte(byte)).count()
+}
+
+fn iterator_increment(s: &str) -> usize {
+    let mut c = 0;
+    for _ in s.chars() {
+        c += 1;
+    }
+    c
+}
+
+fn manual_char_len(s: &str) -> usize {
+    let s = s.as_bytes();
+    let mut c = 0;
+    let mut i = 0;
+    let l = s.len();
+    while i < l {
+        let b = s[i];
+        if b < 0x80 {
+            i += 1;
+        } else if b < 0xe0 {
+            i += 2;
+        } else if b < 0xf0 {
+            i += 3;
+        } else {
+            i += 4;
+        }
+        c += 1;
+    }
+    c
+}
diff --git a/library/core/benches/str/corpora.rs b/library/core/benches/str/corpora.rs
new file mode 100644 (file)
index 0000000..b4ac625
--- /dev/null
@@ -0,0 +1,88 @@
+//! Exposes a number of modules with different kinds of strings.
+//!
+//! Each module contains `&str` constants named `TINY`, `SMALL`, `MEDIUM`,
+//! `LARGE`, and `HUGE`.
+//!
+//! - The `TINY` string is generally around 8 bytes.
+//! - The `SMALL` string is generally around 30-40 bytes.
+//! - The `MEDIUM` string is generally around 600-700 bytes.
+//! - The `LARGE` string is the `MEDIUM` string repeated 8x, and is around 5kb.
+//! - The `HUGE` string is the `LARGE` string repeated 8x (or the `MEDIUM`
+//!   string repeated 64x), and is around 40kb.
+//!
+//! Except for `mod emoji` (which is just a bunch of emoji), the strings were
+//! pulled from (localizations of) rust-lang.org.
+
+macro_rules! repeat8 {
+    ($s:expr) => {
+        concat!($s, $s, $s, $s, $s, $s, $s, $s)
+    };
+}
+
+macro_rules! define_consts {
+    ($s:literal) => {
+        pub const MEDIUM: &str = $s;
+        pub const LARGE: &str = repeat8!($s);
+        pub const HUGE: &str = repeat8!(repeat8!(repeat8!($s)));
+    };
+}
+
+pub mod en {
+    pub const TINY: &str = "Mary had";
+    pub const SMALL: &str = "Mary had a little lamb, Little lamb";
+    define_consts! {
+        "Rust is blazingly fast and memory-efficient: with no runtime or garbage
+         collector, it can power performance-critical services, run on embedded
+         devices, and easily integrate with other languages.  Rust’s rich type system
+         and ownership model guarantee memory-safety and thread-safety — enabling you
+         to eliminate many classes of bugs at compile-time.  Rust has great
+         documentation, a friendly compiler with useful error messages, and top-notch
+         tooling — an integrated package manager and build tool, smart multi-editor
+         support with auto-completion and type inspections, an auto-formatter, and
+         more."
+    }
+}
+
+pub mod zh {
+    pub const TINY: &str = "速度惊";
+    pub const SMALL: &str = "速度惊人且内存利用率极高";
+    define_consts! {
+        "Rust   速度惊人且内存利用率极高。由于\
+         没有运行时和垃圾回收,它能够胜任对性能要\
+         求特别高的服务,可以在嵌入式设备上运行,\
+         还能轻松和其他语言集成。Rust 丰富的类型\
+         系统和所有权模型保证了内存安全和线程安全,\
+         让您在编译期就能够消除各种各样的错误。\
+         Rust 拥有出色的文档、友好的编译器和清晰\
+         的错误提示信息, 还集成了一流的工具——\
+         包管理器和构建工具, 智能地自动补全和类\
+         型检验的多编辑器支持, 以及自动格式化代\
+         码等等。"
+    }
+}
+
+pub mod ru {
+    pub const TINY: &str = "Сотни";
+    pub const SMALL: &str = "Сотни компаний по";
+    define_consts! {
+        "Сотни компаний по всему миру используют Rust в реальных\
+         проектах для быстрых кросс-платформенных решений с\
+         ограниченными ресурсами. Такие проекты, как Firefox,\
+         Dropbox и Cloudflare, используют Rust. Rust отлично\
+         подходит как для стартапов, так и для больших компаний,\
+         как для встраиваемых устройств, так и для масштабируемых\
+         web-сервисов. Мой самый большой комплимент Rust."
+    }
+}
+
+pub mod emoji {
+    pub const TINY: &str = "😀😃";
+    pub const SMALL: &str = "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘";
+    define_consts! {
+        "😀😃😄😁😆😅🤣😂🙂🙃😉😊😇🥰😍🤩😘😗☺😚😙🥲😋😛😜🤪😝🤑🤗🤭🤫🤔🤐🤨😐😑😶😶‍🌫️😏😒\
+         🙄😬😮‍💨🤥😌😔😪🤤😴😷🤒🤕🤢🤮🤧🥵🥶🥴😵😵‍💫🤯��🥳🥸😎🤓🧐😕😟🙁☹😮😯😲😳🥺😦😧😨\
+         😰😥😢😭😱😖😣😞😓😩😫🥱😤😡😠🤬😈👿💀☠💩🤡👹👺👻👽👾🤖😺😸😹😻😼😽🙀😿😾🙈🙉🙊\
+         💋💌💘💝💖💗💓��💕💟❣💔❤️‍🔥❤️‍🩹❤🧡💛💚💙💜🤎🖤🤍💯💢💥💫💦💨🕳💬👁️‍🗨️🗨🗯💭💤👋\
+         🤚🖐✋🖖👌🤌🤏✌"
+    }
+}
index 121aa634deb330988fb3c4ad224e11e619677d1b..ee79021ed536e69555e6a8ba2c470549143fd7e8 100644 (file)
@@ -512,6 +512,7 @@ macro_rules! array_impl_default {
 
     /// Returns a slice containing the entire array. Equivalent to `&s[..]`.
     #[stable(feature = "array_as_slice", since = "1.57.0")]
+    #[rustc_const_stable(feature = "array_as_slice", since = "1.57.0")]
     pub const fn as_slice(&self) -> &[T] {
         self
     }
index 5fd60b759286a3fc6439913ffbd4efa765b5fde6..aef7ad77568036d29752182ea18a404ae1fc711b 100644 (file)
@@ -315,6 +315,7 @@ fn cmp(&self, other: &Cell<T>) -> Ordering {
 #[stable(feature = "cell_from", since = "1.12.0")]
 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
 impl<T> const From<T> for Cell<T> {
+    /// Creates a new `Cell<T>` containing the given value.
     fn from(t: T) -> Cell<T> {
         Cell::new(t)
     }
@@ -1244,6 +1245,7 @@ fn cmp(&self, other: &RefCell<T>) -> Ordering {
 #[stable(feature = "cell_from", since = "1.12.0")]
 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
 impl<T> const From<T> for RefCell<T> {
+    /// Creates a new `RefCell<T>` containing the given value.
     fn from(t: T) -> RefCell<T> {
         RefCell::new(t)
     }
@@ -1959,6 +1961,7 @@ pub const fn get_mut(&mut self) -> &mut T {
     /// ```
     #[inline(always)]
     #[stable(feature = "unsafe_cell_raw_get", since = "1.56.0")]
+    #[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
@@ -1978,6 +1981,7 @@ fn default() -> UnsafeCell<T> {
 #[stable(feature = "cell_from", since = "1.12.0")]
 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
 impl<T> const From<T> for UnsafeCell<T> {
+    /// Creates a new `UnsafeCell<T>` containing the given value.
     fn from(t: T) -> UnsafeCell<T> {
         UnsafeCell::new(t)
     }
index 5566c2ffe87deeed0a75bb26e745f2527cd5e079..0ceedf936333d6d4659998664d0e0b89d6b8d168 100644 (file)
@@ -538,6 +538,10 @@ impl<T, U> const Into<U> for T
 where
     U: ~const From<T>,
 {
+    /// Calls `U::from(self)`.
+    ///
+    /// That is, this conversion is whatever the implementation of
+    /// <code>[From]&lt;T&gt; for U</code> chooses to do.
     fn into(self) -> U {
         U::from(self)
     }
@@ -547,6 +551,7 @@ fn into(self) -> U {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
 impl<T> const From<T> for T {
+    /// Returns the argument unchanged.
     fn from(t: T) -> T {
         t
     }
index db8776ac7418d9aa2a79be51282e657ec7573426..2ae92e89d63b51662d9790e612c4254a051cefc0 100644 (file)
@@ -1,5 +1,5 @@
 use crate::iter::{InPlaceIterable, Iterator};
-use crate::ops::{ControlFlow, Try};
+use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, NeverShortCircuit, Residual, Try};
 
 mod chain;
 mod cloned;
@@ -128,41 +128,45 @@ pub unsafe trait SourceIter {
 }
 
 /// An iterator adapter that produces output as long as the underlying
-/// iterator produces `Result::Ok` values.
+/// iterator produces values where `Try::branch` says to `ControlFlow::Continue`.
 ///
-/// If an error is encountered, the iterator stops and the error is
-/// stored.
-pub(crate) struct ResultShunt<'a, I, E> {
+/// If a `ControlFlow::Break` is encountered, the iterator stops and the
+/// residual is stored.
+pub(crate) struct GenericShunt<'a, I, R> {
     iter: I,
-    error: &'a mut Result<(), E>,
+    residual: &'a mut Option<R>,
 }
 
-/// Process the given iterator as if it yielded a `T` instead of a
-/// `Result<T, _>`. Any errors will stop the inner iterator and
-/// the overall result will be an error.
-pub(crate) fn process_results<I, T, E, F, U>(iter: I, mut f: F) -> Result<U, E>
+/// Process the given iterator as if it yielded a the item's `Try::Output`
+/// type instead. Any `Try::Residual`s encountered will stop the inner iterator
+/// and be propagated back to the overall result.
+pub(crate) fn try_process<I, T, R, F, U>(iter: I, mut f: F) -> ChangeOutputType<I::Item, U>
 where
-    I: Iterator<Item = Result<T, E>>,
-    for<'a> F: FnMut(ResultShunt<'a, I, E>) -> U,
+    I: Iterator<Item: Try<Output = T, Residual = R>>,
+    for<'a> F: FnMut(GenericShunt<'a, I, R>) -> U,
+    R: Residual<U>,
 {
-    let mut error = Ok(());
-    let shunt = ResultShunt { iter, error: &mut error };
+    let mut residual = None;
+    let shunt = GenericShunt { iter, residual: &mut residual };
     let value = f(shunt);
-    error.map(|()| value)
+    match residual {
+        Some(r) => FromResidual::from_residual(r),
+        None => Try::from_output(value),
+    }
 }
 
-impl<I, T, E> Iterator for ResultShunt<'_, I, E>
+impl<I, R> Iterator for GenericShunt<'_, I, R>
 where
-    I: Iterator<Item = Result<T, E>>,
+    I: Iterator<Item: Try<Residual = R>>,
 {
-    type Item = T;
+    type Item = <I::Item as Try>::Output;
 
     fn next(&mut self) -> Option<Self::Item> {
-        self.find(|_| true)
+        self.try_for_each(ControlFlow::Break).break_value()
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        if self.error.is_err() {
+        if self.residual.is_some() {
             (0, Some(0))
         } else {
             let (_, upper) = self.iter.size_hint();
@@ -170,17 +174,16 @@ fn size_hint(&self) -> (usize, Option<usize>) {
         }
     }
 
-    fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R
+    fn try_fold<B, F, T>(&mut self, init: B, mut f: F) -> T
     where
-        F: FnMut(B, Self::Item) -> R,
-        R: Try<Output = B>,
+        F: FnMut(B, Self::Item) -> T,
+        T: Try<Output = B>,
     {
-        let error = &mut *self.error;
         self.iter
-            .try_fold(init, |acc, x| match x {
-                Ok(x) => ControlFlow::from_try(f(acc, x)),
-                Err(e) => {
-                    *error = Err(e);
+            .try_fold(init, |acc, x| match Try::branch(x) {
+                ControlFlow::Continue(x) => ControlFlow::from_try(f(acc, x)),
+                ControlFlow::Break(r) => {
+                    *self.residual = Some(r);
                     ControlFlow::Break(try { acc })
                 }
             })
@@ -192,17 +195,12 @@ fn fold<B, F>(mut self, init: B, fold: F) -> B
         Self: Sized,
         F: FnMut(B, Self::Item) -> B,
     {
-        #[inline]
-        fn ok<B, T>(mut f: impl FnMut(B, T) -> B) -> impl FnMut(B, T) -> Result<B, !> {
-            move |acc, x| Ok(f(acc, x))
-        }
-
-        self.try_fold(init, ok(fold)).unwrap()
+        self.try_fold(init, NeverShortCircuit::wrap_mut_2(fold)).0
     }
 }
 
 #[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I, E> SourceIter for ResultShunt<'_, I, E>
+unsafe impl<I, R> SourceIter for GenericShunt<'_, I, R>
 where
     I: SourceIter,
 {
@@ -215,11 +213,11 @@ unsafe fn as_inner(&mut self) -> &mut Self::Source {
     }
 }
 
-// SAFETY: ResultShunt::next calls I::find, which has to advance `iter` in order to
-// return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's guaranteed that
-// at least one item will be moved out from the underlying source.
+// SAFETY: GenericShunt::next calls `I::try_for_each`, which has to advance `iter`
+// in order to return `Some(_)`. Since `iter` has type `I: InPlaceIterable` it's
+// guaranteed that at least one item will be moved out from the underlying source.
 #[unstable(issue = "none", feature = "inplace_iteration")]
-unsafe impl<I, T, E> InPlaceIterable for ResultShunt<'_, I, E> where
-    I: Iterator<Item = Result<T, E>> + InPlaceIterable
+unsafe impl<I, T, R> InPlaceIterable for GenericShunt<'_, I, R> where
+    I: Iterator<Item: Try<Output = T, Residual = R>> + InPlaceIterable
 {
 }
index da459ed7c68f47d6b452d403a5f93f5c5c4e289d..65f56f64dbfa63ab850ed3b696d857ec4320b154 100644 (file)
 #[unstable(feature = "iter_intersperse", reason = "recently added", issue = "79524")]
 pub use self::adapters::{Intersperse, IntersperseWith};
 
-pub(crate) use self::adapters::process_results;
+pub(crate) use self::adapters::try_process;
 
 mod adapters;
 mod range;
index c2e837df5ff2a138b03be1d039a52b692a4820bb..84d83ee39699fe1841149b00e0c929389a1a7bc3 100644 (file)
@@ -167,7 +167,7 @@ fn sum<I>(iter: I) -> Result<T, E>
     where
         I: Iterator<Item = Result<U, E>>,
     {
-        iter::process_results(iter, |i| i.sum())
+        iter::try_process(iter, |i| i.sum())
     }
 }
 
@@ -183,7 +183,7 @@ fn product<I>(iter: I) -> Result<T, E>
     where
         I: Iterator<Item = Result<U, E>>,
     {
-        iter::process_results(iter, |i| i.product())
+        iter::try_process(iter, |i| i.product())
     }
 }
 
@@ -210,7 +210,7 @@ fn sum<I>(iter: I) -> Option<T>
     where
         I: Iterator<Item = Option<U>>,
     {
-        iter.map(|x| x.ok_or(())).sum::<Result<_, _>>().ok()
+        iter::try_process(iter, |i| i.sum())
     }
 }
 
@@ -226,6 +226,6 @@ fn product<I>(iter: I) -> Option<T>
     where
         I: Iterator<Item = Option<U>>,
     {
-        iter.map(|x| x.ok_or(())).product::<Result<_, _>>().ok()
+        iter::try_process(iter, |i| i.product())
     }
 }
index fc14620a2df84b752686aa0daa4d47318079489b..637d7bc44885e96902413d6eed0290f06004babf 100644 (file)
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_on_unimplemented(
+    on(
+        _Self = "[{A}]",
+        message = "a value of type `{Self}` cannot be built since `{Self}` has no definite size",
+        label = "try explicitly collecting into a `Vec<{A}>`",
+    ),
+    on(
+        all(
+            A = "{integer}",
+            any(
+                _Self = "[i8]",
+                _Self = "[i16]",
+                _Self = "[i32]",
+                _Self = "[i64]",
+                _Self = "[i128]",
+                _Self = "[isize]",
+                _Self = "[u8]",
+                _Self = "[u16]",
+                _Self = "[u32]",
+                _Self = "[u64]",
+                _Self = "[u128]",
+                _Self = "[usize]"
+            )
+        ),
+        message = "a value of type `{Self}` cannot be built since `{Self}` has no definite size",
+        label = "try explicitly collecting into a `Vec<{A}>`",
+    ),
     message = "a value of type `{Self}` cannot be built from an iterator \
                over elements of type `{A}`",
     label = "value of type `{Self}` cannot be built from `std::iter::Iterator<Item={A}>`"
index a8fe5f59bae0148794c333f14e48b6588d216b49..5a361edecd9c00298e95a3d91446d73a241a8f4d 100644 (file)
@@ -1,6 +1,7 @@
 use crate::cmp::{self, Ordering};
 use crate::ops::{ChangeOutputType, ControlFlow, FromResidual, Residual, Try};
 
+use super::super::try_process;
 use super::super::TrustedRandomAccessNoCoerce;
 use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse};
 use super::super::{FlatMap, Flatten};
@@ -1777,6 +1778,87 @@ fn collect<B: FromIterator<Self::Item>>(self) -> B
         FromIterator::from_iter(self)
     }
 
+    /// Fallibly transforms an iterator into a collection, short circuiting if
+    /// a failure is encountered.
+    ///
+    /// `try_collect()` is a variation of [`collect()`][`collect`] that allows fallible
+    /// conversions during collection. Its main use case is simplifying conversions from
+    /// iterators yielding [`Option<T>`][`Option`] into `Option<Collection<T>>`, or similarly for other [`Try`]
+    /// types (e.g. [`Result`]).
+    ///
+    /// Importantly, `try_collect()` doesn't require that the outer [`Try`] type also implements [`FromIterator`];
+    /// only the inner type produced on `Try::Output` must implement it. Concretely,
+    /// this means that collecting into `ControlFlow<_, Vec<i32>>` is valid because `Vec<i32>` implements
+    /// [`FromIterator`], even though [`ControlFlow`] doesn't.
+    ///
+    /// Also, if a failure is encountered during `try_collect()`, the iterator is still valid and
+    /// may continue to be used, in which case it will continue iterating starting after the element that
+    /// triggered the failure. See the last example below for an example of how this works.
+    ///
+    /// # Examples
+    /// Successfully collecting an iterator of `Option<i32>` into `Option<Vec<i32>>`:
+    /// ```
+    /// #![feature(iterator_try_collect)]
+    ///
+    /// let u = vec![Some(1), Some(2), Some(3)];
+    /// let v = u.into_iter().try_collect::<Vec<i32>>();
+    /// assert_eq!(v, Some(vec![1, 2, 3]));
+    /// ```
+    ///
+    /// Failing to collect in the same way:
+    /// ```
+    /// #![feature(iterator_try_collect)]
+    ///
+    /// let u = vec![Some(1), Some(2), None, Some(3)];
+    /// let v = u.into_iter().try_collect::<Vec<i32>>();
+    /// assert_eq!(v, None);
+    /// ```
+    ///
+    /// A similar example, but with `Result`:
+    /// ```
+    /// #![feature(iterator_try_collect)]
+    ///
+    /// let u: Vec<Result<i32, ()>> = vec![Ok(1), Ok(2), Ok(3)];
+    /// let v = u.into_iter().try_collect::<Vec<i32>>();
+    /// assert_eq!(v, Ok(vec![1, 2, 3]));
+    ///
+    /// let u = vec![Ok(1), Ok(2), Err(()), Ok(3)];
+    /// let v = u.into_iter().try_collect::<Vec<i32>>();
+    /// assert_eq!(v, Err(()));
+    /// ```
+    ///
+    /// Finally, even [`ControlFlow`] works, despite the fact that it
+    /// doesn't implement [`FromIterator`]. Note also that the iterator can
+    /// continue to be used, even if a failure is encountered:
+    ///
+    /// ```
+    /// #![feature(iterator_try_collect)]
+    ///
+    /// use core::ops::ControlFlow::{Break, Continue};
+    ///
+    /// let u = [Continue(1), Continue(2), Break(3), Continue(4), Continue(5)];
+    /// let mut it = u.into_iter();
+    ///
+    /// let v = it.try_collect::<Vec<_>>();
+    /// assert_eq!(v, Break(3));
+    ///
+    /// let v = it.try_collect::<Vec<_>>();
+    /// assert_eq!(v, Continue(vec![4, 5]));
+    /// ```
+    ///
+    /// [`collect`]: Iterator::collect
+    #[inline]
+    #[unstable(feature = "iterator_try_collect", issue = "94047")]
+    fn try_collect<B>(&mut self) -> ChangeOutputType<Self::Item, B>
+    where
+        Self: Sized,
+        <Self as Iterator>::Item: Try,
+        <<Self as Iterator>::Item as Try>::Residual: Residual<B>,
+        B: FromIterator<<Self::Item as Try>::Output>,
+    {
+        try_process(self, |i| i.collect())
+    }
+
     /// Consumes an iterator, creating two collections from it.
     ///
     /// The predicate passed to `partition()` can return `true`, or `false`.
index 788f0cce01ba838a83f57f92cbf4d482c00739bc..88826782a3d607318a61348d4ad666b9392c830e 100644 (file)
@@ -75,6 +75,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`.
     fn from(value: T) -> Self {
         OnceCell { inner: UnsafeCell::new(Some(value)) }
     }
index 66f2d2ec1e9313ae8876825a738947098f5a2c0c..aa1ad9362a90e897b4fee9c84dc74cdcbeb32ff5 100644 (file)
 #![feature(associated_type_bounds)]
 #![feature(auto_traits)]
 #![feature(cfg_target_has_atomic)]
+#![cfg_attr(not(bootstrap), feature(cfg_target_has_atomic_equal_alignment))]
 #![feature(const_fn_floating_point_arithmetic)]
 #![feature(const_fn_fn_ptr_basics)]
 #![feature(const_fn_trait_bound)]
index 0cc428d6962782b247914d4ccf9afc8bbc91e989..628b679236e1d4d879df4e906fcb79cbb5cb13d2 100644 (file)
@@ -594,6 +594,22 @@ macro_rules! writeln {
 ///     unreachable!("The loop should always return");
 /// }
 /// ```
+#[cfg(not(bootstrap))]
+#[macro_export]
+#[rustc_builtin_macro(unreachable)]
+#[allow_internal_unstable(edition_panic)]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "unreachable_macro")]
+macro_rules! unreachable {
+    // Expands to either `$crate::panic::unreachable_2015` or `$crate::panic::unreachable_2021`
+    // depending on the edition of the caller.
+    ($($arg:tt)*) => {
+        /* compiler built-in */
+    };
+}
+
+/// unreachable!() macro
+#[cfg(bootstrap)]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "unreachable_macro")]
@@ -856,7 +872,7 @@ macro_rules! format_args {
         ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
     }
 
-    /// Same as `format_args`, but can be used in some const contexts.
+    /// Same as [`format_args`], but can be used in some const contexts.
     ///
     /// This macro is used by the panic macros for the `const_panic` feature.
     ///
@@ -870,7 +886,7 @@ macro_rules! const_format_args {
         ($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }};
     }
 
-    /// Same as `format_args`, but adds a newline in the end.
+    /// Same as [`format_args`], but adds a newline in the end.
     #[unstable(
         feature = "format_args_nl",
         issue = "none",
index 79436c8e8ede485c5fc93fadd00c1cd6a6e8ffb0..199af081560f592e23fecc9f10b8de007cf83ad3 100644 (file)
@@ -4,7 +4,7 @@ macro_rules! int_impl {
      $reversed:expr, $le_bytes:expr, $be_bytes:expr,
      $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
         /// The smallest value that can be represented by this integer type,
-        #[doc = concat!("-2<sup>", $BITS_MINUS_ONE, "</sup>.")]
+        #[doc = concat!("&minus;2<sup>", $BITS_MINUS_ONE, "</sup>.")]
         ///
         /// # Examples
         ///
@@ -17,7 +17,7 @@ macro_rules! int_impl {
         pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self;
 
         /// The largest value that can be represented by this integer type,
-        #[doc = concat!("2<sup>", $BITS_MINUS_ONE, "</sup> - 1.")]
+        #[doc = concat!("2<sup>", $BITS_MINUS_ONE, "</sup> &minus; 1.")]
         ///
         /// # Examples
         ///
@@ -1064,6 +1064,7 @@ pub const fn saturating_mul(self, rhs: Self) -> Self {
         ///
         /// ```
         #[stable(feature = "saturating_div", since = "1.58.0")]
+        #[rustc_const_stable(feature = "saturating_div", since = "1.58.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -2419,14 +2420,14 @@ pub const fn abs(self) -> Self {
         /// Basic usage:
         ///
         /// ```
-        /// #![feature(int_abs_diff)]
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(80), 20", stringify!($UnsignedT), ");")]
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(110), 10", stringify!($UnsignedT), ");")]
         #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").abs_diff(80), 180", stringify!($UnsignedT), ");")]
         #[doc = concat!("assert_eq!((-100", stringify!($SelfT), ").abs_diff(-120), 20", stringify!($UnsignedT), ");")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.abs_diff(", stringify!($SelfT), "::MAX), ", stringify!($UnsignedT), "::MAX);")]
         /// ```
-        #[unstable(feature = "int_abs_diff", issue = "89492")]
+        #[stable(feature = "int_abs_diff", since = "1.60.0")]
+        #[rustc_const_stable(feature = "int_abs_diff", since = "1.60.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
index 721c030b410aec548ecbd15e73630e8bd65ba6f5..72105888f9447f2eac6c277754d157d38dd0b6c3 100644 (file)
@@ -791,7 +791,6 @@ pub const fn is_ascii_control(&self) -> bool {
     /// # Examples
     ///
     /// ```
-    /// #![feature(inherent_ascii_escape)]
     ///
     /// assert_eq!("0", b'0'.escape_ascii().to_string());
     /// assert_eq!("\\t", b'\t'.escape_ascii().to_string());
@@ -804,10 +803,15 @@ pub const fn is_ascii_control(&self) -> bool {
     /// ```
     #[must_use = "this returns the escaped byte as an iterator, \
                   without modifying the original"]
-    #[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+    #[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
     #[inline]
-    pub fn escape_ascii(&self) -> ascii::EscapeDefault {
-        ascii::escape_default(*self)
+    pub fn escape_ascii(self) -> ascii::EscapeDefault {
+        ascii::escape_default(self)
+    }
+
+    pub(crate) fn is_utf8_char_boundary(self) -> bool {
+        // This is bit magic equivalent to: b < 128 || b >= 192
+        (self as i8) >= -0x40
     }
 }
 
index e21ae48917953530440f1e08086ff558e080b827..1ebd1c58f2b59dc3b8b02e743becc57cc17b6ed3 100644 (file)
@@ -972,6 +972,7 @@ impl $Ty {
                 /// ```
                 #[must_use]
                 #[stable(feature = "nonzero_is_power_of_two", since = "1.59.0")]
+                #[rustc_const_stable(feature = "nonzero_is_power_of_two", since = "1.59.0")]
                 #[inline]
                 pub const fn is_power_of_two(self) -> bool {
                     // LLVM 11 normalizes `unchecked_sub(x, 1) & x == 0` to the implementation seen here.
index 0bb654977764d48c7df40eefa5730247d8580a8c..feec448ebbdb318e687386ef772b49bdd579e1b9 100644 (file)
@@ -17,7 +17,7 @@ macro_rules! uint_impl {
         pub const MIN: Self = 0;
 
         /// The largest value that can be represented by this integer type,
-        #[doc = concat!("2<sup>", $BITS, "</sup> - 1.")]
+        #[doc = concat!("2<sup>", $BITS, "</sup> &minus; 1.")]
         ///
         /// # Examples
         ///
@@ -1132,6 +1132,7 @@ pub const fn saturating_mul(self, rhs: Self) -> Self {
         ///
         /// ```
         #[stable(feature = "saturating_div", since = "1.58.0")]
+        #[rustc_const_stable(feature = "saturating_div", since = "1.58.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1634,11 +1635,11 @@ pub const fn borrowing_sub(self, rhs: Self, borrow: bool) -> (Self, bool) {
         /// Basic usage:
         ///
         /// ```
-        /// #![feature(int_abs_diff)]
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(80), 20", stringify!($SelfT), ");")]
         #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".abs_diff(110), 10", stringify!($SelfT), ");")]
         /// ```
-        #[unstable(feature = "int_abs_diff", issue = "89492")]
+        #[stable(feature = "int_abs_diff", since = "1.60.0")]
+        #[rustc_const_stable(feature = "int_abs_diff", since = "1.60.0")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
index a0e42c51e4517a8091baa59893d90752983cac9b..5353d900e76629a33ef568ef1ecbe13291b81a50 100644 (file)
@@ -239,6 +239,16 @@ fn add_assign(&mut self, other: Wrapping<$t>) {
         }
         forward_ref_op_assign! { impl const AddAssign, add_assign for Wrapping<$t>, Wrapping<$t> }
 
+        #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const AddAssign<$t> for Wrapping<$t> {
+            #[inline]
+            fn add_assign(&mut self, other: $t) {
+                *self = *self + Wrapping(other);
+            }
+        }
+        forward_ref_op_assign! { impl const AddAssign, add_assign for Wrapping<$t>, $t }
+
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
         impl const Sub for Wrapping<$t> {
@@ -262,6 +272,16 @@ fn sub_assign(&mut self, other: Wrapping<$t>) {
         }
         forward_ref_op_assign! { impl const SubAssign, sub_assign for Wrapping<$t>, Wrapping<$t> }
 
+        #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const SubAssign<$t> for Wrapping<$t> {
+            #[inline]
+            fn sub_assign(&mut self, other: $t) {
+                *self = *self - Wrapping(other);
+            }
+        }
+        forward_ref_op_assign! { impl const SubAssign, sub_assign for Wrapping<$t>, $t }
+
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
         impl const Mul for Wrapping<$t> {
@@ -285,6 +305,16 @@ fn mul_assign(&mut self, other: Wrapping<$t>) {
         }
         forward_ref_op_assign! { impl const MulAssign, mul_assign for Wrapping<$t>, Wrapping<$t> }
 
+        #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const MulAssign<$t> for Wrapping<$t> {
+            #[inline]
+            fn mul_assign(&mut self, other: $t) {
+                *self = *self * Wrapping(other);
+            }
+        }
+        forward_ref_op_assign! { impl const MulAssign, mul_assign for Wrapping<$t>, $t }
+
         #[stable(feature = "wrapping_div", since = "1.3.0")]
         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
         impl const Div for Wrapping<$t> {
@@ -308,6 +338,16 @@ fn div_assign(&mut self, other: Wrapping<$t>) {
         }
         forward_ref_op_assign! { impl const DivAssign, div_assign for Wrapping<$t>, Wrapping<$t> }
 
+        #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const DivAssign<$t> for Wrapping<$t> {
+            #[inline]
+            fn div_assign(&mut self, other: $t) {
+                *self = *self / Wrapping(other);
+            }
+        }
+        forward_ref_op_assign! { impl const DivAssign, div_assign for Wrapping<$t>, $t }
+
         #[stable(feature = "wrapping_impls", since = "1.7.0")]
         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
         impl const Rem for Wrapping<$t> {
@@ -331,6 +371,16 @@ fn rem_assign(&mut self, other: Wrapping<$t>) {
         }
         forward_ref_op_assign! { impl const RemAssign, rem_assign for Wrapping<$t>, Wrapping<$t> }
 
+        #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const RemAssign<$t> for Wrapping<$t> {
+            #[inline]
+            fn rem_assign(&mut self, other: $t) {
+                *self = *self % Wrapping(other);
+            }
+        }
+        forward_ref_op_assign! { impl const RemAssign, rem_assign for Wrapping<$t>, $t }
+
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
         impl const Not for Wrapping<$t> {
@@ -367,6 +417,16 @@ fn bitxor_assign(&mut self, other: Wrapping<$t>) {
         }
         forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for Wrapping<$t>, Wrapping<$t> }
 
+        #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitXorAssign<$t> for Wrapping<$t> {
+            #[inline]
+            fn bitxor_assign(&mut self, other: $t) {
+                *self = *self ^ Wrapping(other);
+            }
+        }
+        forward_ref_op_assign! { impl const BitXorAssign, bitxor_assign for Wrapping<$t>, $t }
+
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
         impl const BitOr for Wrapping<$t> {
@@ -390,6 +450,16 @@ fn bitor_assign(&mut self, other: Wrapping<$t>) {
         }
         forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for Wrapping<$t>, Wrapping<$t> }
 
+        #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitOrAssign<$t> for Wrapping<$t> {
+            #[inline]
+            fn bitor_assign(&mut self, other: $t) {
+                *self = *self | Wrapping(other);
+            }
+        }
+        forward_ref_op_assign! { impl const BitOrAssign, bitor_assign for Wrapping<$t>, $t }
+
         #[stable(feature = "rust1", since = "1.0.0")]
         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
         impl const BitAnd for Wrapping<$t> {
@@ -413,6 +483,16 @@ fn bitand_assign(&mut self, other: Wrapping<$t>) {
         }
         forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for Wrapping<$t>, Wrapping<$t> }
 
+        #[stable(feature = "wrapping_int_assign_impl", since = "1.60.0")]
+        #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+        impl const BitAndAssign<$t> for Wrapping<$t> {
+            #[inline]
+            fn bitand_assign(&mut self, other: $t) {
+                *self = *self & Wrapping(other);
+            }
+        }
+        forward_ref_op_assign! { impl const BitAndAssign, bitand_assign for Wrapping<$t>, $t }
+
         #[stable(feature = "wrapping_neg", since = "1.10.0")]
         #[rustc_const_unstable(feature = "const_ops", issue = "90080")]
         impl const Neg for Wrapping<$t> {
index 6a414ae8c4b800981533f7e44e297caa828f28e3..ba369e7f3aaa0a2af92477588d6e36e4500405d7 100644 (file)
@@ -302,6 +302,7 @@ pub trait Try: FromResidual {
         enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
     ),
 )]
+#[rustc_diagnostic_item = "FromResidual"]
 #[unstable(feature = "try_trait_v2", issue = "84277")]
 pub trait FromResidual<R = <Self as Try>::Residual> {
     /// Constructs the type from a compatible `Residual` type.
@@ -359,6 +360,14 @@ pub trait Residual<O> {
 #[repr(transparent)]
 pub(crate) struct NeverShortCircuit<T>(pub T);
 
+impl<T> NeverShortCircuit<T> {
+    /// Wrap a binary `FnMut` to return its result wrapped in a `NeverShortCircuit`.
+    #[inline]
+    pub fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self {
+        move |a, b| NeverShortCircuit(f(a, b))
+    }
+}
+
 pub(crate) enum NeverShortCircuitResidual {}
 
 impl<T> Try for NeverShortCircuit<T> {
index 611f4ab38ab334d713b677b6d3a4fc75277bf4be..508837f63c3bee8d7bad27fc71c02b68f8f36e9b 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use crate::iter::{FromIterator, FusedIterator, TrustedLen};
+use crate::iter::{self, FromIterator, FusedIterator, TrustedLen};
 use crate::panicking::{panic, panic_str};
 use crate::pin::Pin;
 use crate::{
@@ -1207,13 +1207,25 @@ pub const fn and<U>(self, optb: Option<U>) -> Option<U>
     /// # Examples
     ///
     /// ```
-    /// fn sq(x: u32) -> Option<u32> { Some(x * x) }
-    /// fn nope(_: u32) -> Option<u32> { None }
+    /// fn sq_then_to_string(x: u32) -> Option<String> {
+    ///     x.checked_mul(x).map(|sq| sq.to_string())
+    /// }
+    ///
+    /// assert_eq!(Some(2).and_then(sq_then_to_string), Some(4.to_string()));
+    /// assert_eq!(Some(1_000_000).and_then(sq_then_to_string), None); // overflowed!
+    /// assert_eq!(None.and_then(sq_then_to_string), None);
+    /// ```
+    ///
+    /// Often used to chain fallible operations that may return [`None`].
+    ///
+    /// ```
+    /// let arr_2d = [["A0", "A1"], ["B0", "B1"]];
+    ///
+    /// let item_0_1 = arr_2d.get(0).and_then(|row| row.get(1));
+    /// assert_eq!(item_0_1, Some(&"A1"));
     ///
-    /// assert_eq!(Some(2).and_then(sq).and_then(sq), Some(16));
-    /// assert_eq!(Some(2).and_then(sq).and_then(nope), None);
-    /// assert_eq!(Some(2).and_then(nope).and_then(sq), None);
-    /// assert_eq!(None.and_then(sq).and_then(sq), None);
+    /// let item_2_0 = arr_2d.get(2).and_then(|row| row.get(0));
+    /// assert_eq!(item_2_0, None);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -2233,7 +2245,7 @@ fn from_iter<I: IntoIterator<Item = Option<A>>>(iter: I) -> Option<V> {
         // FIXME(#11084): This could be replaced with Iterator::scan when this
         // performance bug is closed.
 
-        iter.into_iter().map(|x| x.ok_or(())).collect::<Result<_, _>>().ok()
+        iter::try_process(iter.into_iter(), |i| i.collect())
     }
 }
 
index 7a8b04d6f3c13c4599201e5c1b6064d854604041..0be3f06ff6c2a56720ff41ad14631722091ca6bc 100644 (file)
     ),
 }
 
+#[doc(hidden)]
+#[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")]
+#[allow_internal_unstable(core_panic)]
+#[rustc_diagnostic_item = "unreachable_2015_macro"]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro unreachable_2015 {
+    () => (
+        $crate::panicking::panic("internal error: entered unreachable code")
+    ),
+    // Use of `unreachable_display` for non_fmt_panic lint.
+    // NOTE: the message ("internal error ...") is embeded directly in unreachable_display
+    ($msg:expr $(,)?) => (
+        $crate::panicking::unreachable_display(&$msg)
+    ),
+    ($fmt:expr, $($arg:tt)*) => (
+        $crate::panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*)
+    ),
+}
+
+#[doc(hidden)]
+#[unstable(feature = "edition_panic", issue = "none", reason = "use unreachable!() instead")]
+#[allow_internal_unstable(core_panic)]
+#[rustc_diagnostic_item = "unreachable_2021_macro"]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro unreachable_2021 {
+    () => (
+        $crate::panicking::panic("internal error: entered unreachable code")
+    ),
+    ($($t:tt)+) => (
+        $crate::panic!("internal error: entered unreachable code: {}", $crate::format_args!($($t)+))
+    ),
+}
+
 /// 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.
index 405224f8fb0b095f03947a1f31020939c6ad9bd2..be8598fae09d793a8859a0e9dac14e2cd9fa3dbe 100644 (file)
@@ -136,6 +136,10 @@ pub fn location(&self) -> Option<&Location<'_>> {
     /// This is true for most kinds of panics with the exception of panics
     /// caused by trying to unwind out of a `Drop` implementation or a function
     /// whose ABI does not support unwinding.
+    ///
+    /// It is safe for a panic handler to unwind even when this function returns
+    /// true, however this will simply cause the panic handler to be called
+    /// again.
     #[must_use]
     #[unstable(feature = "panic_can_unwind", issue = "92988")]
     pub fn can_unwind(&self) -> bool {
index 5078eea07a15c5499daff9c0fa50d9982407c83b..0798076411ac4bff1d157112732fea1ced9b0d07 100644 (file)
@@ -50,12 +50,20 @@ pub const fn panic(expr: &'static str) -> ! {
 
 #[inline]
 #[track_caller]
-#[lang = "panic_str"] // needed for `non-fmt-panics` lint
+#[rustc_diagnostic_item = "panic_str"]
 #[rustc_const_unstable(feature = "core_panic", issue = "none")]
 pub const fn panic_str(expr: &str) -> ! {
     panic_display(&expr);
 }
 
+#[cfg(not(bootstrap))]
+#[inline]
+#[track_caller]
+#[rustc_diagnostic_item = "unreachable_display"] // needed for `non-fmt-panics` lint
+pub fn unreachable_display<T: fmt::Display>(x: &T) -> ! {
+    panic_fmt(format_args!("internal error: entered unreachable code: {}", *x));
+}
+
 #[inline]
 #[track_caller]
 #[lang = "panic_display"] // needed for const-evaluated panics
index 09fc6df5429759ce336bd08b7670b710d68dfce3..dec1b5270d58b559534c7472997539de55d44575 100644 (file)
 #[repr(transparent)]
 #[derive(Copy, Clone)]
 pub struct Pin<P> {
-    pointer: P,
+    // FIXME(#93176): this field is made `#[unstable] #[doc(hidden)] pub` to:
+    //   - deter downstream users from accessing it (which would be unsound!),
+    //   - let the `pin!` macro access it (such a macro requires using struct
+    //     literal syntax in order to benefit from lifetime extension).
+    // Long-term, `unsafe` fields or macro hygiene are expected to offer more robust alternatives.
+    #[unstable(feature = "unsafe_pin_internals", issue = "none")]
+    #[doc(hidden)]
+    pub pointer: P,
 }
 
 // The following implementations aren't derived in order to avoid soundness
@@ -909,3 +916,243 @@ impl<P, U> CoerceUnsized<Pin<U>> for Pin<P> where P: CoerceUnsized<U> {}
 
 #[stable(feature = "pin", since = "1.33.0")]
 impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
+
+/// Constructs a <code>[Pin]<[&mut] T></code>, by pinning[^1] a `value: T` _locally_[^2].
+///
+/// Unlike [`Box::pin`], this does not involve a heap allocation.
+///
+/// [^1]: If the (type `T` of the) given value does not implement [`Unpin`], then this
+/// effectively pins the `value` in memory, where it will be unable to be moved.
+/// Otherwise, <code>[Pin]<[&mut] T></code> behaves like <code>[&mut] T</code>, and operations such
+/// as [`mem::replace()`][crate::mem::replace] will allow extracting that value, and therefore,
+/// moving it.
+/// See [the `Unpin` section of the `pin` module][self#unpin] for more info.
+///
+/// [^2]: This is usually dubbed "stack"-pinning. And whilst local values are almost always located
+/// in the stack (_e.g._, when within the body of a non-`async` function), the truth is that inside
+/// the body of an `async fn` or block —more generally, the body of a generator— any locals crossing
+/// an `.await` point —a `yield` point— end up being part of the state captured by the `Future` —by
+/// the `Generator`—, and thus will be stored wherever that one is.
+///
+/// ## Examples
+///
+/// ### Basic usage
+///
+/// ```rust
+/// #![feature(pin_macro)]
+/// # use core::marker::PhantomPinned as Foo;
+/// use core::pin::{pin, Pin};
+///
+/// fn stuff(foo: Pin<&mut Foo>) {
+///     // …
+///     # let _ = foo;
+/// }
+///
+/// let pinned_foo = pin!(Foo { /* … */ });
+/// stuff(pinned_foo);
+/// // or, directly:
+/// stuff(pin!(Foo { /* … */ }));
+/// ```
+///
+/// ### Manually polling a `Future` (wihout `Unpin` bounds)
+///
+/// ```rust
+/// #![feature(pin_macro)]
+/// use std::{
+///     future::Future,
+///     pin::pin,
+///     task::{Context, Poll},
+///     thread,
+/// };
+/// # use std::{sync::Arc, task::Wake, thread::Thread};
+///
+/// # /// A waker that wakes up the current thread when called.
+/// # struct ThreadWaker(Thread);
+/// #
+/// # impl Wake for ThreadWaker {
+/// #     fn wake(self: Arc<Self>) {
+/// #         self.0.unpark();
+/// #     }
+/// # }
+/// #
+/// /// Runs a future to completion.
+/// fn block_on<Fut: Future>(fut: Fut) -> Fut::Output {
+///     let waker_that_unparks_thread = // …
+///         # Arc::new(ThreadWaker(thread::current())).into();
+///     let mut cx = Context::from_waker(&waker_that_unparks_thread);
+///     // Pin the future so it can be polled.
+///     let mut pinned_fut = pin!(fut);
+///     loop {
+///         match pinned_fut.as_mut().poll(&mut cx) {
+///             Poll::Pending => thread::park(),
+///             Poll::Ready(res) => return res,
+///         }
+///     }
+/// }
+/// #
+/// # assert_eq!(42, block_on(async { 42 }));
+/// ```
+///
+/// ### With `Generator`s
+///
+/// ```rust
+/// #![feature(generators, generator_trait, pin_macro)]
+/// use core::{
+///     ops::{Generator, GeneratorState},
+///     pin::pin,
+/// };
+///
+/// fn generator_fn() -> impl Generator<Yield = usize, Return = ()> /* not Unpin */ {
+///  // Allow generator to be self-referential (not `Unpin`)
+///  // vvvvvv        so that locals can cross yield points.
+///     static || {
+///         let foo = String::from("foo"); // --+
+///         yield 0;                         // | <- crosses yield point!
+///         println!("{}", &foo); // <----------+
+///         yield foo.len();
+///     }
+/// }
+///
+/// fn main() {
+///     let mut generator = pin!(generator_fn());
+///     match generator.as_mut().resume(()) {
+///         GeneratorState::Yielded(0) => {},
+///         _ => unreachable!(),
+///     }
+///     match generator.as_mut().resume(()) {
+///         GeneratorState::Yielded(3) => {},
+///         _ => unreachable!(),
+///     }
+///     match generator.resume(()) {
+///         GeneratorState::Yielded(_) => unreachable!(),
+///         GeneratorState::Complete(()) => {},
+///     }
+/// }
+/// ```
+///
+/// ## Remarks
+///
+/// Precisely because a value is pinned to local storage, the resulting <code>[Pin]<[&mut] T></code>
+/// reference ends up borrowing a local tied to that block: it can't escape it.
+///
+/// The following, for instance, fails to compile:
+///
+/// ```rust,compile_fail
+/// #![feature(pin_macro)]
+/// use core::pin::{pin, Pin};
+/// # use core::{marker::PhantomPinned as Foo, mem::drop as stuff};
+///
+/// let x: Pin<&mut Foo> = {
+///     let x: Pin<&mut Foo> = pin!(Foo { /* … */ });
+///     x
+/// }; // <- Foo is dropped
+/// stuff(x); // Error: use of dropped value
+/// ```
+///
+/// <details><summary>Error message</summary>
+///
+/// ```console
+/// error[E0716]: temporary value dropped while borrowed
+///   --> src/main.rs:9:28
+///    |
+/// 8  | let x: Pin<&mut Foo> = {
+///    |     - borrow later stored here
+/// 9  |     let x: Pin<&mut Foo> = pin!(Foo { /* … */ });
+///    |                            ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+/// 10 |     x
+/// 11 | }; // <- Foo is dropped
+///    | - temporary value is freed at the end of this statement
+///    |
+///    = note: consider using a `let` binding to create a longer lived value
+/// ```
+///
+/// </details>
+///
+/// This makes [`pin!`] **unsuitable to pin values when intending to _return_ them**. Instead, the
+/// value is expected to be passed around _unpinned_ until the point where it is to be consumed,
+/// where it is then useful and even sensible to pin the value locally using [`pin!`].
+///
+/// If you really need to return a pinned value, consider using [`Box::pin`] instead.
+///
+/// On the other hand, pinning to the stack[<sup>2</sup>](#fn2) using [`pin!`] is likely to be
+/// cheaper than pinning into a fresh heap allocation using [`Box::pin`]. Moreover, by virtue of not
+/// even needing an allocator, [`pin!`] is the main non-`unsafe` `#![no_std]`-compatible [`Pin`]
+/// constructor.
+///
+/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin
+#[unstable(feature = "pin_macro", issue = "93178")]
+#[rustc_macro_transparency = "semitransparent"]
+#[allow_internal_unstable(unsafe_pin_internals)]
+pub macro pin($value:expr $(,)?) {
+    // This is `Pin::new_unchecked(&mut { $value })`, so, for starters, let's
+    // review such a hypothetical macro (that any user-code could define):
+    //
+    // ```rust
+    // macro_rules! pin {( $value:expr ) => (
+    //     match &mut { $value } { at_value => unsafe { // Do not wrap `$value` in an `unsafe` block.
+    //         $crate::pin::Pin::<&mut _>::new_unchecked(at_value)
+    //     }}
+    // )}
+    // ```
+    //
+    // Safety:
+    //   - `type P = &mut _`. There are thus no pathological `Deref{,Mut}` impls
+    //     that would break `Pin`'s invariants.
+    //   - `{ $value }` is braced, making it a _block expression_, thus **moving**
+    //     the given `$value`, and making it _become an **anonymous** temporary_.
+    //     By virtue of being anonynomous, it can no longer be accessed, thus
+    //     preventing any attemps to `mem::replace` it or `mem::forget` it, _etc._
+    //
+    // This gives us a `pin!` definition that is sound, and which works, but only
+    // in certain scenarios:
+    //   - If the `pin!(value)` expression is _directly_ fed to a function call:
+    //     `let poll = pin!(fut).poll(cx);`
+    //   - If the `pin!(value)` expression is part of a scrutinee:
+    //     ```rust
+    //     match pin!(fut) { pinned_fut => {
+    //         pinned_fut.as_mut().poll(...);
+    //         pinned_fut.as_mut().poll(...);
+    //     }} // <- `fut` is dropped here.
+    //     ```
+    // Alas, it doesn't work for the more straight-forward use-case: `let` bindings.
+    // ```rust
+    // let pinned_fut = pin!(fut); // <- temporary value is freed at the end of this statement
+    // pinned_fut.poll(...) // error[E0716]: temporary value dropped while borrowed
+    //                      // note: consider using a `let` binding to create a longer lived value
+    // ```
+    //   - Issues such as this one are the ones motivating https://github.com/rust-lang/rfcs/pull/66
+    //
+    // This makes such a macro incredibly unergonomic in practice, and the reason most macros
+    // out there had to take the path of being a statement/binding macro (_e.g._, `pin!(future);`)
+    // instead of featuring the more intuitive ergonomics of an expression macro.
+    //
+    // Luckily, there is a way to avoid the problem. Indeed, the problem stems from the fact that a
+    // temporary is dropped at the end of its enclosing statement when it is part of the parameters
+    // given to function call, which has precisely been the case with our `Pin::new_unchecked()`!
+    // For instance,
+    // ```rust
+    // let p = Pin::new_unchecked(&mut <temporary>);
+    // ```
+    // becomes:
+    // ```rust
+    // let p = { let mut anon = <temporary>; &mut anon };
+    // ```
+    //
+    // However, when using a literal braced struct to construct the value, references to temporaries
+    // can then be taken. This makes Rust change the lifespan of such temporaries so that they are,
+    // instead, dropped _at the end of the enscoping block_.
+    // For instance,
+    // ```rust
+    // let p = Pin { pointer: &mut <temporary> };
+    // ```
+    // becomes:
+    // ```rust
+    // let mut anon = <temporary>;
+    // let p = Pin { pointer: &mut anon };
+    // ```
+    // which is *exactly* what we want.
+    //
+    // See https://doc.rust-lang.org/1.58.1/reference/destructors.html#temporary-lifetime-extension
+    // for more info.
+    $crate::pin::Pin::<&mut _> { pointer: &mut { $value } }
+}
index 3f5d3f62c96044b587868088eb7c5bad076a163e..0aa8e9960a8dd706db63cd1575f4a4ced3804880 100644 (file)
@@ -721,6 +721,9 @@ fn from(unique: Unique<T>) -> Self {
 #[stable(feature = "nonnull", since = "1.25.0")]
 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
 impl<T: ?Sized> const From<&mut T> for NonNull<T> {
+    /// Converts a `&mut T` to a `NonNull<T>`.
+    ///
+    /// This conversion is safe and infallible since references cannot be null.
     #[inline]
     fn from(reference: &mut T) -> Self {
         // SAFETY: A mutable reference cannot be null.
@@ -731,6 +734,9 @@ fn from(reference: &mut T) -> Self {
 #[stable(feature = "nonnull", since = "1.25.0")]
 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
 impl<T: ?Sized> const From<&T> for NonNull<T> {
+    /// Converts a `&T` to a `NonNull<T>`.
+    ///
+    /// This conversion is safe and infallible since references cannot be null.
     #[inline]
     fn from(reference: &T) -> Self {
         // SAFETY: A reference cannot be null, so the conditions for
index f5c624c225f26350b17c0b04cf36c928bb7fdc44..661d111c99d5294b7d7bf79db10aad7c5bb2b936 100644 (file)
@@ -178,6 +178,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 #[unstable(feature = "ptr_internals", issue = "none")]
 impl<T: ?Sized> const From<&mut T> for Unique<T> {
+    /// Converts a `&mut T` to a `Unique<T>`.
+    ///
+    /// This conversion is infallible since references cannot be null.
     #[inline]
     fn from(reference: &mut T) -> Self {
         // SAFETY: A mutable reference cannot be null
index fbd6d419236ae110240b9eb4b91ebfd113d3d0dd..801e3a0b3a4ccaf34038d70ed286bd3185d7802f 100644 (file)
@@ -1281,16 +1281,28 @@ pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> {
     ///
     /// # Examples
     ///
-    /// Basic usage:
+    /// ```
+    /// fn sq_then_to_string(x: u32) -> Result<String, &'static str> {
+    ///     x.checked_mul(x).map(|sq| sq.to_string()).ok_or("overflowed")
+    /// }
     ///
+    /// assert_eq!(Ok(2).and_then(sq_then_to_string), Ok(4.to_string()));
+    /// assert_eq!(Ok(1_000_000).and_then(sq_then_to_string), Err("overflowed"));
+    /// assert_eq!(Err("not a number").and_then(sq_then_to_string), Err("not a number"));
     /// ```
-    /// fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
-    /// fn err(x: u32) -> Result<u32, u32> { Err(x) }
     ///
-    /// assert_eq!(Ok(2).and_then(sq).and_then(sq), Ok(16));
-    /// assert_eq!(Ok(2).and_then(sq).and_then(err), Err(4));
-    /// assert_eq!(Ok(2).and_then(err).and_then(sq), Err(2));
-    /// assert_eq!(Err(3).and_then(sq).and_then(sq), Err(3));
+    /// Often used to chain fallible operations that may return [`Err`].
+    ///
+    /// ```
+    /// use std::{io::ErrorKind, path::Path};
+    ///
+    /// // Note: on Windows "/" maps to "C:\"
+    /// let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified());
+    /// assert!(root_modified_time.is_ok());
+    ///
+    /// let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified());
+    /// assert!(should_fail.is_err());
+    /// assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -2016,7 +2028,7 @@ fn from_iter<I: IntoIterator<Item = Result<A, E>>>(iter: I) -> Result<V, E> {
         // FIXME(#11084): This could be replaced with Iterator::scan when this
         // performance bug is closed.
 
-        iter::process_results(iter.into_iter(), |i| i.collect())
+        iter::try_process(iter.into_iter(), |i| i.collect())
     }
 }
 
index 080256f493f5ffe95d2148d88f4f2ab384fb49c0..304ba7ee5544f9abf264751ba7320372fb470368 100644 (file)
@@ -68,7 +68,6 @@ pub fn make_ascii_lowercase(&mut self) {
     /// # Examples
     ///
     /// ```
-    /// #![feature(inherent_ascii_escape)]
     ///
     /// let s = b"0\t\r\n'\"\\\x9d";
     /// let escaped = s.escape_ascii().to_string();
@@ -76,7 +75,7 @@ pub fn make_ascii_lowercase(&mut self) {
     /// ```
     #[must_use = "this returns the escaped bytes as an iterator, \
                   without modifying the original"]
-    #[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+    #[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
     pub fn escape_ascii(&self) -> EscapeAscii<'_> {
         EscapeAscii { inner: self.iter().flat_map(EscapeByte) }
     }
@@ -93,13 +92,13 @@ struct EscapeByte impl Fn = |byte: &u8| -> ascii::EscapeDefault {
 ///
 /// This `struct` is created by the [`slice::escape_ascii`] method. See its
 /// documentation for more information.
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 #[derive(Clone)]
 pub struct EscapeAscii<'a> {
     inner: iter::FlatMap<super::Iter<'a, u8>, ascii::EscapeDefault, EscapeByte>,
 }
 
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> iter::Iterator for EscapeAscii<'a> {
     type Item = u8;
     #[inline]
@@ -131,23 +130,23 @@ fn last(mut self) -> Option<u8> {
     }
 }
 
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> iter::DoubleEndedIterator for EscapeAscii<'a> {
     fn next_back(&mut self) -> Option<u8> {
         self.inner.next_back()
     }
 }
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> iter::ExactSizeIterator for EscapeAscii<'a> {}
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> iter::FusedIterator for EscapeAscii<'a> {}
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> fmt::Display for EscapeAscii<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         self.clone().try_for_each(|b| f.write_char(b as char))
     }
 }
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 impl<'a> fmt::Debug for EscapeAscii<'a> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("EscapeAscii").finish_non_exhaustive()
index 72af47c71dd64333b9c4d4e12c9104540678736b..27c6b6f5bc02f474a8954a54c53de4f7f6347ed9 100644 (file)
@@ -1,7 +1,6 @@
 //! Comparison traits for `[T]`.
 
-use crate::cmp;
-use crate::cmp::Ordering::{self, Greater, Less};
+use crate::cmp::{self, Ordering};
 use crate::mem;
 
 use super::from_raw_parts;
@@ -189,18 +188,18 @@ impl<A: Ord> SliceOrd for A {
 impl SliceOrd for u8 {
     #[inline]
     fn compare(left: &[Self], right: &[Self]) -> Ordering {
-        let order =
-            // SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
-            // We use the minimum of both lengths which guarantees that both regions are
-            // valid for reads in that interval.
-            unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) };
+        // Since the length of a slice is always less than or equal to isize::MAX, this never underflows.
+        let diff = left.len() as isize - right.len() as isize;
+        // This comparison gets optimized away (on x86_64 and ARM) because the subtraction updates flags.
+        let len = if left.len() < right.len() { left.len() } else { right.len() };
+        // SAFETY: `left` and `right` are references and are thus guaranteed to be valid.
+        // We use the minimum of both lengths which guarantees that both regions are
+        // valid for reads in that interval.
+        let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize };
         if order == 0 {
-            left.len().cmp(&right.len())
-        } else if order < 0 {
-            Less
-        } else {
-            Greater
+            order = diff;
         }
+        order.cmp(&0)
     }
 }
 
index 4e22c1d8c6d94e999f5c783d6c140bac9c1eafd1..cd38c3a75473d4c1393823bb1afab8ef61812654 100644 (file)
@@ -81,7 +81,7 @@
 #[unstable(feature = "slice_range", issue = "76393")]
 pub use index::range;
 
-#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
+#[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 pub use ascii::EscapeAscii;
 
 /// Calculates the direction and split point of a one-sided range.
diff --git a/library/core/src/str/count.rs b/library/core/src/str/count.rs
new file mode 100644 (file)
index 0000000..5abc2b3
--- /dev/null
@@ -0,0 +1,136 @@
+//! Code for efficiently counting the number of `char`s in a UTF-8 encoded
+//! string.
+//!
+//! Broadly, UTF-8 encodes `char`s as a "leading" byte which begins the `char`,
+//! followed by some number (possibly 0) of continuation bytes.
+//!
+//! The leading byte can have a number of bit-patterns (with the specific
+//! pattern indicating how many continuation bytes follow), but the continuation
+//! bytes are always in the format `0b10XX_XXXX` (where the `X`s can take any
+//! value). That is, the most significant bit is set, and the second most
+//! significant bit is unset.
+//!
+//! To count the number of characters, we can just count the number of bytes in
+//! the string which are not continuation bytes, which can be done many bytes at
+//! a time fairly easily.
+//!
+//! Note: Because the term "leading byte" can sometimes be ambiguous (for
+//! example, it could also refer to the first byte of a slice), we'll often use
+//! the term "non-continuation byte" to refer to these bytes in the code.
+use core::intrinsics::unlikely;
+
+const USIZE_SIZE: usize = core::mem::size_of::<usize>();
+const UNROLL_INNER: usize = 4;
+
+#[inline]
+pub(super) fn count_chars(s: &str) -> usize {
+    if s.len() < USIZE_SIZE * UNROLL_INNER {
+        // Avoid entering the optimized implementation for strings where the
+        // difference is not likely to matter, or where it might even be slower.
+        // That said, a ton of thought was not spent on the particular threshold
+        // here, beyond "this value seems to make sense".
+        char_count_general_case(s.as_bytes())
+    } else {
+        do_count_chars(s)
+    }
+}
+
+fn do_count_chars(s: &str) -> usize {
+    // For correctness, `CHUNK_SIZE` must be:
+    //
+    // - Less than or equal to 255, otherwise we'll overflow bytes in `counts`.
+    // - A multiple of `UNROLL_INNER`, otherwise our `break` inside the
+    //   `body.chunks(CHUNK_SIZE)` loop is incorrect.
+    //
+    // For performance, `CHUNK_SIZE` should be:
+    // - Relatively cheap to `/` against (so some simple sum of powers of two).
+    // - Large enough to avoid paying for the cost of the `sum_bytes_in_usize`
+    //   too often.
+    const CHUNK_SIZE: usize = 192;
+
+    // Check the properties of `CHUNK_SIZE` and `UNROLL_INNER` that are required
+    // for correctness.
+    const _: () = assert!(CHUNK_SIZE < 256);
+    const _: () = assert!(CHUNK_SIZE % UNROLL_INNER == 0);
+
+    // SAFETY: transmuting `[u8]` to `[usize]` is safe except for size
+    // differences which are handled by `align_to`.
+    let (head, body, tail) = unsafe { s.as_bytes().align_to::<usize>() };
+
+    // This should be quite rare, and basically exists to handle the degenerate
+    // cases where align_to fails (as well as miri under symbolic alignment
+    // mode).
+    //
+    // The `unlikely` helps discourage LLVM from inlining the body, which is
+    // nice, as we would rather not mark the `char_count_general_case` function
+    // as cold.
+    if unlikely(body.is_empty() || head.len() > USIZE_SIZE || tail.len() > USIZE_SIZE) {
+        return char_count_general_case(s.as_bytes());
+    }
+
+    let mut total = char_count_general_case(head) + char_count_general_case(tail);
+    // Split `body` into `CHUNK_SIZE` chunks to reduce the frequency with which
+    // we call `sum_bytes_in_usize`.
+    for chunk in body.chunks(CHUNK_SIZE) {
+        // We accumulate intermediate sums in `counts`, where each byte contains
+        // a subset of the sum of this chunk, like a `[u8; size_of::<usize>()]`.
+        let mut counts = 0;
+
+        let (unrolled_chunks, remainder) = chunk.as_chunks::<UNROLL_INNER>();
+        for unrolled in unrolled_chunks {
+            for &word in unrolled {
+                // Because `CHUNK_SIZE` is < 256, this addition can't cause the
+                // count in any of the bytes to overflow into a subsequent byte.
+                counts += contains_non_continuation_byte(word);
+            }
+        }
+
+        // Sum the values in `counts` (which, again, is conceptually a `[u8;
+        // size_of::<usize>()]`), and accumulate the result into `total`.
+        total += sum_bytes_in_usize(counts);
+
+        // If there's any data in `remainder`, then handle it. This will only
+        // happen for the last `chunk` in `body.chunks()` (because `CHUNK_SIZE`
+        // is divisible by `UNROLL_INNER`), so we explicitly break at the end
+        // (which seems to help LLVM out).
+        if !remainder.is_empty() {
+            // Accumulate all the data in the remainder.
+            let mut counts = 0;
+            for &word in remainder {
+                counts += contains_non_continuation_byte(word);
+            }
+            total += sum_bytes_in_usize(counts);
+            break;
+        }
+    }
+    total
+}
+
+// Checks each byte of `w` to see if it contains the first byte in a UTF-8
+// sequence. Bytes in `w` which are continuation bytes are left as `0x00` (e.g.
+// false), and bytes which are non-continuation bytes are left as `0x01` (e.g.
+// true)
+#[inline]
+fn contains_non_continuation_byte(w: usize) -> usize {
+    const LSB: usize = 0x0101_0101_0101_0101u64 as usize;
+    ((!w >> 7) | (w >> 6)) & LSB
+}
+
+// Morally equivalent to `values.to_ne_bytes().into_iter().sum::<usize>()`, but
+// more efficient.
+#[inline]
+fn sum_bytes_in_usize(values: usize) -> usize {
+    const LSB_SHORTS: usize = 0x0001_0001_0001_0001_u64 as usize;
+    const SKIP_BYTES: usize = 0x00ff_00ff_00ff_00ff_u64 as usize;
+
+    let pair_sum: usize = (values & SKIP_BYTES) + ((values >> 8) & SKIP_BYTES);
+    pair_sum.wrapping_mul(LSB_SHORTS) >> ((USIZE_SIZE - 2) * 8)
+}
+
+// This is the most direct implementation of the concept of "count the number of
+// bytes in the string which are not continuation bytes", and is used for the
+// head and tail of the input string (the first and last item in the tuple
+// returned by `slice::align_to`).
+fn char_count_general_case(s: &[u8]) -> usize {
+    s.iter().filter(|&&byte| !super::validations::utf8_is_cont_byte(byte)).count()
+}
index de6e6d52b362543d455664e25cf0c8bd58818d10..e529bccbc7999ee1ea852e4cc6cd90cab17101cc 100644 (file)
@@ -12,7 +12,7 @@
 use super::from_utf8_unchecked;
 use super::pattern::Pattern;
 use super::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher};
-use super::validations::{next_code_point, next_code_point_reverse, utf8_is_cont_byte};
+use super::validations::{next_code_point, next_code_point_reverse};
 use super::LinesAnyMap;
 use super::{BytesIsNotEmpty, UnsafeBytesToStr};
 use super::{CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode};
@@ -46,8 +46,7 @@ fn next(&mut self) -> Option<char> {
 
     #[inline]
     fn count(self) -> usize {
-        // length in `char` is equal to the number of non-continuation bytes
-        self.iter.filter(|&&byte| !utf8_is_cont_byte(byte)).count()
+        super::count::count_chars(self.as_str())
     }
 
     #[inline]
index 1d4600fa4a2d7e0917e8e26e8ae1b3a125a140b8..09709dc3cf6dfbd187f2ecfe020ad0a6a07fbe33 100644 (file)
@@ -7,6 +7,7 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 mod converts;
+mod count;
 mod error;
 mod iter;
 mod traits;
 use iter::SplitInternal;
 use iter::{MatchesInternal, SplitNInternal};
 
-use validations::truncate_to_char_boundary;
-
 #[inline(never)]
 #[cold]
 #[track_caller]
 fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
     const MAX_DISPLAY_LENGTH: usize = 256;
-    let (truncated, s_trunc) = truncate_to_char_boundary(s, MAX_DISPLAY_LENGTH);
-    let ellipsis = if truncated { "[...]" } else { "" };
+    let trunc_len = s.floor_char_boundary(MAX_DISPLAY_LENGTH);
+    let s_trunc = &s[..trunc_len];
+    let ellipsis = if trunc_len < s.len() { "[...]" } else { "" };
 
     // 1. out of bounds
     if begin > s.len() || end > s.len() {
@@ -104,10 +104,7 @@ fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! {
     // 3. character boundary
     let index = if !s.is_char_boundary(begin) { begin } else { end };
     // find the character
-    let mut char_start = index;
-    while !s.is_char_boundary(char_start) {
-        char_start -= 1;
-    }
+    let char_start = s.floor_char_boundary(index);
     // `char_start` must be less than len and a char boundary
     let ch = s[char_start..].chars().next().unwrap();
     let char_range = char_start..char_start + ch.len_utf8();
@@ -214,8 +211,80 @@ pub fn is_char_boundary(&self, index: usize) -> bool {
             // code on higher opt-levels. See PR #84751 for more details.
             None => index == self.len(),
 
-            // This is bit magic equivalent to: b < 128 || b >= 192
-            Some(&b) => (b as i8) >= -0x40,
+            Some(&b) => b.is_utf8_char_boundary(),
+        }
+    }
+
+    /// Finds the closest `x` not exceeding `index` where `is_char_boundary(x)` is `true`.
+    ///
+    /// This method can help you truncate a string so that it's still valid UTF-8, but doesn't
+    /// exceed a given number of bytes. Note that this is done purely at the character level
+    /// and can still visually split graphemes, even though the underlying characters aren't
+    /// split. For example, the emoji 🧑‍🔬 (scientist) could be split so that the string only
+    /// includes 🧑 (person) instead.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(round_char_boundary)]
+    /// let s = "❤️🧡💛💚💙💜";
+    /// assert_eq!(s.len(), 26);
+    /// assert!(!s.is_char_boundary(13));
+    ///
+    /// let closest = s.floor_char_boundary(13);
+    /// assert_eq!(closest, 10);
+    /// assert_eq!(&s[..closest], "❤️🧡");
+    /// ```
+    #[unstable(feature = "round_char_boundary", issue = "93743")]
+    #[inline]
+    pub fn floor_char_boundary(&self, index: usize) -> usize {
+        if index >= self.len() {
+            self.len()
+        } else {
+            let lower_bound = index.saturating_sub(3);
+            let new_index = self.as_bytes()[lower_bound..=index]
+                .iter()
+                .rposition(|b| b.is_utf8_char_boundary());
+
+            // SAFETY: we know that the character boundary will be within four bytes
+            unsafe { lower_bound + new_index.unwrap_unchecked() }
+        }
+    }
+
+    /// Finds the closest `x` not below `index` where `is_char_boundary(x)` is `true`.
+    ///
+    /// This method is the natural complement to [`floor_char_boundary`]. See that method
+    /// for more details.
+    ///
+    /// [`floor_char_boundary`]: str::floor_char_boundary
+    ///
+    /// # Panics
+    ///
+    /// Panics if `index > self.len()`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(round_char_boundary)]
+    /// let s = "❤️🧡💛💚💙💜";
+    /// assert_eq!(s.len(), 26);
+    /// assert!(!s.is_char_boundary(13));
+    ///
+    /// let closest = s.ceil_char_boundary(13);
+    /// assert_eq!(closest, 14);
+    /// assert_eq!(&s[..closest], "❤️🧡💛");
+    /// ```
+    #[unstable(feature = "round_char_boundary", issue = "93743")]
+    #[inline]
+    pub fn ceil_char_boundary(&self, index: usize) -> usize {
+        if index > self.len() {
+            slice_error_fail(self, index, index)
+        } else {
+            let upper_bound = Ord::min(index + 4, self.len());
+            self.as_bytes()[index..upper_bound]
+                .iter()
+                .position(|b| b.is_utf8_char_boundary())
+                .map_or(upper_bound, |pos| pos + index)
         }
     }
 
index b2ea86d699aa6bf6f88c4dce209189e830ae241e..0d3dc856be577c44669176a29cb182c6cdc95316 100644 (file)
@@ -273,16 +273,3 @@ pub const fn utf8_char_width(b: u8) -> usize {
 
 /// Mask of the value bits of a continuation byte.
 const CONT_MASK: u8 = 0b0011_1111;
-
-// truncate `&str` to length at most equal to `max`
-// return `true` if it were truncated, and the new str.
-pub(super) fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) {
-    if max >= s.len() {
-        (false, s)
-    } else {
-        while !s.is_char_boundary(max) {
-            max -= 1;
-        }
-        (true, &s[..max])
-    }
-}
index 792016902aebe925b42f2e11bd7682f9c59263c3..9ee88dd601493a03f910e583dd674801a0bf811c 100644 (file)
@@ -1295,6 +1295,7 @@ fn from(b: bool) -> Self {
 #[stable(feature = "atomic_from", since = "1.23.0")]
 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
 impl<T> const From<*mut T> for AtomicPtr<T> {
+    /// Converts a `*mut T` into an `AtomicPtr<T>`.
     #[inline]
     fn from(p: *mut T) -> Self {
         Self::new(p)
index 72a030617ad8ad387059f03450c43c73172428e6..41f0a25dbc3e08daa688c5b6202ba987d468765a 100644 (file)
@@ -243,7 +243,7 @@ pub fn map_err<U, F>(self, f: F) -> Poll<Option<Result<T, U>>>
 #[stable(feature = "futures_api", since = "1.36.0")]
 #[rustc_const_unstable(feature = "const_convert", issue = "88674")]
 impl<T> const From<T> for Poll<T> {
-    /// Convert to a `Ready` variant.
+    /// Moves the value into a [`Poll::Ready`] to make a `Poll<T>`.
     ///
     /// # Example
     ///
index 0ed8c52c21224a7b22676ec7aeb97301f36718d8..74b6f74e4013ce3271cc3d97f11025b0a697f2fd 100644 (file)
@@ -118,3 +118,11 @@ fn wake(self: Arc<Self>) {
         }
     }
 }
+
+// just tests by whether or not this compiles
+fn _pending_impl_all_auto_traits<T>() {
+    use std::panic::{RefUnwindSafe, UnwindSafe};
+    fn all_auto_traits<T: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe>() {}
+
+    all_auto_traits::<std::future::Pending<T>>();
+}
index 72ccdd4848a47ec4979c12744f3173b3ca286b84..a173e461c606f6e69d5ccbb170555fdc726c326d 100644 (file)
@@ -146,3 +146,11 @@ fn test_build_hasher_object_safe() {
 
     let _: &dyn BuildHasher<Hasher = DefaultHasher> = &RandomState::new();
 }
+
+// just tests by whether or not this compiles
+fn _build_hasher_default_impl_all_auto_traits<T>() {
+    use std::panic::{RefUnwindSafe, UnwindSafe};
+    fn all_auto_traits<T: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe>() {}
+
+    all_auto_traits::<std::hash::BuildHasherDefault<T>>();
+}
index bb4da831412770386744bc4cdc73cbe3d4a080b0..cf69f0a7a4d7e7e687bf781a33f4b050554a3c87 100644 (file)
@@ -496,3 +496,57 @@ fn test_collect() {
     let b: Vec<isize> = a.iter().cloned().collect();
     assert!(a == b);
 }
+
+#[test]
+fn test_try_collect() {
+    use core::ops::ControlFlow::{Break, Continue};
+
+    let u = vec![Some(1), Some(2), Some(3)];
+    let v = u.into_iter().try_collect::<Vec<i32>>();
+    assert_eq!(v, Some(vec![1, 2, 3]));
+
+    let u = vec![Some(1), Some(2), None, Some(3)];
+    let mut it = u.into_iter();
+    let v = it.try_collect::<Vec<i32>>();
+    assert_eq!(v, None);
+    let v = it.try_collect::<Vec<i32>>();
+    assert_eq!(v, Some(vec![3]));
+
+    let u: Vec<Result<i32, ()>> = vec![Ok(1), Ok(2), Ok(3)];
+    let v = u.into_iter().try_collect::<Vec<i32>>();
+    assert_eq!(v, Ok(vec![1, 2, 3]));
+
+    let u = vec![Ok(1), Ok(2), Err(()), Ok(3)];
+    let v = u.into_iter().try_collect::<Vec<i32>>();
+    assert_eq!(v, Err(()));
+
+    let numbers = vec![1, 2, 3, 4, 5];
+    let all_positive = numbers
+        .iter()
+        .cloned()
+        .map(|n| if n > 0 { Some(n) } else { None })
+        .try_collect::<Vec<i32>>();
+    assert_eq!(all_positive, Some(numbers));
+
+    let numbers = vec![-2, -1, 0, 1, 2];
+    let all_positive =
+        numbers.into_iter().map(|n| if n > 0 { Some(n) } else { None }).try_collect::<Vec<i32>>();
+    assert_eq!(all_positive, None);
+
+    let u = [Continue(1), Continue(2), Break(3), Continue(4), Continue(5)];
+    let mut it = u.into_iter();
+
+    let v = it.try_collect::<Vec<_>>();
+    assert_eq!(v, Break(3));
+
+    let v = it.try_collect::<Vec<_>>();
+    assert_eq!(v, Continue(vec![4, 5]));
+}
+
+// just tests by whether or not this compiles
+fn _empty_impl_all_auto_traits<T>() {
+    use std::panic::{RefUnwindSafe, UnwindSafe};
+    fn all_auto_traits<T: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe>() {}
+
+    all_auto_traits::<std::iter::Empty<T>>();
+}
index a993def0a818ef98375d4a65ff1a7ee65b7f6a3b..32f3405243ceaa6d8cfff8ab074ddc5f22bff116 100644 (file)
@@ -7,7 +7,7 @@
 #![feature(box_syntax)]
 #![feature(cell_update)]
 #![feature(cfg_panic)]
-#![feature(cfg_target_has_atomic)]
+#![cfg_attr(bootstrap, feature(cfg_target_has_atomic))]
 #![feature(const_assume)]
 #![feature(const_black_box)]
 #![feature(const_bool_to_option)]
@@ -45,6 +45,7 @@
 #![feature(inline_const)]
 #![feature(is_sorted)]
 #![feature(pattern)]
+#![feature(pin_macro)]
 #![feature(sort_internals)]
 #![feature(slice_take)]
 #![feature(maybe_uninit_uninit_array)]
@@ -66,6 +67,7 @@
 #![feature(iter_intersperse)]
 #![feature(iter_is_partitioned)]
 #![feature(iter_order_by)]
+#![feature(iterator_try_collect)]
 #![feature(iterator_try_reduce)]
 #![feature(const_mut_refs)]
 #![feature(const_pin)]
 mod option;
 mod pattern;
 mod pin;
+mod pin_macro;
 mod ptr;
 mod result;
 mod simd;
diff --git a/library/core/tests/pin_macro.rs b/library/core/tests/pin_macro.rs
new file mode 100644 (file)
index 0000000..79c8c16
--- /dev/null
@@ -0,0 +1,33 @@
+// edition:2021
+use core::{
+    marker::PhantomPinned,
+    mem::{drop as stuff, transmute},
+    pin::{pin, Pin},
+};
+
+#[test]
+fn basic() {
+    let it: Pin<&mut PhantomPinned> = pin!(PhantomPinned);
+    stuff(it);
+}
+
+#[test]
+fn extension_works_through_block() {
+    let it: Pin<&mut PhantomPinned> = { pin!(PhantomPinned) };
+    stuff(it);
+}
+
+#[test]
+fn extension_works_through_unsafe_block() {
+    // "retro-type-inference" works as well.
+    let it: Pin<&mut PhantomPinned> = unsafe { pin!(transmute(())) };
+    stuff(it);
+}
+
+#[test]
+fn unsize_coercion() {
+    let slice: Pin<&mut [PhantomPinned]> = pin!([PhantomPinned; 2]);
+    stuff(slice);
+    let dyn_obj: Pin<&mut dyn Send> = pin!([PhantomPinned; 2]);
+    stuff(dyn_obj);
+}
index 9d6ede73e3db12e8ae137464e8d21f9bee1611fb..a0297b4b2f524f783a535b16254730bb633aba59 100644 (file)
@@ -105,6 +105,9 @@ fn rust_exception_class() -> uw::_Unwind_Exception_Class {
 #[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
 const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 / X0, X1
 
+#[cfg(target_arch = "m68k")]
+const UNWIND_DATA_REG: (i32, i32) = (0, 1); // D0, D1
+
 #[cfg(any(target_arch = "mips", target_arch = "mips64"))]
 const UNWIND_DATA_REG: (i32, i32) = (4, 5); // A0, A1
 
index de26d9dcb2627fa6aaa82d0d17b91d3ef5fd69b8..146096535dbbe128933208e464d3aa8da4125892 100644 (file)
@@ -16,7 +16,7 @@ panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
 libc = { version = "0.2.116", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.67" }
+compiler_builtins = { version = "0.1.69" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
 hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] }
index c06928647d3897761ee40c2a5b941f60576b4d5d..5ed9fa9d6f0fd1a956c3a0ce84e16066d33befa8 100644 (file)
 
 /// Returns the current working directory as a [`PathBuf`].
 ///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `getcwd` function on Unix
+/// and the `GetCurrentDirectoryW` function on Windows.
+///
 /// # Errors
 ///
 /// Returns an [`Err`] if the current working directory value is invalid.
@@ -49,6 +54,11 @@ pub fn current_dir() -> io::Result<PathBuf> {
 
 /// Changes the current working directory to the specified path.
 ///
+/// # Platform-specific behavior
+///
+/// This function currently corresponds to the `chdir` function on Unix
+/// and the `SetCurrentDirectoryW` function on Windows.
+///
 /// Returns an [`Err`] if the operation fails.
 ///
 /// # Examples
index 66fee2fe548374dbd02eaaf7d62fd5f5a7f34282..6e70d5ca02d7532f48359ce5bc2cb98f129a294c 100644 (file)
@@ -871,6 +871,8 @@ fn borrow(&self) -> &CStr {
 
 #[stable(feature = "cstring_from_cow_cstr", since = "1.28.0")]
 impl<'a> From<Cow<'a, CStr>> for CString {
+    /// Converts a `Cow<'a, CStr>` into a `CString`, by copying the contents if they are
+    /// borrowed.
     #[inline]
     fn from(s: Cow<'a, CStr>) -> Self {
         s.into_owned()
@@ -879,6 +881,8 @@ fn from(s: Cow<'a, CStr>) -> Self {
 
 #[stable(feature = "box_from_c_str", since = "1.17.0")]
 impl From<&CStr> for Box<CStr> {
+    /// Converts a `&CStr` into a `Box<CStr>`,
+    /// by copying the contents into a newly allocated [`Box`].
     fn from(s: &CStr) -> Box<CStr> {
         let boxed: Box<[u8]> = Box::from(s.to_bytes_with_nul());
         unsafe { Box::from_raw(Box::into_raw(boxed) as *mut CStr) }
@@ -887,6 +891,8 @@ fn from(s: &CStr) -> Box<CStr> {
 
 #[stable(feature = "box_from_cow", since = "1.45.0")]
 impl From<Cow<'_, CStr>> for Box<CStr> {
+    /// Converts a `Cow<'a, CStr>` into a `Box<CStr>`,
+    /// by copying the contents if they are borrowed.
     #[inline]
     fn from(cow: Cow<'_, CStr>) -> Box<CStr> {
         match cow {
@@ -984,6 +990,8 @@ fn from(s: CString) -> Arc<CStr> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<&CStr> for Arc<CStr> {
+    /// Converts a `&CStr` into a `Arc<CStr>`,
+    /// by copying the contents into a newly allocated [`Arc`].
     #[inline]
     fn from(s: &CStr) -> Arc<CStr> {
         let arc: Arc<[u8]> = Arc::from(s.to_bytes_with_nul());
@@ -1004,6 +1012,8 @@ fn from(s: CString) -> Rc<CStr> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<&CStr> for Rc<CStr> {
+    /// Converts a `&CStr` into a `Rc<CStr>`,
+    /// by copying the contents into a newly allocated [`Rc`].
     #[inline]
     fn from(s: &CStr) -> Rc<CStr> {
         let rc: Rc<[u8]> = Rc::from(s.to_bytes_with_nul());
@@ -1077,7 +1087,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl From<NulError> for io::Error {
     /// Converts a [`NulError`] into a [`io::Error`].
     fn from(_: NulError) -> io::Error {
-        io::Error::new_const(io::ErrorKind::InvalidInput, &"data provided contains a nul byte")
+        io::const_io_error!(io::ErrorKind::InvalidInput, "data provided contains a nul byte")
     }
 }
 
@@ -1252,15 +1262,16 @@ pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
     /// assert!(cstr.is_err());
     /// ```
     #[stable(feature = "cstr_from_bytes", since = "1.10.0")]
-    pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&CStr, FromBytesWithNulError> {
+    pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
         let nul_pos = memchr::memchr(0, bytes);
-        if let Some(nul_pos) = nul_pos {
-            if nul_pos + 1 != bytes.len() {
-                return Err(FromBytesWithNulError::interior_nul(nul_pos));
+        match nul_pos {
+            Some(nul_pos) if nul_pos + 1 == bytes.len() => {
+                // SAFETY: We know there is only one nul byte, at the end
+                // of the byte slice.
+                Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
             }
-            Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) })
-        } else {
-            Err(FromBytesWithNulError::not_nul_terminated())
+            Some(nul_pos) => Err(FromBytesWithNulError::interior_nul(nul_pos)),
+            None => Err(FromBytesWithNulError::not_nul_terminated()),
         }
     }
 
@@ -1529,6 +1540,7 @@ fn clone_into(&self, target: &mut CString) {
 
 #[stable(feature = "cstring_asref", since = "1.7.0")]
 impl From<&CStr> for CString {
+    /// Copies the contents of the `&CStr` into a newly allocated `CString`.
     fn from(s: &CStr) -> CString {
         s.to_owned()
     }
index 81f72e34d93889fdd1a4216abaa35af97a09e6e5..9b5e5d6c0cc4b1d377896ba1ba8d7dc444a2bfe3 100644 (file)
@@ -452,6 +452,8 @@ fn from(s: String) -> OsString {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + AsRef<OsStr>> From<&T> for OsString {
+    /// Copies any value implementing <code>[AsRef]&lt;[OsStr]&gt;</code>
+    /// into a newly allocated [`OsString`].
     fn from(s: &T) -> OsString {
         s.as_ref().to_os_string()
     }
@@ -942,6 +944,7 @@ pub fn eq_ignore_ascii_case<S: AsRef<OsStr>>(&self, other: S) -> bool {
 
 #[stable(feature = "box_from_os_str", since = "1.17.0")]
 impl From<&OsStr> for Box<OsStr> {
+    /// Copies the string into a newly allocated <code>[Box]&lt;[OsStr]&gt;</code>.
     #[inline]
     fn from(s: &OsStr) -> Box<OsStr> {
         let rw = Box::into_raw(s.inner.into_box()) as *mut OsStr;
@@ -951,6 +954,8 @@ fn from(s: &OsStr) -> Box<OsStr> {
 
 #[stable(feature = "box_from_cow", since = "1.45.0")]
 impl From<Cow<'_, OsStr>> for Box<OsStr> {
+    /// Converts a `Cow<'a, OsStr>` into a <code>[Box]&lt;[OsStr]&gt;</code>,
+    /// by copying the contents if they are borrowed.
     #[inline]
     fn from(cow: Cow<'_, OsStr>) -> Box<OsStr> {
         match cow {
@@ -1000,6 +1005,7 @@ fn from(s: OsString) -> Arc<OsStr> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<&OsStr> for Arc<OsStr> {
+    /// Copies the string into a newly allocated <code>[Arc]&lt;[OsStr]&gt;</code>.
     #[inline]
     fn from(s: &OsStr) -> Arc<OsStr> {
         let arc = s.inner.into_arc();
@@ -1020,6 +1026,7 @@ fn from(s: OsString) -> Rc<OsStr> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<&OsStr> for Rc<OsStr> {
+    /// Copies the string into a newly allocated <code>[Rc]&lt;[OsStr]&gt;</code>.
     #[inline]
     fn from(s: &OsStr) -> Rc<OsStr> {
         let rc = s.inner.into_rc();
@@ -1029,6 +1036,7 @@ fn from(s: &OsStr) -> Rc<OsStr> {
 
 #[stable(feature = "cow_from_osstr", since = "1.28.0")]
 impl<'a> From<OsString> for Cow<'a, OsStr> {
+    /// Moves the string into a [`Cow::Owned`].
     #[inline]
     fn from(s: OsString) -> Cow<'a, OsStr> {
         Cow::Owned(s)
@@ -1037,6 +1045,7 @@ fn from(s: OsString) -> Cow<'a, OsStr> {
 
 #[stable(feature = "cow_from_osstr", since = "1.28.0")]
 impl<'a> From<&'a OsStr> for Cow<'a, OsStr> {
+    /// Converts the string reference into a [`Cow::Borrowed`].
     #[inline]
     fn from(s: &'a OsStr) -> Cow<'a, OsStr> {
         Cow::Borrowed(s)
@@ -1045,6 +1054,7 @@ fn from(s: &'a OsStr) -> Cow<'a, OsStr> {
 
 #[stable(feature = "cow_from_osstr", since = "1.28.0")]
 impl<'a> From<&'a OsString> for Cow<'a, OsStr> {
+    /// Converts the string reference into a [`Cow::Borrowed`].
     #[inline]
     fn from(s: &'a OsString) -> Cow<'a, OsStr> {
         Cow::Borrowed(s.as_os_str())
@@ -1053,6 +1063,8 @@ fn from(s: &'a OsString) -> Cow<'a, OsStr> {
 
 #[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")]
 impl<'a> From<Cow<'a, OsStr>> for OsString {
+    /// Converts a `Cow<'a, OsStr>` into an [`OsString`],
+    /// by copying the contents if they are borrowed.
     #[inline]
     fn from(s: Cow<'a, OsStr>) -> Self {
         s.into_owned()
index 9d6b2fe8c25d845b9811385c57fa3b7f3f79a4a5..0b65336a5a7dac2b6d499026dec5ebd7f334a04e 100644 (file)
@@ -2044,7 +2044,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 ///
 /// This function currently corresponds to `openat`, `fdopendir`, `unlinkat` and `lstat` functions
 /// on Unix (except for macOS before version 10.10 and REDOX) and the `CreateFileW`,
-/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtOpenFile` functions on
+/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtCreateFile` functions on
 /// Windows. Note that, this [may change in the future][changes].
 ///
 /// [changes]: io#platform-specific-behavior
@@ -2263,9 +2263,9 @@ fn create_dir_all(&self, path: &Path) -> io::Result<()> {
         match path.parent() {
             Some(p) => self.create_dir_all(p)?,
             None => {
-                return Err(io::Error::new_const(
+                return Err(io::const_io_error!(
                     io::ErrorKind::Uncategorized,
-                    &"failed to create whole tree",
+                    "failed to create whole tree",
                 ));
             }
         }
@@ -2288,7 +2288,7 @@ fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder {
 /// This function will traverse symbolic links to query information about the
 /// destination file. In case of broken symbolic links this will return `Ok(false)`.
 ///
-/// As opposed to the `exists()` method, this one doesn't silently ignore errors
+/// As opposed to the [`Path::exists`] method, this one doesn't silently ignore errors
 /// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission
 /// denied on some of the parent directories.)
 ///
@@ -2301,6 +2301,8 @@ fn as_inner_mut(&mut self) -> &mut fs_imp::DirBuilder {
 /// assert!(!fs::try_exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt"));
 /// assert!(fs::try_exists("/root/secret_file.txt").is_err());
 /// ```
+///
+/// [`Path::exists`]: crate::path::Path::exists
 // FIXME: stabilization should modify documentation of `exists()` to recommend this method
 // instead.
 #[unstable(feature = "path_try_exists", issue = "83186")]
index b56dc65f0b2f30f7e711b21c018ffd9992f92f4a..e7eee4436249b5073e76038d84c1f7be60ba27b9 100644 (file)
@@ -357,9 +357,9 @@ fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
             let mut bytes = Vec::new();
             self.read_to_end(&mut bytes)?;
             let string = crate::str::from_utf8(&bytes).map_err(|_| {
-                io::Error::new_const(
+                io::const_io_error!(
                     io::ErrorKind::InvalidData,
-                    &"stream did not contain valid UTF-8",
+                    "stream did not contain valid UTF-8",
                 )
             })?;
             *buf += string;
index c7423e4d92a896c359743285a3e76f2d47ab3ed6..2d3a0f37b4c2a56cf1bf56784e0252a1823cb9bf 100644 (file)
@@ -1,7 +1,7 @@
 use crate::error;
 use crate::fmt;
 use crate::io::{
-    self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
+    self, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE,
 };
 use crate::mem;
 use crate::ptr;
@@ -168,9 +168,9 @@ fn drop(&mut self) {
 
             match r {
                 Ok(0) => {
-                    return Err(Error::new_const(
+                    return Err(io::const_io_error!(
                         ErrorKind::WriteZero,
-                        &"failed to write the buffered data",
+                        "failed to write the buffered data",
                     ));
                 }
                 Ok(n) => guard.consume(n),
index 416cc906e65a56d0162dd13a639cb010675f8235..fc19704becee2e53d01c5d28ff742412a126a39a 100644 (file)
@@ -4,7 +4,7 @@
 use crate::io::prelude::*;
 
 use crate::cmp;
-use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};
 
 use core::convert::TryInto;
 
@@ -297,9 +297,9 @@ fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
                 self.pos = n;
                 Ok(self.pos)
             }
-            None => Err(Error::new_const(
+            None => Err(io::const_io_error!(
                 ErrorKind::InvalidInput,
-                &"invalid seek to a negative or overflowing position",
+                "invalid seek to a negative or overflowing position",
             )),
         }
     }
@@ -400,9 +400,9 @@ fn slice_write_vectored(
 // Resizing write implementation
 fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
     let pos: usize = (*pos_mut).try_into().map_err(|_| {
-        Error::new_const(
+        io::const_io_error!(
             ErrorKind::InvalidInput,
-            &"cursor position exceeds maximum possible vector length",
+            "cursor position exceeds maximum possible vector length",
         )
     })?;
     // Make sure the internal buffer is as least as big as where we
index 074d693b83155dcfddf0808d7751b17b0ac3c31d..1aa6d657889129c0fedae5aa4ce0c7472c8a9843 100644 (file)
@@ -1,6 +1,16 @@
 #[cfg(test)]
 mod tests;
 
+#[cfg(target_pointer_width = "64")]
+mod repr_bitpacked;
+#[cfg(target_pointer_width = "64")]
+use repr_bitpacked::Repr;
+
+#[cfg(not(target_pointer_width = "64"))]
+mod repr_unpacked;
+#[cfg(not(target_pointer_width = "64"))]
+use repr_unpacked::Repr;
+
 use crate::convert::From;
 use crate::error;
 use crate::fmt;
@@ -66,15 +76,58 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-enum Repr {
+// Only derive debug in tests, to make sure it
+// doesn't accidentally get printed.
+#[cfg_attr(test, derive(Debug))]
+enum ErrorData<C> {
     Os(i32),
     Simple(ErrorKind),
-    // &str is a fat pointer, but &&str is a thin pointer.
-    SimpleMessage(ErrorKind, &'static &'static str),
-    Custom(Box<Custom>),
+    SimpleMessage(&'static SimpleMessage),
+    Custom(C),
 }
 
+// `#[repr(align(4))]` is probably redundant, it should have that value or
+// higher already. We include it just because repr_bitpacked.rs's encoding
+// requires an alignment >= 4 (note that `#[repr(align)]` will not reduce the
+// alignment required by the struct, only increase it).
+//
+// If we add more variants to ErrorData, this can be increased to 8, but it
+// should probably be behind `#[cfg_attr(target_pointer_width = "64", ...)]` or
+// whatever cfg we're using to enable the `repr_bitpacked` code, since only the
+// that version needs the alignment, and 8 is higher than the alignment we'll
+// have on 32 bit platforms.
+//
+// (For the sake of being explicit: the alignment requirement here only matters
+// if `error/repr_bitpacked.rs` is in use — for the unpacked repr it doesn't
+// matter at all)
+#[repr(align(4))]
 #[derive(Debug)]
+pub(crate) struct SimpleMessage {
+    kind: ErrorKind,
+    message: &'static str,
+}
+
+impl SimpleMessage {
+    pub(crate) const fn new(kind: ErrorKind, message: &'static str) -> Self {
+        Self { kind, message }
+    }
+}
+
+/// Create and return an `io::Error` for a given `ErrorKind` and constant
+/// message. This doesn't allocate.
+pub(crate) macro const_io_error($kind:expr, $message:expr $(,)?) {
+    $crate::io::error::Error::from_static_message({
+        const MESSAGE_DATA: $crate::io::error::SimpleMessage =
+            $crate::io::error::SimpleMessage::new($kind, $message);
+        &MESSAGE_DATA
+    })
+}
+
+// As with `SimpleMessage`: `#[repr(align(4))]` here is just because
+// repr_bitpacked's encoding requires it. In practice it almost certainly be
+// already be this high or higher.
+#[derive(Debug)]
+#[repr(align(4))]
 struct Custom {
     kind: ErrorKind,
     error: Box<dyn error::Error + Send + Sync>,
@@ -243,12 +296,11 @@ pub enum ErrorKind {
     /// The filesystem does not support making so many hardlinks to the same file.
     #[unstable(feature = "io_error_more", issue = "86442")]
     TooManyLinks,
-    /// Filename too long.
+    /// A filename was invalid.
     ///
-    /// The limit might be from the underlying filesystem or API, or an administratively imposed
-    /// resource limit.
+    /// This error can also cause if it exceeded the filename length limit.
     #[unstable(feature = "io_error_more", issue = "86442")]
-    FilenameTooLong,
+    InvalidFilename,
     /// Program argument list too long.
     ///
     /// When trying to run an external program, a system or process limit on the size of the
@@ -329,12 +381,12 @@ pub(crate) fn as_str(&self) -> &'static str {
             DirectoryNotEmpty => "directory not empty",
             ExecutableFileBusy => "executable file busy",
             FileTooLarge => "file too large",
-            FilenameTooLong => "filename too long",
             FilesystemLoop => "filesystem loop or indirection limit (e.g. symlink loop)",
             FilesystemQuotaExceeded => "filesystem quota exceeded",
             HostUnreachable => "host unreachable",
             Interrupted => "operation interrupted",
             InvalidData => "invalid data",
+            InvalidFilename => "invalid filename",
             InvalidInput => "invalid input parameter",
             IsADirectory => "is a directory",
             NetworkDown => "network down",
@@ -396,7 +448,7 @@ impl From<ErrorKind> for Error {
     /// ```
     #[inline]
     fn from(kind: ErrorKind) -> Error {
-        Error { repr: Repr::Simple(kind) }
+        Error { repr: Repr::new_simple(kind) }
     }
 }
 
@@ -461,20 +513,22 @@ pub fn other<E>(error: E) -> Error
     }
 
     fn _new(kind: ErrorKind, error: Box<dyn error::Error + Send + Sync>) -> Error {
-        Error { repr: Repr::Custom(Box::new(Custom { kind, error })) }
+        Error { repr: Repr::new_custom(Box::new(Custom { kind, error })) }
     }
 
-    /// Creates a new I/O error from a known kind of error as well as a
-    /// constant message.
+    /// Creates a new I/O error from a known kind of error as well as a constant
+    /// message.
     ///
     /// This function does not allocate.
     ///
-    /// This function should maybe change to
-    /// `new_const<const MSG: &'static str>(kind: ErrorKind)`
-    /// in the future, when const generics allow that.
+    /// You should not use this directly, and instead use the `const_io_error!`
+    /// macro: `io::const_io_error!(ErrorKind::Something, "some_message")`.
+    ///
+    /// This function should maybe change to `from_static_message<const MSG: &'static
+    /// str>(kind: ErrorKind)` in the future, when const generics allow that.
     #[inline]
-    pub(crate) const fn new_const(kind: ErrorKind, message: &'static &'static str) -> Error {
-        Self { repr: Repr::SimpleMessage(kind, message) }
+    pub(crate) const fn from_static_message(msg: &'static SimpleMessage) -> Error {
+        Self { repr: Repr::new_simple_message(msg) }
     }
 
     /// Returns an error representing the last OS error which occurred.
@@ -532,7 +586,7 @@ pub fn last_os_error() -> Error {
     #[must_use]
     #[inline]
     pub fn from_raw_os_error(code: i32) -> Error {
-        Error { repr: Repr::Os(code) }
+        Error { repr: Repr::new_os(code) }
     }
 
     /// Returns the OS error that this error represents (if any).
@@ -568,11 +622,11 @@ pub fn from_raw_os_error(code: i32) -> Error {
     #[must_use]
     #[inline]
     pub fn raw_os_error(&self) -> Option<i32> {
-        match self.repr {
-            Repr::Os(i) => Some(i),
-            Repr::Custom(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
+        match self.repr.data() {
+            ErrorData::Os(i) => Some(i),
+            ErrorData::Custom(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
         }
     }
 
@@ -607,11 +661,11 @@ pub fn raw_os_error(&self) -> Option<i32> {
     #[must_use]
     #[inline]
     pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
-        match self.repr {
-            Repr::Os(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::Custom(ref c) => Some(&*c.error),
+        match self.repr.data() {
+            ErrorData::Os(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::Custom(c) => Some(&*c.error),
         }
     }
 
@@ -681,11 +735,11 @@ pub fn get_ref(&self) -> Option<&(dyn error::Error + Send + Sync + 'static)> {
     #[must_use]
     #[inline]
     pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'static)> {
-        match self.repr {
-            Repr::Os(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::Custom(ref mut c) => Some(&mut *c.error),
+        match self.repr.data_mut() {
+            ErrorData::Os(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::Custom(c) => Some(&mut *c.error),
         }
     }
 
@@ -720,11 +774,11 @@ pub fn get_mut(&mut self) -> Option<&mut (dyn error::Error + Send + Sync + 'stat
     #[must_use = "`self` will be dropped if the result is not used"]
     #[inline]
     pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
-        match self.repr {
-            Repr::Os(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::Custom(c) => Some(c.error),
+        match self.repr.into_data() {
+            ErrorData::Os(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::Custom(c) => Some(c.error),
         }
     }
 
@@ -750,29 +804,31 @@ pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
     #[must_use]
     #[inline]
     pub fn kind(&self) -> ErrorKind {
-        match self.repr {
-            Repr::Os(code) => sys::decode_error_kind(code),
-            Repr::Custom(ref c) => c.kind,
-            Repr::Simple(kind) => kind,
-            Repr::SimpleMessage(kind, _) => kind,
+        match self.repr.data() {
+            ErrorData::Os(code) => sys::decode_error_kind(code),
+            ErrorData::Custom(c) => c.kind,
+            ErrorData::Simple(kind) => kind,
+            ErrorData::SimpleMessage(m) => m.kind,
         }
     }
 }
 
 impl fmt::Debug for Repr {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match *self {
-            Repr::Os(code) => fmt
+        match self.data() {
+            ErrorData::Os(code) => fmt
                 .debug_struct("Os")
                 .field("code", &code)
                 .field("kind", &sys::decode_error_kind(code))
                 .field("message", &sys::os::error_string(code))
                 .finish(),
-            Repr::Custom(ref c) => fmt::Debug::fmt(&c, fmt),
-            Repr::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
-            Repr::SimpleMessage(kind, &message) => {
-                fmt.debug_struct("Error").field("kind", &kind).field("message", &message).finish()
-            }
+            ErrorData::Custom(c) => fmt::Debug::fmt(&c, fmt),
+            ErrorData::Simple(kind) => fmt.debug_tuple("Kind").field(&kind).finish(),
+            ErrorData::SimpleMessage(msg) => fmt
+                .debug_struct("Error")
+                .field("kind", &msg.kind)
+                .field("message", &msg.message)
+                .finish(),
         }
     }
 }
@@ -780,14 +836,14 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for Error {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.repr {
-            Repr::Os(code) => {
+        match self.repr.data() {
+            ErrorData::Os(code) => {
                 let detail = sys::os::error_string(code);
                 write!(fmt, "{} (os error {})", detail, code)
             }
-            Repr::Custom(ref c) => c.error.fmt(fmt),
-            Repr::Simple(kind) => write!(fmt, "{}", kind.as_str()),
-            Repr::SimpleMessage(_, &msg) => msg.fmt(fmt),
+            ErrorData::Custom(ref c) => c.error.fmt(fmt),
+            ErrorData::Simple(kind) => write!(fmt, "{}", kind.as_str()),
+            ErrorData::SimpleMessage(msg) => msg.message.fmt(fmt),
         }
     }
 }
@@ -796,29 +852,29 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl error::Error for Error {
     #[allow(deprecated, deprecated_in_future)]
     fn description(&self) -> &str {
-        match self.repr {
-            Repr::Os(..) | Repr::Simple(..) => self.kind().as_str(),
-            Repr::SimpleMessage(_, &msg) => msg,
-            Repr::Custom(ref c) => c.error.description(),
+        match self.repr.data() {
+            ErrorData::Os(..) | ErrorData::Simple(..) => self.kind().as_str(),
+            ErrorData::SimpleMessage(msg) => msg.message,
+            ErrorData::Custom(c) => c.error.description(),
         }
     }
 
     #[allow(deprecated)]
     fn cause(&self) -> Option<&dyn error::Error> {
-        match self.repr {
-            Repr::Os(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::Custom(ref c) => c.error.cause(),
+        match self.repr.data() {
+            ErrorData::Os(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::Custom(c) => c.error.cause(),
         }
     }
 
     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
-        match self.repr {
-            Repr::Os(..) => None,
-            Repr::Simple(..) => None,
-            Repr::SimpleMessage(..) => None,
-            Repr::Custom(ref c) => c.error.source(),
+        match self.repr.data() {
+            ErrorData::Os(..) => None,
+            ErrorData::Simple(..) => None,
+            ErrorData::SimpleMessage(..) => None,
+            ErrorData::Custom(c) => c.error.source(),
         }
     }
 }
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
new file mode 100644 (file)
index 0000000..4301e94
--- /dev/null
@@ -0,0 +1,391 @@
+//! This is a densely packed error representation which is used on targets with
+//! 64-bit pointers.
+//!
+//! (Note that `bitpacked` vs `unpacked` here has no relationship to
+//! `#[repr(packed)]`, it just refers to attempting to use any available bits in
+//! a more clever manner than `rustc`'s default layout algorithm would).
+//!
+//! Conceptually, it stores the same data as the "unpacked" equivalent we use on
+//! other targets. Specifically, you can imagine it as an optimized version of
+//! the following enum (which is roughly equivalent to what's stored by
+//! `repr_unpacked::Repr`, e.g. `super::ErrorData<Box<Custom>>`):
+//!
+//! ```ignore (exposition-only)
+//! enum ErrorData {
+//!    Os(i32),
+//!    Simple(ErrorKind),
+//!    SimpleMessage(&'static SimpleMessage),
+//!    Custom(Box<Custom>),
+//! }
+//! ```
+//!
+//! However, it packs this data into a 64bit non-zero value.
+//!
+//! This optimization not only allows `io::Error` to occupy a single pointer,
+//! but improves `io::Result` as well, especially for situations like
+//! `io::Result<()>` (which is now 64 bits) or `io::Result<u64>` (which is now
+//! 128 bits), which are quite common.
+//!
+//! # Layout
+//! Tagged values are 64 bits, with the 2 least significant bits used for the
+//! tag. This means there are there are 4 "variants":
+//!
+//! - **Tag 0b00**: The first variant is equivalent to
+//!   `ErrorData::SimpleMessage`, and holds a `&'static SimpleMessage` directly.
+//!
+//!   `SimpleMessage` has an alignment >= 4 (which is requested with
+//!   `#[repr(align)]` and checked statically at the bottom of this file), which
+//!   means every `&'static SimpleMessage` should have the both tag bits as 0,
+//!   meaning its tagged and untagged representation are equivalent.
+//!
+//!   This means we can skip tagging it, which is necessary as this variant can
+//!   be constructed from a `const fn`, which probably cannot tag pointers (or
+//!   at least it would be difficult).
+//!
+//! - **Tag 0b01**: The other pointer variant holds the data for
+//!   `ErrorData::Custom` and the remaining 62 bits are used to store a
+//!   `Box<Custom>`. `Custom` also has alignment >= 4, so the bottom two bits
+//!   are free to use for the tag.
+//!
+//!   The only important thing to note is that `ptr::wrapping_add` and
+//!   `ptr::wrapping_sub` are used to tag the pointer, rather than bitwise
+//!   operations. This should preserve the pointer's provenance, which would
+//!   otherwise be lost.
+//!
+//! - **Tag 0b10**: Holds the data for `ErrorData::Os(i32)`. We store the `i32`
+//!   in the pointer's most significant 32 bits, and don't use the bits `2..32`
+//!   for anything. Using the top 32 bits is just to let us easily recover the
+//!   `i32` code with the correct sign.
+//!
+//! - **Tag 0b11**: Holds the data for `ErrorData::Simple(ErrorKind)`. This
+//!   stores the `ErrorKind` in the top 32 bits as well, although it doesn't
+//!   occupy nearly that many. Most of the bits are unused here, but it's not
+//!   like we need them for anything else yet.
+//!
+//! # Use of `NonNull<()>`
+//!
+//! Everything is stored in a `NonNull<()>`, which is odd, but actually serves a
+//! purpose.
+//!
+//! Conceptually you might think of this more like:
+//!
+//! ```ignore (exposition-only)
+//! union Repr {
+//!     // holds integer (Simple/Os) variants, and
+//!     // provides access to the tag bits.
+//!     bits: NonZeroU64,
+//!     // Tag is 0, so this is stored untagged.
+//!     msg: &'static SimpleMessage,
+//!     // Tagged (offset) `Box<Custom>` pointer.
+//!     tagged_custom: NonNull<()>,
+//! }
+//! ```
+//!
+//! But there are a few problems with this:
+//!
+//! 1. Union access is equivalent to a transmute, so this representation would
+//!    require we transmute between integers and pointers in at least one
+//!    direction, which may be UB (and even if not, it is likely harder for a
+//!    compiler to reason about than explicit ptr->int operations).
+//!
+//! 2. Even if all fields of a union have a niche, the union itself doesn't,
+//!    although this may change in the future. This would make things like
+//!    `io::Result<()>` and `io::Result<usize>` larger, which defeats part of
+//!    the motivation of this bitpacking.
+//!
+//! Storing everything in a `NonZeroUsize` (or some other integer) would be a
+//! bit more traditional for pointer tagging, but it would lose provenance
+//! information, couldn't be constructed from a `const fn`, and would probably
+//! run into other issues as well.
+//!
+//! The `NonNull<()>` seems like the only alternative, even if it's fairly odd
+//! to use a pointer type to store something that may hold an integer, some of
+//! the time.
+
+use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
+use alloc::boxed::Box;
+use core::mem::{align_of, size_of};
+use core::ptr::NonNull;
+
+// The 2 least-significant bits are used as tag.
+const TAG_MASK: usize = 0b11;
+const TAG_SIMPLE_MESSAGE: usize = 0b00;
+const TAG_CUSTOM: usize = 0b01;
+const TAG_OS: usize = 0b10;
+const TAG_SIMPLE: usize = 0b11;
+
+#[repr(transparent)]
+pub(super) struct Repr(NonNull<()>);
+
+// All the types `Repr` stores internally are Send + Sync, and so is it.
+unsafe impl Send for Repr {}
+unsafe impl Sync for Repr {}
+
+impl Repr {
+    pub(super) fn new_custom(b: Box<Custom>) -> Self {
+        let p = Box::into_raw(b).cast::<u8>();
+        // Should only be possible if an allocator handed out a pointer with
+        // wrong alignment.
+        debug_assert_eq!((p as usize & TAG_MASK), 0);
+        // Note: We know `TAG_CUSTOM <= size_of::<Custom>()` (static_assert at
+        // end of file), and both the start and end of the expression must be
+        // valid without address space wraparound due to `Box`'s semantics.
+        //
+        // This means it would be correct to implement this using `ptr::add`
+        // (rather than `ptr::wrapping_add`), but it's unclear this would give
+        // any benefit, so we just use `wrapping_add` instead.
+        let tagged = p.wrapping_add(TAG_CUSTOM).cast::<()>();
+        // Safety: `TAG_CUSTOM + p` is the same as `TAG_CUSTOM | p`,
+        // because `p`'s alignment means it isn't allowed to have any of the
+        // `TAG_BITS` set (you can verify that addition and bitwise-or are the
+        // same when the operands have no bits in common using a truth table).
+        //
+        // Then, `TAG_CUSTOM | p` is not zero, as that would require
+        // `TAG_CUSTOM` and `p` both be zero, and neither is (as `p` came from a
+        // box, and `TAG_CUSTOM` just... isn't zero -- it's `0b01`). Therefore,
+        // `TAG_CUSTOM + p` isn't zero and so `tagged` can't be, and the
+        // `new_unchecked` is safe.
+        let res = Self(unsafe { NonNull::new_unchecked(tagged) });
+        // quickly smoke-check we encoded the right thing (This generally will
+        // only run in libstd's tests, unless the user uses -Zbuild-std)
+        debug_assert!(matches!(res.data(), ErrorData::Custom(_)), "repr(custom) encoding failed");
+        res
+    }
+
+    #[inline]
+    pub(super) fn new_os(code: i32) -> Self {
+        let utagged = ((code as usize) << 32) | TAG_OS;
+        // Safety: `TAG_OS` is not zero, so the result of the `|` is not 0.
+        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) });
+        // quickly smoke-check we encoded the right thing (This generally will
+        // only run in libstd'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,
+        );
+        res
+    }
+
+    #[inline]
+    pub(super) fn new_simple(kind: ErrorKind) -> Self {
+        let utagged = ((kind as usize) << 32) | TAG_SIMPLE;
+        // Safety: `TAG_SIMPLE` is not zero, so the result of the `|` is not 0.
+        let res = Self(unsafe { NonNull::new_unchecked(utagged as *mut ()) });
+        // quickly smoke-check we encoded the right thing (This generally will
+        // only run in libstd's tests, unless the user uses -Zbuild-std)
+        debug_assert!(
+            matches!(res.data(), ErrorData::Simple(k) if k == kind),
+            "repr(simple) encoding failed {:?}",
+            kind,
+        );
+        res
+    }
+
+    #[inline]
+    pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
+        // Safety: References are never null.
+        Self(unsafe { NonNull::new_unchecked(m as *const _ as *mut ()) })
+    }
+
+    #[inline]
+    pub(super) fn data(&self) -> ErrorData<&Custom> {
+        // Safety: We're a Repr, decode_repr is fine.
+        unsafe { decode_repr(self.0, |c| &*c) }
+    }
+
+    #[inline]
+    pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
+        // Safety: We're a Repr, decode_repr is fine.
+        unsafe { decode_repr(self.0, |c| &mut *c) }
+    }
+
+    #[inline]
+    pub(super) fn into_data(self) -> ErrorData<Box<Custom>> {
+        let this = core::mem::ManuallyDrop::new(self);
+        // Safety: We're a Repr, decode_repr is fine. The `Box::from_raw` is
+        // safe because we prevent double-drop using `ManuallyDrop`.
+        unsafe { decode_repr(this.0, |p| Box::from_raw(p)) }
+    }
+}
+
+impl Drop for Repr {
+    #[inline]
+    fn drop(&mut self) {
+        // Safety: We're a Repr, decode_repr is fine. The `Box::from_raw` is
+        // safe because we're being dropped.
+        unsafe {
+            let _ = decode_repr(self.0, |p| Box::<Custom>::from_raw(p));
+        }
+    }
+}
+
+// Shared helper to decode a `Repr`'s internal pointer into an ErrorData.
+//
+// Safety: `ptr`'s bits should be encoded as described in the document at the
+// top (it should `some_repr.0`)
+#[inline]
+unsafe fn decode_repr<C, F>(ptr: NonNull<()>, make_custom: F) -> ErrorData<C>
+where
+    F: FnOnce(*mut Custom) -> C,
+{
+    let bits = ptr.as_ptr() as usize;
+    match bits & TAG_MASK {
+        TAG_OS => {
+            let code = ((bits as i64) >> 32) as i32;
+            ErrorData::Os(code)
+        }
+        TAG_SIMPLE => {
+            let kind_bits = (bits >> 32) as u32;
+            let kind = kind_from_prim(kind_bits).unwrap_or_else(|| {
+                debug_assert!(false, "Invalid io::error::Repr bits: `Repr({:#018x})`", bits);
+                // This means the `ptr` passed in was not valid, which violates
+                // the unsafe contract of `decode_repr`.
+                //
+                // Using this rather than unwrap meaningfully improves the code
+                // for callers which only care about one variant (usually
+                // `Custom`)
+                core::hint::unreachable_unchecked();
+            });
+            ErrorData::Simple(kind)
+        }
+        TAG_SIMPLE_MESSAGE => ErrorData::SimpleMessage(&*ptr.cast::<SimpleMessage>().as_ptr()),
+        TAG_CUSTOM => {
+            // It would be correct for us to use `ptr::sub` here (see the
+            // comment above the `wrapping_add` call in `new_custom` for why),
+            // but it isn't clear that it makes a difference, so we don't.
+            let custom = ptr.as_ptr().cast::<u8>().wrapping_sub(TAG_CUSTOM).cast::<Custom>();
+            ErrorData::Custom(make_custom(custom))
+        }
+        _ => {
+            // Can't happen, and compiler can tell
+            unreachable!();
+        }
+    }
+}
+
+// This compiles to the same code as the check+transmute, but doesn't require
+// unsafe, or to hard-code max ErrorKind or its size in a way the compiler
+// couldn't verify.
+#[inline]
+fn kind_from_prim(ek: u32) -> Option<ErrorKind> {
+    macro_rules! from_prim {
+        ($prim:expr => $Enum:ident { $($Variant:ident),* $(,)? }) => {{
+            // Force a compile error if the list gets out of date.
+            const _: fn(e: $Enum) = |e: $Enum| match e {
+                $($Enum::$Variant => ()),*
+            };
+            match $prim {
+                $(v if v == ($Enum::$Variant as _) => Some($Enum::$Variant),)*
+                _ => None,
+            }
+        }}
+    }
+    from_prim!(ek => ErrorKind {
+        NotFound,
+        PermissionDenied,
+        ConnectionRefused,
+        ConnectionReset,
+        HostUnreachable,
+        NetworkUnreachable,
+        ConnectionAborted,
+        NotConnected,
+        AddrInUse,
+        AddrNotAvailable,
+        NetworkDown,
+        BrokenPipe,
+        AlreadyExists,
+        WouldBlock,
+        NotADirectory,
+        IsADirectory,
+        DirectoryNotEmpty,
+        ReadOnlyFilesystem,
+        FilesystemLoop,
+        StaleNetworkFileHandle,
+        InvalidInput,
+        InvalidData,
+        TimedOut,
+        WriteZero,
+        StorageFull,
+        NotSeekable,
+        FilesystemQuotaExceeded,
+        FileTooLarge,
+        ResourceBusy,
+        ExecutableFileBusy,
+        Deadlock,
+        CrossesDevices,
+        TooManyLinks,
+        InvalidFilename,
+        ArgumentListTooLong,
+        Interrupted,
+        Other,
+        UnexpectedEof,
+        Unsupported,
+        OutOfMemory,
+        Uncategorized,
+    })
+}
+
+// Some static checking to alert us if a change breaks any of the assumptions
+// 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
+// just use `repr_unpacked.rs` there instead (unless the fix is easy).
+macro_rules! static_assert {
+    ($condition:expr) => {
+        const _: () = assert!($condition);
+    };
+    (@usize_eq: $lhs:expr, $rhs:expr) => {
+        const _: [(); $lhs] = [(); $rhs];
+    };
+}
+
+// The bitpacking we use requires pointers be exactly 64 bits.
+static_assert!(@usize_eq: size_of::<NonNull<()>>(), 8);
+
+// We also require pointers and usize be the same size.
+static_assert!(@usize_eq: size_of::<NonNull<()>>(), size_of::<usize>());
+
+// `Custom` and `SimpleMessage` need to be thin pointers.
+static_assert!(@usize_eq: size_of::<&'static SimpleMessage>(), 8);
+static_assert!(@usize_eq: size_of::<Box<Custom>>(), 8);
+
+static_assert!((TAG_MASK + 1).is_power_of_two());
+// And they must have sufficient alignment.
+static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1);
+static_assert!(align_of::<Custom>() >= TAG_MASK + 1);
+
+static_assert!(@usize_eq: (TAG_MASK & TAG_SIMPLE_MESSAGE), TAG_SIMPLE_MESSAGE);
+static_assert!(@usize_eq: (TAG_MASK & TAG_CUSTOM), TAG_CUSTOM);
+static_assert!(@usize_eq: (TAG_MASK & TAG_OS), TAG_OS);
+static_assert!(@usize_eq: (TAG_MASK & TAG_SIMPLE), TAG_SIMPLE);
+
+// This is obviously true (`TAG_CUSTOM` is `0b01`), but in `Repr::new_custom` we
+// offset a pointer by this value, and expect it to both be within the same
+// object, and to not wrap around the address space. See the comment in that
+// function for further details.
+//
+// Actually, at the moment we use `ptr::wrapping_add`, not `ptr::add`, so this
+// check isn't needed for that one, although the assertion that we don't
+// actually wrap around in that wrapping_add does simplify the safety reasoning
+// elsewhere considerably.
+static_assert!(size_of::<Custom>() >= TAG_CUSTOM);
+
+// These two store a payload which is allowed to be zero, so they must be
+// non-zero to preserve the `NonNull`'s range invariant.
+static_assert!(TAG_OS != 0);
+static_assert!(TAG_SIMPLE != 0);
+// We can't tag `SimpleMessage`s, the tag must be 0.
+static_assert!(@usize_eq: TAG_SIMPLE_MESSAGE, 0);
+
+// Check that the point of all of this still holds.
+//
+// We'd check against `io::Error`, but *technically* it's allowed to vary,
+// as it's not `#[repr(transparent)]`/`#[repr(C)]`. We could add that, but
+// the `#[repr()]` would show up in rustdoc, which might be seen as a stable
+// commitment.
+static_assert!(@usize_eq: size_of::<Repr>(), 8);
+static_assert!(@usize_eq: size_of::<Option<Repr>>(), 8);
+static_assert!(@usize_eq: size_of::<Result<(), Repr>>(), 8);
+static_assert!(@usize_eq: size_of::<Result<usize, Repr>>(), 16);
diff --git a/library/std/src/io/error/repr_unpacked.rs b/library/std/src/io/error/repr_unpacked.rs
new file mode 100644 (file)
index 0000000..3729c03
--- /dev/null
@@ -0,0 +1,50 @@
+//! This is a fairly simple unpacked error representation that's used on
+//! non-64bit targets, where the packed 64 bit representation wouldn't work, and
+//! would have no benefit.
+
+use super::{Custom, ErrorData, ErrorKind, SimpleMessage};
+use alloc::boxed::Box;
+
+type Inner = ErrorData<Box<Custom>>;
+
+pub(super) struct Repr(Inner);
+
+impl Repr {
+    pub(super) fn new_custom(b: Box<Custom>) -> Self {
+        Self(Inner::Custom(b))
+    }
+    #[inline]
+    pub(super) fn new_os(code: i32) -> Self {
+        Self(Inner::Os(code))
+    }
+    #[inline]
+    pub(super) fn new_simple(kind: ErrorKind) -> Self {
+        Self(Inner::Simple(kind))
+    }
+    #[inline]
+    pub(super) const fn new_simple_message(m: &'static SimpleMessage) -> Self {
+        Self(Inner::SimpleMessage(m))
+    }
+    #[inline]
+    pub(super) fn into_data(self) -> ErrorData<Box<Custom>> {
+        self.0
+    }
+    #[inline]
+    pub(super) fn data(&self) -> ErrorData<&Custom> {
+        match &self.0 {
+            Inner::Os(c) => ErrorData::Os(*c),
+            Inner::Simple(k) => ErrorData::Simple(*k),
+            Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
+            Inner::Custom(m) => ErrorData::Custom(&*m),
+        }
+    }
+    #[inline]
+    pub(super) fn data_mut(&mut self) -> ErrorData<&mut Custom> {
+        match &mut self.0 {
+            Inner::Os(c) => ErrorData::Os(*c),
+            Inner::Simple(k) => ErrorData::Simple(*k),
+            Inner::SimpleMessage(m) => ErrorData::SimpleMessage(*m),
+            Inner::Custom(m) => ErrorData::Custom(&mut *m),
+        }
+    }
+}
index 5098a46313de39c22385f5b08cde895f5fe6ecae..c2c51553b208c25253eff217e4891d2f9b2f5dce 100644 (file)
@@ -1,4 +1,5 @@
-use super::{Custom, Error, ErrorKind, Repr};
+use super::{const_io_error, Custom, Error, ErrorData, ErrorKind, Repr};
+use crate::assert_matches::assert_matches;
 use crate::error;
 use crate::fmt;
 use crate::mem::size_of;
@@ -16,9 +17,9 @@ fn test_debug_error() {
     let msg = error_string(code);
     let kind = decode_error_kind(code);
     let err = Error {
-        repr: Repr::Custom(box Custom {
+        repr: Repr::new_custom(box Custom {
             kind: ErrorKind::InvalidInput,
-            error: box Error { repr: super::Repr::Os(code) },
+            error: box Error { repr: super::Repr::new_os(code) },
         }),
     };
     let expected = format!(
@@ -60,10 +61,83 @@ impl error::Error for TestError {}
 
 #[test]
 fn test_const() {
-    const E: Error = Error::new_const(ErrorKind::NotFound, &"hello");
+    const E: Error = const_io_error!(ErrorKind::NotFound, "hello");
 
     assert_eq!(E.kind(), ErrorKind::NotFound);
     assert_eq!(E.to_string(), "hello");
     assert!(format!("{:?}", E).contains("\"hello\""));
     assert!(format!("{:?}", E).contains("NotFound"));
 }
+
+#[test]
+fn test_os_packing() {
+    for code in -20i32..20i32 {
+        let e = Error::from_raw_os_error(code);
+        assert_eq!(e.raw_os_error(), Some(code));
+        assert_matches!(
+            e.repr.data(),
+            ErrorData::Os(c) if c == code,
+        );
+    }
+}
+
+#[test]
+fn test_errorkind_packing() {
+    assert_eq!(Error::from(ErrorKind::NotFound).kind(), ErrorKind::NotFound);
+    assert_eq!(Error::from(ErrorKind::PermissionDenied).kind(), ErrorKind::PermissionDenied);
+    assert_eq!(Error::from(ErrorKind::Uncategorized).kind(), ErrorKind::Uncategorized);
+    // Check that the innards look like like what we want.
+    assert_matches!(
+        Error::from(ErrorKind::OutOfMemory).repr.data(),
+        ErrorData::Simple(ErrorKind::OutOfMemory),
+    );
+}
+
+#[test]
+fn test_simple_message_packing() {
+    use super::{ErrorKind::*, SimpleMessage};
+    macro_rules! check_simple_msg {
+        ($err:expr, $kind:ident, $msg:literal) => {{
+            let e = &$err;
+            // Check that the public api is right.
+            assert_eq!(e.kind(), $kind);
+            assert!(format!("{:?}", e).contains($msg));
+            // and we got what we expected
+            assert_matches!(
+                e.repr.data(),
+                ErrorData::SimpleMessage(SimpleMessage { kind: $kind, message: $msg })
+            );
+        }};
+    }
+
+    let not_static = const_io_error!(Uncategorized, "not a constant!");
+    check_simple_msg!(not_static, Uncategorized, "not a constant!");
+
+    const CONST: Error = const_io_error!(NotFound, "definitely a constant!");
+    check_simple_msg!(CONST, NotFound, "definitely a constant!");
+
+    static STATIC: Error = const_io_error!(BrokenPipe, "a constant, sort of!");
+    check_simple_msg!(STATIC, BrokenPipe, "a constant, sort of!");
+}
+
+#[derive(Debug, PartialEq)]
+struct Bojji(bool);
+impl error::Error for Bojji {}
+impl fmt::Display for Bojji {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "ah! {:?}", self)
+    }
+}
+
+#[test]
+fn test_custom_error_packing() {
+    use super::Custom;
+    let test = Error::new(ErrorKind::Uncategorized, Bojji(true));
+    assert_matches!(
+        test.repr.data(),
+        ErrorData::Custom(Custom {
+            kind: ErrorKind::Uncategorized,
+            error,
+        }) if error.downcast_ref::<Bojji>().as_deref() == Some(&Bojji(true)),
+    );
+}
index 23201f9fc5c94deeaee0516f0fdc99bb5ea03e81..64d2457bce1596b28c2d619e3ca40b2fb142f93b 100644 (file)
@@ -5,7 +5,7 @@
 use crate::cmp;
 use crate::fmt;
 use crate::io::{
-    self, BufRead, Error, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
+    self, BufRead, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf, Seek, SeekFrom, Write,
 };
 use crate::mem;
 
@@ -279,7 +279,10 @@ fn is_read_vectored(&self) -> bool {
     #[inline]
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
         if buf.len() > self.len() {
-            return Err(Error::new_const(ErrorKind::UnexpectedEof, &"failed to fill whole buffer"));
+            return Err(io::const_io_error!(
+                ErrorKind::UnexpectedEof,
+                "failed to fill whole buffer"
+            ));
         }
         let (a, b) = self.split_at(buf.len());
 
@@ -361,7 +364,7 @@ fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
         if self.write(data)? == data.len() {
             Ok(())
         } else {
-            Err(Error::new_const(ErrorKind::WriteZero, &"failed to write whole buffer"))
+            Err(io::const_io_error!(ErrorKind::WriteZero, "failed to write whole buffer"))
         }
     }
 
index 824938ce38e68b430e5f45cd8ca53b62c2e35f27..71a59fb58032115e17e61ff233003068ad7887da 100644 (file)
 
 #[unstable(feature = "read_buf", issue = "78485")]
 pub use self::readbuf::ReadBuf;
+pub(crate) use error::const_io_error;
 
 mod buffered;
 pub(crate) mod copy;
@@ -337,7 +338,10 @@ pub(crate) unsafe fn append_to_string<F>(buf: &mut String, f: F) -> Result<usize
     let ret = f(g.buf);
     if str::from_utf8(&g.buf[g.len..]).is_err() {
         ret.and_then(|_| {
-            Err(Error::new_const(ErrorKind::InvalidData, &"stream did not contain valid UTF-8"))
+            Err(error::const_io_error!(
+                ErrorKind::InvalidData,
+                "stream did not contain valid UTF-8"
+            ))
         })
     } else {
         g.len = g.buf.len();
@@ -454,7 +458,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
         }
     }
     if !buf.is_empty() {
-        Err(Error::new_const(ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+        Err(error::const_io_error!(ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
     } else {
         Ok(())
     }
@@ -1512,9 +1516,9 @@ fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
         while !buf.is_empty() {
             match self.write(buf) {
                 Ok(0) => {
-                    return Err(Error::new_const(
+                    return Err(error::const_io_error!(
                         ErrorKind::WriteZero,
-                        &"failed to write whole buffer",
+                        "failed to write whole buffer",
                     ));
                 }
                 Ok(n) => buf = &buf[n..],
@@ -1580,9 +1584,9 @@ fn write_all_vectored(&mut self, mut bufs: &mut [IoSlice<'_>]) -> Result<()> {
         while !bufs.is_empty() {
             match self.write_vectored(bufs) {
                 Ok(0) => {
-                    return Err(Error::new_const(
+                    return Err(error::const_io_error!(
                         ErrorKind::WriteZero,
-                        &"failed to write whole buffer",
+                        "failed to write whole buffer",
                     ));
                 }
                 Ok(n) => IoSlice::advance_slices(&mut bufs, n),
@@ -1657,7 +1661,7 @@ fn write_str(&mut self, s: &str) -> fmt::Result {
                 if output.error.is_err() {
                     output.error
                 } else {
-                    Err(Error::new_const(ErrorKind::Uncategorized, &"formatter error"))
+                    Err(error::const_io_error!(ErrorKind::Uncategorized, "formatter error"))
                 }
             }
         }
index ea49bfe3421d1beb6a83f64b211c947c67536887..eb62634856462aa874bc26ab64a9d3381df7a116 100644 (file)
@@ -185,12 +185,12 @@ fn take_eof() {
 
     impl Read for R {
         fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
-            Err(io::Error::new_const(io::ErrorKind::Other, &""))
+            Err(io::const_io_error!(io::ErrorKind::Other, ""))
         }
     }
     impl BufRead for R {
         fn fill_buf(&mut self) -> io::Result<&[u8]> {
-            Err(io::Error::new_const(io::ErrorKind::Other, &""))
+            Err(io::const_io_error!(io::ErrorKind::Other, ""))
         }
         fn consume(&mut self, _amt: usize) {}
     }
index f3bb2eeb8586ec4efe41aa492b26df06fd332b1c..8c38db9b62cdcecf9c896f248d10dbd2fb3645e2 100644 (file)
 // std is implemented with unstable features, many of which are internal
 // compiler details that will never be stable
 // NB: the following list is sorted to minimize merge conflicts.
+#![feature(absolute_path)]
 #![feature(alloc_error_handler)]
 #![feature(alloc_layout_extra)]
 #![feature(allocator_api)]
 #![feature(c_variadic)]
 #![feature(cfg_accessible)]
 #![feature(cfg_eval)]
-#![feature(cfg_target_has_atomic)]
+#![cfg_attr(bootstrap, feature(cfg_target_has_atomic))]
 #![feature(cfg_target_thread_local)]
 #![feature(char_error_internals)]
 #![feature(char_internals)]
@@ -546,13 +547,14 @@ pub mod arch {
     #[doc(no_inline)] // Note (#82861): required for correct documentation
     pub use core::arch::*;
 
+    #[stable(feature = "simd_aarch64", since = "1.60.0")]
+    pub use std_detect::is_aarch64_feature_detected;
     #[stable(feature = "simd_x86", since = "1.27.0")]
     pub use std_detect::is_x86_feature_detected;
     #[unstable(feature = "stdsimd", issue = "48556")]
     pub use std_detect::{
-        is_aarch64_feature_detected, is_arm_feature_detected, is_mips64_feature_detected,
-        is_mips_feature_detected, is_powerpc64_feature_detected, is_powerpc_feature_detected,
-        is_riscv_feature_detected,
+        is_arm_feature_detected, is_mips64_feature_detected, is_mips_feature_detected,
+        is_powerpc64_feature_detected, is_powerpc_feature_detected, is_riscv_feature_detected,
     };
 }
 
index 2669f4dbf3068b9603f58098dc7c07efedffccb1..f676e0a04f000883760a3a141da84018273b1b18 100644 (file)
@@ -17,7 +17,7 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use crate::io::{self, Error, ErrorKind};
+use crate::io::{self, ErrorKind};
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
@@ -90,6 +90,6 @@ fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
         }
     }
     Err(last_err.unwrap_or_else(|| {
-        Error::new_const(ErrorKind::InvalidInput, &"could not resolve to any addresses")
+        io::const_io_error!(ErrorKind::InvalidInput, "could not resolve to any addresses")
     }))
 }
index 6354752e64e766c97517bce6f845a994ad1e1228..11a696e92c82565725411e01b018e8d1bf61c5fd 100644 (file)
@@ -2,7 +2,7 @@
 mod tests;
 
 use crate::fmt;
-use crate::io::{self, Error, ErrorKind};
+use crate::io::{self, ErrorKind};
 use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs};
 use crate::sys_common::net as net_imp;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -175,7 +175,9 @@ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
     pub fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> io::Result<usize> {
         match addr.to_socket_addrs()?.next() {
             Some(addr) => self.0.send_to(buf, &addr),
-            None => Err(Error::new_const(ErrorKind::InvalidInput, &"no addresses to send data to")),
+            None => {
+                Err(io::const_io_error!(ErrorKind::InvalidInput, "no addresses to send data to"))
+            }
         }
     }
 
index 0b6588db92c83102b30fb5fe7a17de01c82a4acf..71c660e7186751be890291f7d5d1127a1d23b850 100644 (file)
@@ -93,9 +93,9 @@ pub fn try_clone(&self) -> crate::io::Result<Self> {
 
     #[cfg(target_os = "wasi")]
     pub fn try_clone(&self) -> crate::io::Result<Self> {
-        Err(crate::io::Error::new_const(
+        Err(crate::io::const_io_error!(
             crate::io::ErrorKind::Unsupported,
-            &"operation not supported on WASI yet",
+            "operation not supported on WASI yet",
         ))
     }
 }
@@ -200,6 +200,22 @@ pub trait AsFd {
     fn as_fd(&self) -> BorrowedFd<'_>;
 }
 
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsFd> AsFd for &T {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        T::as_fd(self)
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsFd> AsFd for &mut T {
+    #[inline]
+    fn as_fd(&self) -> BorrowedFd<'_> {
+        T::as_fd(self)
+    }
+}
+
 #[unstable(feature = "io_safety", issue = "87074")]
 impl AsFd for BorrowedFd<'_> {
     #[inline]
index 0284a428b5d749b8695257d575592cd4f8298672..75d65e6d5fc036bff10c39ab60f6cd2636b62a79 100644 (file)
@@ -114,7 +114,7 @@ fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
             }
         }
         if !buf.is_empty() {
-            Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+            Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer",))
         } else {
             Ok(())
         }
@@ -196,9 +196,9 @@ fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
         while !buf.is_empty() {
             match self.write_at(buf, offset) {
                 Ok(0) => {
-                    return Err(io::Error::new_const(
+                    return Err(io::const_io_error!(
                         io::ErrorKind::WriteZero,
-                        &"failed to write whole buffer",
+                        "failed to write whole buffer",
                     ));
                 }
                 Ok(n) => {
@@ -966,7 +966,7 @@ pub fn chown<P: AsRef<Path>>(dir: P, uid: Option<u32>, gid: Option<u32>) -> io::
 ///
 /// fn main() -> std::io::Result<()> {
 ///     let f = std::fs::File::open("/file")?;
-///     fs::fchown(f, Some(0), Some(0))?;
+///     fs::fchown(&f, Some(0), Some(0))?;
 ///     Ok(())
 /// }
 /// ```
index 9dbd4548bc92d02240e64b20a7bf24b9380ce0e5..034fa301ba1ead4c434edf14adb9a41886f22844 100644 (file)
@@ -30,16 +30,16 @@ pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::s
     let bytes = path.as_os_str().as_bytes();
 
     if bytes.contains(&0) {
-        return Err(io::Error::new_const(
+        return Err(io::const_io_error!(
             io::ErrorKind::InvalidInput,
-            &"paths must not contain interior null bytes",
+            "paths must not contain interior null bytes",
         ));
     }
 
     if bytes.len() >= addr.sun_path.len() {
-        return Err(io::Error::new_const(
+        return Err(io::const_io_error!(
             io::ErrorKind::InvalidInput,
-            &"path must be shorter than SUN_LEN",
+            "path must be shorter than SUN_LEN",
         ));
     }
     // SAFETY: `bytes` and `addr.sun_path` are not overlapping and
@@ -121,9 +121,9 @@ pub(super) fn from_parts(
             // linux returns zero bytes of address
             len = sun_path_offset(&addr) as libc::socklen_t; // i.e., zero-length address
         } else if addr.sun_family != libc::AF_UNIX as libc::sa_family_t {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 io::ErrorKind::InvalidInput,
-                &"file descriptor did not correspond to a Unix socket",
+                "file descriptor did not correspond to a Unix socket",
             ));
         }
 
@@ -323,9 +323,9 @@ pub fn from_abstract_namespace(namespace: &[u8]) -> io::Result<SocketAddr> {
             addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
 
             if namespace.len() + 1 > addr.sun_path.len() {
-                return Err(io::Error::new_const(
+                return Err(io::const_io_error!(
                     io::ErrorKind::InvalidInput,
-                    &"namespace must be shorter than SUN_LEN",
+                    "namespace must be shorter than SUN_LEN",
                 ));
             }
 
index 37126069f942b218d0f1f8bef319d8bab01f7b34..160c8f1eca251a01fe4286ed7a23269226c8e6ae 100644 (file)
@@ -87,7 +87,7 @@ fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
             }
         }
         if !buf.is_empty() {
-            Err(io::Error::new_const(io::ErrorKind::UnexpectedEof, &"failed to fill whole buffer"))
+            Err(io::const_io_error!(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer"))
         } else {
             Ok(())
         }
@@ -153,9 +153,9 @@ fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
         while !buf.is_empty() {
             match self.write_at(buf, offset) {
                 Ok(0) => {
-                    return Err(io::Error::new_const(
+                    return Err(io::const_io_error!(
                         io::ErrorKind::WriteZero,
-                        &"failed to write whole buffer",
+                        "failed to write whole buffer",
                     ));
                 }
                 Ok(n) => {
@@ -258,9 +258,9 @@ fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> {
             a if a == wasi::ADVICE_DONTNEED.raw() => wasi::ADVICE_DONTNEED,
             a if a == wasi::ADVICE_NOREUSE.raw() => wasi::ADVICE_NOREUSE,
             _ => {
-                return Err(io::Error::new_const(
+                return Err(io::const_io_error!(
                     io::ErrorKind::InvalidInput,
-                    &"invalid parameter 'advice'",
+                    "invalid parameter 'advice'",
                 ));
             }
         };
@@ -554,5 +554,5 @@ pub fn symlink_path<P: AsRef<Path>, U: AsRef<Path>>(old_path: P, new_path: U) ->
 
 fn osstr2str(f: &OsStr) -> io::Result<&str> {
     f.to_str()
-        .ok_or_else(|| io::Error::new_const(io::ErrorKind::Uncategorized, &"input must be utf-8"))
+        .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8"))
 }
index e37ce633a129a77f231af65ffff172824d358adc..8df6c54a4144e9f42c1314bbb07d12d333d16cdf 100644 (file)
@@ -316,6 +316,22 @@ pub trait AsHandle {
     fn as_handle(&self) -> BorrowedHandle<'_>;
 }
 
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsHandle> AsHandle for &T {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        T::as_handle(self)
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsHandle> AsHandle for &mut T {
+    #[inline]
+    fn as_handle(&self) -> BorrowedHandle<'_> {
+        T::as_handle(self)
+    }
+}
+
 impl AsHandle for BorrowedHandle<'_> {
     #[inline]
     fn as_handle(&self) -> BorrowedHandle<'_> {
index 26b569bcdd3625f3f1c0ecaa75eb6c183113e6d3..2f13eb77a1b948519bb93e51ceda78e8cfe20f5c 100644 (file)
@@ -135,7 +135,7 @@ pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
 
     #[cfg(target_vendor = "uwp")]
     pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
-        Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP"))
+        Err(io::const_io_error!(io::ErrorKind::Unsupported, "Unavailable on UWP"))
     }
 }
 
@@ -210,6 +210,22 @@ pub trait AsSocket {
     fn as_socket(&self) -> BorrowedSocket<'_>;
 }
 
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsSocket> AsSocket for &T {
+    #[inline]
+    fn as_socket(&self) -> BorrowedSocket<'_> {
+        T::as_socket(self)
+    }
+}
+
+#[unstable(feature = "io_safety", issue = "87074")]
+impl<T: AsSocket> AsSocket for &mut T {
+    #[inline]
+    fn as_socket(&self) -> BorrowedSocket<'_> {
+        T::as_socket(self)
+    }
+}
+
 impl AsSocket for BorrowedSocket<'_> {
     #[inline]
     fn as_socket(&self) -> BorrowedSocket<'_> {
index e540f86016038fcdcc010cae006709cd1064eefe..e544608f83c299c9ad3f2262b2ffc50062a48298 100644 (file)
@@ -85,7 +85,7 @@
 use crate::sync::Arc;
 
 use crate::ffi::{OsStr, OsString};
-
+use crate::sys;
 use crate::sys::path::{is_sep_byte, is_verbatim_sep, parse_prefix, MAIN_SEP_STR};
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -268,6 +268,12 @@ pub fn is_separator(c: char) -> bool {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub const MAIN_SEPARATOR: char = crate::sys::path::MAIN_SEP;
 
+/// The primary separator of path components for the current platform.
+///
+/// For example, `/` on Unix and `\` on Windows.
+#[unstable(feature = "main_separator_str", issue = "94071")]
+pub const MAIN_SEPARATOR_STR: &str = crate::sys::path::MAIN_SEP_STR;
+
 ////////////////////////////////////////////////////////////////////////////////
 // Misc helpers
 ////////////////////////////////////////////////////////////////////////////////
@@ -1600,7 +1606,7 @@ fn from(cow: Cow<'_, Path>) -> Box<Path> {
 
 #[stable(feature = "path_buf_from_box", since = "1.18.0")]
 impl From<Box<Path>> for PathBuf {
-    /// Converts a `Box<Path>` into a `PathBuf`
+    /// Converts a <code>[Box]&lt;[Path]&gt;</code> into a [`PathBuf`].
     ///
     /// This conversion does not allocate or copy memory.
     #[inline]
@@ -1611,7 +1617,7 @@ fn from(boxed: Box<Path>) -> PathBuf {
 
 #[stable(feature = "box_from_path_buf", since = "1.20.0")]
 impl From<PathBuf> for Box<Path> {
-    /// Converts a `PathBuf` into a `Box<Path>`
+    /// Converts a [`PathBuf`] into a <code>[Box]&lt;[Path]&gt;</code>.
     ///
     /// This conversion currently should not allocate memory,
     /// but this behavior is not guaranteed on all platforms or in all future versions.
@@ -1631,7 +1637,7 @@ fn clone(&self) -> Self {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + AsRef<OsStr>> From<&T> for PathBuf {
-    /// Converts a borrowed `OsStr` to a `PathBuf`.
+    /// Converts a borrowed [`OsStr`] to a [`PathBuf`].
     ///
     /// Allocates a [`PathBuf`] and copies the data into it.
     #[inline]
@@ -2730,7 +2736,7 @@ pub fn exists(&self) -> bool {
     /// This function will traverse symbolic links to query information about the
     /// destination file. In case of broken symbolic links this will return `Ok(false)`.
     ///
-    /// As opposed to the `exists()` method, this one doesn't silently ignore errors
+    /// As opposed to the [`exists()`] method, this one doesn't silently ignore errors
     /// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission
     /// denied on some of the parent directories.)
     ///
@@ -2743,6 +2749,8 @@ pub fn exists(&self) -> bool {
     /// assert!(!Path::new("does_not_exist.txt").try_exists().expect("Can't check existence of file does_not_exist.txt"));
     /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err());
     /// ```
+    ///
+    /// [`exists()`]: Self::exists
     // FIXME: stabilization should modify documentation of `exists()` to recommend this method
     // instead.
     #[unstable(feature = "path_try_exists", issue = "83186")]
@@ -2920,12 +2928,12 @@ fn eq(&self, other: &Path) -> bool {
 impl Hash for Path {
     fn hash<H: Hasher>(&self, h: &mut H) {
         let bytes = self.as_u8_slice();
-        let prefix_len = match parse_prefix(&self.inner) {
+        let (prefix_len, verbatim) = match parse_prefix(&self.inner) {
             Some(prefix) => {
                 prefix.hash(h);
-                prefix.len()
+                (prefix.len(), prefix.is_verbatim())
             }
-            None => 0,
+            None => (0, false),
         };
         let bytes = &bytes[prefix_len..];
 
@@ -2933,7 +2941,8 @@ fn hash<H: Hasher>(&self, h: &mut H) {
         let mut bytes_hashed = 0;
 
         for i in 0..bytes.len() {
-            if is_sep_byte(bytes[i]) {
+            let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) };
+            if is_sep {
                 if i > component_start {
                     let to_hash = &bytes[component_start..i];
                     h.write(to_hash);
@@ -2941,11 +2950,18 @@ fn hash<H: Hasher>(&self, h: &mut H) {
                 }
 
                 // skip over separator and optionally a following CurDir item
-                // since components() would normalize these away
-                component_start = i + match bytes[i..] {
-                    [_, b'.', b'/', ..] | [_, b'.'] => 2,
-                    _ => 1,
-                };
+                // since components() would normalize these away.
+                component_start = i + 1;
+
+                let tail = &bytes[component_start..];
+
+                if !verbatim {
+                    component_start += match tail {
+                        [b'.'] => 1,
+                        [b'.', sep @ _, ..] if is_sep_byte(*sep) => 1,
+                        _ => 0,
+                    };
+                }
             }
         }
 
@@ -3162,3 +3178,79 @@ fn description(&self) -> &str {
         "prefix not found"
     }
 }
+
+/// Makes the path absolute without accessing the filesystem.
+///
+/// If the path is relative, the current directory is used as the base directory.
+/// All intermediate components will be resolved according to platforms-specific
+/// rules but unlike [`canonicalize`][crate::fs::canonicalize] this does not
+/// resolve symlinks and may succeed even if the path does not exist.
+///
+/// If the `path` is empty or getting the
+/// [current directory][crate::env::current_dir] fails then an error will be
+/// returned.
+///
+/// # Examples
+///
+/// ## Posix paths
+///
+/// ```
+/// #![feature(absolute_path)]
+/// # #[cfg(unix)]
+/// fn main() -> std::io::Result<()> {
+///   use std::path::{self, Path};
+///
+///   // Relative to absolute
+///   let absolute = path::absolute("foo/./bar")?;
+///   assert!(absolute.ends_with("foo/bar"));
+///
+///   // Absolute to absolute
+///   let absolute = path::absolute("/foo//test/.././bar.rs")?;
+///   assert_eq!(absolute, Path::new("/foo/test/../bar.rs"));
+///   Ok(())
+/// }
+/// # #[cfg(not(unix))]
+/// # fn main() {}
+/// ```
+///
+/// The path is resolved using [POSIX semantics][posix-semantics] except that
+/// it stops short of resolving symlinks. This means it will keep `..`
+/// components and trailing slashes.
+///
+/// ## Windows paths
+///
+/// ```
+/// #![feature(absolute_path)]
+/// # #[cfg(windows)]
+/// fn main() -> std::io::Result<()> {
+///   use std::path::{self, Path};
+///
+///   // Relative to absolute
+///   let absolute = path::absolute("foo/./bar")?;
+///   assert!(absolute.ends_with(r"foo\bar"));
+///
+///   // Absolute to absolute
+///   let absolute = path::absolute(r"C:\foo//test\..\./bar.rs")?;
+///
+///   assert_eq!(absolute, Path::new(r"C:\foo\bar.rs"));
+///   Ok(())
+/// }
+/// # #[cfg(not(windows))]
+/// # fn main() {}
+/// ```
+///
+/// For verbatim paths this will simply return the path as given. For other
+/// paths this is currently equivalent to calling [`GetFullPathNameW`][windows-path]
+/// This may change in the future.
+///
+/// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+/// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
+#[unstable(feature = "absolute_path", issue = "92750")]
+pub fn absolute<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
+    let path = path.as_ref();
+    if path.as_os_str().is_empty() {
+        Err(io::const_io_error!(io::ErrorKind::InvalidInput, "cannot make an empty path absolute",))
+    } else {
+        sys::path::absolute(path)
+    }
+}
index 2bf499e1ab823b656aefaab444a876fdcdd08b8a..8e51433094a6962d40eb3b7b442119d19ba343bf 100644 (file)
@@ -1498,6 +1498,20 @@ macro_rules! tc (
     relative_from: Some("")
     );
 
+    tc!("foo/.", "foo",
+    eq: true,
+    starts_with: true,
+    ends_with: true,
+    relative_from: Some("")
+    );
+
+    tc!("foo/./bar", "foo/bar",
+    eq: true,
+    starts_with: true,
+    ends_with: true,
+    relative_from: Some("")
+    );
+
     tc!("foo/bar", "foo",
     eq: false,
     starts_with: true,
@@ -1541,6 +1555,27 @@ macro_rules! tc (
         ends_with: true,
         relative_from: Some("")
         );
+
+        tc!(r"C:\foo\.\bar.txt", r"C:\foo\bar.txt",
+        eq: true,
+        starts_with: true,
+        ends_with: true,
+        relative_from: Some("")
+        );
+
+        tc!(r"C:\foo\.", r"C:\foo",
+        eq: true,
+        starts_with: true,
+        ends_with: true,
+        relative_from: Some("")
+        );
+
+        tc!(r"\\?\C:\foo\.\bar.txt", r"\\?\C:\foo\bar.txt",
+        eq: false,
+        starts_with: false,
+        ends_with: false,
+        relative_from: None
+        );
     }
 }
 
@@ -1665,6 +1700,64 @@ macro_rules! ord(
     ord!(Equal, "foo/bar", "foo/bar//");
 }
 
+#[test]
+#[cfg(unix)]
+fn test_unix_absolute() {
+    use crate::path::absolute;
+
+    assert!(absolute("").is_err());
+
+    let relative = "a/b";
+    let mut expected = crate::env::current_dir().unwrap();
+    expected.push(relative);
+    assert_eq!(absolute(relative).unwrap(), expected);
+
+    // Test how components are collected.
+    assert_eq!(absolute("/a/b/c").unwrap(), Path::new("/a/b/c"));
+    assert_eq!(absolute("/a//b/c").unwrap(), Path::new("/a/b/c"));
+    assert_eq!(absolute("//a/b/c").unwrap(), Path::new("//a/b/c"));
+    assert_eq!(absolute("///a/b/c").unwrap(), Path::new("/a/b/c"));
+    assert_eq!(absolute("/a/b/c/").unwrap(), Path::new("/a/b/c/"));
+    assert_eq!(absolute("/a/./b/../c/.././..").unwrap(), Path::new("/a/b/../c/../.."));
+}
+
+#[test]
+#[cfg(windows)]
+fn test_windows_absolute() {
+    use crate::path::absolute;
+    // An empty path is an error.
+    assert!(absolute("").is_err());
+
+    let relative = r"a\b";
+    let mut expected = crate::env::current_dir().unwrap();
+    expected.push(relative);
+    assert_eq!(absolute(relative).unwrap(), expected);
+
+    macro_rules! unchanged(
+        ($path:expr) => {
+            assert_eq!(absolute($path).unwrap(), Path::new($path));
+        }
+    );
+
+    unchanged!(r"C:\path\to\file");
+    unchanged!(r"C:\path\to\file\");
+    unchanged!(r"\\server\share\to\file");
+    unchanged!(r"\\server.\share.\to\file");
+    unchanged!(r"\\.\PIPE\name");
+    unchanged!(r"\\.\C:\path\to\COM1");
+    unchanged!(r"\\?\C:\path\to\file");
+    unchanged!(r"\\?\UNC\server\share\to\file");
+    unchanged!(r"\\?\PIPE\name");
+    // Verbatim paths are always unchanged, no matter what.
+    unchanged!(r"\\?\path.\to/file..");
+
+    assert_eq!(absolute(r"C:\path..\to.\file.").unwrap(), Path::new(r"C:\path..\to\file"));
+    assert_eq!(absolute(r"C:\path\to\COM1").unwrap(), Path::new(r"\\.\COM1"));
+    assert_eq!(absolute(r"C:\path\to\COM1.txt").unwrap(), Path::new(r"\\.\COM1"));
+    assert_eq!(absolute(r"C:\path\to\COM1  .txt").unwrap(), Path::new(r"\\.\COM1"));
+    assert_eq!(absolute(r"C:\path\to\cOnOuT$").unwrap(), Path::new(r"\\.\cOnOuT$"));
+}
+
 #[bench]
 fn bench_path_cmp_fast_path_buf_sort(b: &mut test::Bencher) {
     let prefix = "my/home";
index 7d7e08a714938007f77cfaeee752b6cb5e2038c6..e3fff155e47224b6728fa5c355d4de98ca9acbe1 100644 (file)
@@ -1277,7 +1277,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 #[stable(feature = "stdio_from", since = "1.20.0")]
 impl From<ChildStdin> for Stdio {
-    /// Converts a `ChildStdin` into a `Stdio`
+    /// Converts a [`ChildStdin`] into a [`Stdio`].
     ///
     /// # Examples
     ///
@@ -1306,7 +1306,7 @@ fn from(child: ChildStdin) -> Stdio {
 
 #[stable(feature = "stdio_from", since = "1.20.0")]
 impl From<ChildStdout> for Stdio {
-    /// Converts a `ChildStdout` into a `Stdio`
+    /// Converts a [`ChildStdout`] into a [`Stdio`].
     ///
     /// # Examples
     ///
@@ -1335,7 +1335,7 @@ fn from(child: ChildStdout) -> Stdio {
 
 #[stable(feature = "stdio_from", since = "1.20.0")]
 impl From<ChildStderr> for Stdio {
-    /// Converts a `ChildStderr` into a `Stdio`
+    /// Converts a [`ChildStderr`] into a [`Stdio`].
     ///
     /// # Examples
     ///
@@ -1366,7 +1366,7 @@ fn from(child: ChildStderr) -> Stdio {
 
 #[stable(feature = "stdio_from", since = "1.20.0")]
 impl From<fs::File> for Stdio {
-    /// Converts a `File` into a `Stdio`
+    /// Converts a [`File`](fs::File) into a [`Stdio`].
     ///
     /// # Examples
     ///
@@ -1691,6 +1691,14 @@ pub fn to_i32(self) -> i32 {
     }
 }
 
+#[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
+impl From<u8> for ExitCode {
+    /// Construct an exit code from an arbitrary u8 value.
+    fn from(code: u8) -> Self {
+        ExitCode(imp::ExitCode::from(code))
+    }
+}
+
 impl Child {
     /// Forces the child process to exit. If the child has already exited, an [`InvalidInput`]
     /// error is returned.
index 974c44eb8dd5eda540d3eca293b17d4f2142f0a9..fa9a7fb19e4631fcab9c7d99de57a78857256559 100644 (file)
@@ -226,7 +226,7 @@ fn get_access_mode(&self) -> io::Result<i32> {
             (false, _, true) => Ok(O_WRONLY | O_APPEND),
             (true, _, true) => Ok(O_RDWR | O_APPEND),
             (false, false, false) => {
-                Err(io::Error::new_const(ErrorKind::InvalidInput, &"invalid access mode"))
+                Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid access mode"))
             }
         }
     }
@@ -236,17 +236,17 @@ fn get_creation_mode(&self) -> io::Result<i32> {
             (true, false) => {}
             (false, false) => {
                 if self.truncate || self.create || self.create_new {
-                    return Err(io::Error::new_const(
+                    return Err(io::const_io_error!(
                         ErrorKind::InvalidInput,
-                        &"invalid creation mode",
+                        "invalid creation mode",
                     ));
                 }
             }
             (_, true) => {
                 if self.truncate && !self.create_new {
-                    return Err(io::Error::new_const(
+                    return Err(io::const_io_error!(
                         ErrorKind::InvalidInput,
-                        &"invalid creation mode",
+                        "invalid creation mode",
                     ));
                 }
             }
index 185b68c0a7803598107d1ac5acfdc5cd548d56d3..b798c97448b8f541aa68c19076e7736d0b6217ce 100644 (file)
@@ -58,9 +58,9 @@ pub fn unsupported<T>() -> crate::io::Result<T> {
 }
 
 pub fn unsupported_err() -> crate::io::Error {
-    crate::io::Error::new_const(
+    crate::io::const_io_error!(
         crate::io::ErrorKind::Unsupported,
-        &"operation not supported on HermitCore yet",
+        "operation not supported on HermitCore yet",
     )
 }
 
index 1a6b3bc63e6def5868ab4015a8f021a3560cf40c..f65fd8e53bdc999a26998c5093124b0b2bba7ee6 100644 (file)
@@ -14,9 +14,9 @@
 /// if not, starts it.
 pub fn init() -> io::Result<()> {
     if abi::network_init() < 0 {
-        return Err(io::Error::new_const(
+        return Err(io::const_io_error!(
             ErrorKind::Uncategorized,
-            &"Unable to initialize network interface",
+            "Unable to initialize network interface",
         ));
     }
 
@@ -50,9 +50,9 @@ pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
 
         match abi::tcpstream::connect(addr.ip().to_string().as_bytes(), addr.port(), None) {
             Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
-            _ => Err(io::Error::new_const(
+            _ => Err(io::const_io_error!(
                 ErrorKind::Uncategorized,
-                &"Unable to initiate a connection on a socket",
+                "Unable to initiate a connection on a socket",
             )),
         }
     }
@@ -64,9 +64,9 @@ pub fn connect_timeout(saddr: &SocketAddr, duration: Duration) -> io::Result<Tcp
             Some(duration.as_millis() as u64),
         ) {
             Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
-            _ => Err(io::Error::new_const(
+            _ => Err(io::const_io_error!(
                 ErrorKind::Uncategorized,
-                &"Unable to initiate a connection on a socket",
+                "Unable to initiate a connection on a socket",
             )),
         }
     }
@@ -74,7 +74,7 @@ pub fn connect_timeout(saddr: &SocketAddr, duration: Duration) -> io::Result<Tcp
     pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
         abi::tcpstream::set_read_timeout(*self.0.as_inner(), duration.map(|d| d.as_millis() as u64))
             .map_err(|_| {
-                io::Error::new_const(ErrorKind::Uncategorized, &"Unable to set timeout value")
+                io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value")
             })
     }
 
@@ -83,12 +83,12 @@ pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
             *self.0.as_inner(),
             duration.map(|d| d.as_millis() as u64),
         )
-        .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"Unable to set timeout value"))
+        .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value"))
     }
 
     pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
         let duration = abi::tcpstream::get_read_timeout(*self.0.as_inner()).map_err(|_| {
-            io::Error::new_const(ErrorKind::Uncategorized, &"Unable to determine timeout value")
+            io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
         })?;
 
         Ok(duration.map(|d| Duration::from_millis(d)))
@@ -96,7 +96,7 @@ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
 
     pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
         let duration = abi::tcpstream::get_write_timeout(*self.0.as_inner()).map_err(|_| {
-            io::Error::new_const(ErrorKind::Uncategorized, &"Unable to determine timeout value")
+            io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
         })?;
 
         Ok(duration.map(|d| Duration::from_millis(d)))
@@ -104,7 +104,7 @@ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
 
     pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
         abi::tcpstream::peek(*self.0.as_inner(), buf)
-            .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"peek failed"))
+            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peek failed"))
     }
 
     pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
@@ -116,7 +116,7 @@ pub fn read_vectored(&self, ioslice: &mut [IoSliceMut<'_>]) -> io::Result<usize>
 
         for i in ioslice.iter_mut() {
             let ret = abi::tcpstream::read(*self.0.as_inner(), &mut i[0..]).map_err(|_| {
-                io::Error::new_const(ErrorKind::Uncategorized, &"Unable to read on socket")
+                io::const_io_error!(ErrorKind::Uncategorized, "Unable to read on socket")
             })?;
 
             if ret != 0 {
@@ -141,7 +141,7 @@ pub fn write_vectored(&self, ioslice: &[IoSlice<'_>]) -> io::Result<usize> {
 
         for i in ioslice.iter() {
             size += abi::tcpstream::write(*self.0.as_inner(), i).map_err(|_| {
-                io::Error::new_const(ErrorKind::Uncategorized, &"Unable to write on socket")
+                io::const_io_error!(ErrorKind::Uncategorized, "Unable to write on socket")
             })?;
         }
 
@@ -155,13 +155,13 @@ pub fn is_write_vectored(&self) -> bool {
 
     pub fn peer_addr(&self) -> io::Result<SocketAddr> {
         let (ipaddr, port) = abi::tcpstream::peer_addr(*self.0.as_inner())
-            .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"peer_addr failed"))?;
+            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"))?;
 
         let saddr = match ipaddr {
             Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
             Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
             _ => {
-                return Err(io::Error::new_const(ErrorKind::Uncategorized, &"peer_addr failed"));
+                return Err(io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"));
             }
         };
 
@@ -173,9 +173,8 @@ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
     }
 
     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
-        abi::tcpstream::shutdown(*self.0.as_inner(), how as i32).map_err(|_| {
-            io::Error::new_const(ErrorKind::Uncategorized, &"unable to shutdown socket")
-        })
+        abi::tcpstream::shutdown(*self.0.as_inner(), how as i32)
+            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to shutdown socket"))
     }
 
     pub fn duplicate(&self) -> io::Result<TcpStream> {
@@ -192,22 +191,22 @@ pub fn linger(&self) -> io::Result<Option<Duration>> {
 
     pub fn set_nodelay(&self, mode: bool) -> io::Result<()> {
         abi::tcpstream::set_nodelay(*self.0.as_inner(), mode)
-            .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"set_nodelay failed"))
+            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "set_nodelay failed"))
     }
 
     pub fn nodelay(&self) -> io::Result<bool> {
         abi::tcpstream::nodelay(*self.0.as_inner())
-            .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"nodelay failed"))
+            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "nodelay failed"))
     }
 
     pub fn set_ttl(&self, tll: u32) -> io::Result<()> {
         abi::tcpstream::set_tll(*self.0.as_inner(), tll)
-            .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"unable to set TTL"))
+            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to set TTL"))
     }
 
     pub fn ttl(&self) -> io::Result<u32> {
         abi::tcpstream::get_tll(*self.0.as_inner())
-            .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"unable to get TTL"))
+            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to get TTL"))
     }
 
     pub fn take_error(&self) -> io::Result<Option<io::Error>> {
@@ -216,7 +215,7 @@ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
 
     pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> {
         abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode).map_err(|_| {
-            io::Error::new_const(ErrorKind::Uncategorized, &"unable to set blocking mode")
+            io::const_io_error!(ErrorKind::Uncategorized, "unable to set blocking mode")
         })
     }
 }
@@ -243,12 +242,12 @@ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
 
     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
         let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port())
-            .map_err(|_| io::Error::new_const(ErrorKind::Uncategorized, &"accept failed"))?;
+            .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "accept failed"))?;
         let saddr = match ipaddr {
             Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
             Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
             _ => {
-                return Err(io::Error::new_const(ErrorKind::Uncategorized, &"accept failed"));
+                return Err(io::const_io_error!(ErrorKind::Uncategorized, "accept failed"));
             }
         };
 
index 33b8390431f6d5327fa57abf590016ca4713dc78..514de1df6f9c33bc32f0ca34b0bd29ee6523c6c8 100644 (file)
@@ -40,7 +40,7 @@ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
-            Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stdout is not able to print"))
+            Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
         } else {
             Ok(len as usize)
         }
@@ -52,7 +52,7 @@ fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
-            Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stdout is not able to print"))
+            Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
         } else {
             Ok(len as usize)
         }
@@ -81,7 +81,7 @@ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
-            Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stderr is not able to print"))
+            Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
         } else {
             Ok(len as usize)
         }
@@ -93,7 +93,7 @@ fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
-            Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Stderr is not able to print"))
+            Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
         } else {
             Ok(len as usize)
         }
index 81b21fbbb1656c8758ffd982f153a85e7de04486..e53a1fea6a0dca8b4a6e49aeecd49839e6efbe25 100644 (file)
@@ -39,7 +39,7 @@ pub unsafe fn new_with_coreid(
             // The thread failed to start and as a result p was not consumed. Therefore, it is
             // safe to reconstruct the box so that it gets deallocated.
             drop(Box::from_raw(p));
-            Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"Unable to create thread!"))
+            Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Unable to create thread!"))
         } else {
             Ok(Thread { tid: tid })
         };
index c02de17c1fc3ab61688c528bfd55595bffc675cb..27173de6307290c6c2edc0d6d45551f0e152b74b 100644 (file)
@@ -115,14 +115,6 @@ pub fn now() -> Instant {
         Instant { t: time }
     }
 
-    pub const fn zero() -> Instant {
-        Instant { t: Timespec::zero() }
-    }
-
-    pub fn actually_monotonic() -> bool {
-        true
-    }
-
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
         self.t.sub_timespec(&other.t).ok()
     }
index dac4b8abfc47ff1b7e58673887d98d834b0b8ed6..2992a6a542901ccd5fc0d521368344bdbc8fd437 100644 (file)
@@ -15,10 +15,12 @@ unsafe impl Sync for Condvar {}
 pub type MovableCondvar = Condvar;
 
 impl Condvar {
+    #[inline]
     pub const fn new() -> Condvar {
         Condvar { waiters: SpinMutex::new(waiter_queue::WaiterQueue::new()) }
     }
 
+    #[inline]
     pub unsafe fn init(&mut self) {}
 
     pub unsafe fn notify_one(&self) {
@@ -190,7 +192,7 @@ pub unsafe fn insert(&mut self, mut waiter_ptr: NonNull<Waiter>) {
                     let insert_after = {
                         let mut cursor = head.last;
                         loop {
-                            if waiter.priority <= cursor.as_ref().priority {
+                            if waiter.priority >= cursor.as_ref().priority {
                                 // `cursor` and all previous waiters have the same or higher
                                 // priority than `current_task_priority`. Insert the new
                                 // waiter right after `cursor`.
@@ -206,7 +208,7 @@ pub unsafe fn insert(&mut self, mut waiter_ptr: NonNull<Waiter>) {
 
                     if let Some(mut insert_after) = insert_after {
                         // Insert `waiter` after `insert_after`
-                        let insert_before = insert_after.as_ref().prev;
+                        let insert_before = insert_after.as_ref().next;
 
                         waiter.prev = Some(insert_after);
                         insert_after.as_mut().next = Some(waiter_ptr);
@@ -214,6 +216,8 @@ pub unsafe fn insert(&mut self, mut waiter_ptr: NonNull<Waiter>) {
                         waiter.next = insert_before;
                         if let Some(mut insert_before) = insert_before {
                             insert_before.as_mut().prev = Some(waiter_ptr);
+                        } else {
+                            head.last = waiter_ptr;
                         }
                     } else {
                         // Insert `waiter` to the front
@@ -240,11 +244,11 @@ pub unsafe fn remove(&mut self, mut waiter_ptr: NonNull<Waiter>) -> bool {
                     match (waiter.prev, waiter.next) {
                         (Some(mut prev), Some(mut next)) => {
                             prev.as_mut().next = Some(next);
-                            next.as_mut().next = Some(prev);
+                            next.as_mut().prev = Some(prev);
                         }
                         (None, Some(mut next)) => {
                             head.first = next;
-                            next.as_mut().next = None;
+                            next.as_mut().prev = None;
                         }
                         (Some(mut prev), None) => {
                             prev.as_mut().next = None;
@@ -271,6 +275,7 @@ pub unsafe fn is_queued(&self, waiter: NonNull<Waiter>) -> bool {
             unsafe { waiter.as_ref().task != 0 }
         }
 
+        #[inline]
         pub fn pop_front(&mut self) -> Option<abi::ID> {
             unsafe {
                 let head = self.head.as_mut()?;
index 6a992ad1d3c755fbf3d034af0d34d94794832275..25f13ee441aca60095c9e93ada5808aef5c33952 100644 (file)
@@ -14,15 +14,6 @@ pub fn now() -> Instant {
         }
     }
 
-    pub const fn zero() -> Instant {
-        Instant(0)
-    }
-
-    pub fn actually_monotonic() -> bool {
-        // There are ways to change the system time
-        false
-    }
-
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
         self.0.checked_sub(other.0).map(|ticks| {
             // `SYSTIM` is measured in microseconds
index a2a763c2b4e0f3f3c12e94525dcc3555fea9ad54..158c92e7a77d42ccf08c79e23ca576852885967d 100644 (file)
@@ -58,7 +58,7 @@ pub fn unsupported<T>() -> crate::io::Result<T> {
 }
 
 pub fn unsupported_err() -> crate::io::Error {
-    crate::io::Error::new_const(ErrorKind::Unsupported, &"operation not supported on SGX yet")
+    crate::io::const_io_error!(ErrorKind::Unsupported, "operation not supported on SGX yet")
 }
 
 /// This function is used to implement various functions that doesn't exist,
@@ -69,9 +69,9 @@ pub fn unsupported_err() -> crate::io::Error {
 pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> {
     static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false);
     if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) {
-        Err(crate::io::Error::new_const(
+        Err(crate::io::const_io_error!(
             ErrorKind::Uncategorized,
-            &"operation can't be trusted to have any effect on SGX",
+            "operation can't be trusted to have any effect on SGX",
         ))
     } else {
         Ok(v)
index 89c5af6124f201bfdb8225a5306b494a4080099b..d14990c6877af6384dfc4385d2bd2c4702523109 100644 (file)
@@ -97,9 +97,9 @@ pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
 
     pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream> {
         if dur == Duration::default() {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 io::ErrorKind::InvalidInput,
-                &"cannot set a 0 duration timeout",
+                "cannot set a 0 duration timeout",
             ));
         }
         Self::connect(Ok(addr)) // FIXME: ignoring timeout
@@ -108,9 +108,9 @@ pub fn connect_timeout(addr: &SocketAddr, dur: Duration) -> io::Result<TcpStream
     pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
         match dur {
             Some(dur) if dur == Duration::default() => {
-                return Err(io::Error::new_const(
+                return Err(io::const_io_error!(
                     io::ErrorKind::InvalidInput,
-                    &"cannot set a 0 duration timeout",
+                    "cannot set a 0 duration timeout",
                 ));
             }
             _ => sgx_ineffective(()),
@@ -120,9 +120,9 @@ pub fn set_read_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
     pub fn set_write_timeout(&self, dur: Option<Duration>) -> io::Result<()> {
         match dur {
             Some(dur) if dur == Duration::default() => {
-                return Err(io::Error::new_const(
+                return Err(io::const_io_error!(
                     io::ErrorKind::InvalidInput,
-                    &"cannot set a 0 duration timeout",
+                    "cannot set a 0 duration timeout",
                 ));
             }
             _ => sgx_ineffective(()),
index 840a7ae04262508abc1bd81fd78a7f8fd4231363..c805c15e70245115c81ed2693b22f06a0484ac5e 100644 (file)
@@ -1,5 +1,7 @@
 use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
+use crate::sys::unsupported;
 
 #[inline]
 pub fn is_sep_byte(b: u8) -> bool {
@@ -17,3 +19,7 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
 
 pub const MAIN_SEP_STR: &str = "/";
 pub const MAIN_SEP: char = '/';
+
+pub(crate) fn absolute(_path: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
index e2f6e6dba695d3f80c4dfd8b86c6596c0299b3ff..db4cf2804bf13b111f9eff5bbce46d721bc337f4 100644 (file)
@@ -25,14 +25,6 @@ pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
     pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
         Some(Instant(self.0.checked_sub(*other)?))
     }
-
-    pub fn actually_monotonic() -> bool {
-        false
-    }
-
-    pub const fn zero() -> Instant {
-        Instant(Duration::from_secs(0))
-    }
 }
 
 impl SystemTime {
index 8a0eeff0c4d75f3e56d1078fbf9dece5197ee409..a6ed10f7789d26ffdd1e90a55c24243d7106b47b 100644 (file)
@@ -461,7 +461,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 pub fn unlink(p: &Path) -> io::Result<()> {
     if stat(p)?.file_type().is_dir() {
-        Err(io::Error::new_const(io::ErrorKind::IsADirectory, &"is a directory"))
+        Err(io::const_io_error!(io::ErrorKind::IsADirectory, "is a directory"))
     } else {
         error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) })
             .map_err(|e| e.as_io_error())?;
@@ -491,7 +491,7 @@ pub fn rmdir(p: &Path) -> io::Result<()> {
             .map_err(|e| e.as_io_error())?;
         Ok(())
     } else {
-        Err(io::Error::new_const(io::ErrorKind::NotADirectory, &"not a directory"))
+        Err(io::const_io_error!(io::ErrorKind::NotADirectory, "not a directory"))
     }
 }
 
@@ -511,7 +511,7 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> {
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
     // This target doesn't support symlinks
     stat(p)?;
-    Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"not a symbolic link"))
+    Err(io::const_io_error!(io::ErrorKind::InvalidInput, "not a symbolic link"))
 }
 
 pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
index 211b8d7de31f5dd80e9664217720b2c3565b9a15..2082c9401535e8d1f4dd67a535f03eda626286bf 100644 (file)
@@ -57,9 +57,9 @@ pub fn unsupported<T>() -> crate::io::Result<T> {
 }
 
 pub fn unsupported_err() -> crate::io::Error {
-    crate::io::Error::new_const(
+    crate::io::const_io_error!(
         crate::io::ErrorKind::Unsupported,
-        &"operation not supported on this platform",
+        "operation not supported on this platform",
     )
 }
 
index c91ecce4d728b70acd91b977c8084643ba8910d1..a43407bd0f8652a767cef42a221a33c83d26fd13 100644 (file)
@@ -243,9 +243,9 @@ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Resul
         }
 
         if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 io::ErrorKind::InvalidInput,
-                &"cannot set a 0 duration timeout",
+                "cannot set a 0 duration timeout",
             ));
         }
 
@@ -271,7 +271,7 @@ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Resul
         };
 
         match n {
-            0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")),
+            0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")),
             _ => {
                 let can_write = writefds.num_fds != 0;
                 if !can_write {
@@ -364,9 +364,9 @@ pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()>
         let timeout = match dur {
             Some(dur) => {
                 if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
-                    return Err(io::Error::new_const(
+                    return Err(io::const_io_error!(
                         io::ErrorKind::InvalidInput,
-                        &"cannot set a 0 duration timeout",
+                        "cannot set a 0 duration timeout",
                     ));
                 }
 
index 82542d81e6709c18792cf52c457be681798685e6..22239e1fa8ebc1944be2e0ae43e8f13b92b90a34 100644 (file)
@@ -173,11 +173,7 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
 /// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this
 /// function just returns a generic error.
 fn cvt_env(t: c_int) -> io::Result<c_int> {
-    if t == -1 {
-        Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"failure"))
-    } else {
-        Ok(t)
-    }
+    if t == -1 { Err(io::const_io_error!(io::ErrorKind::Uncategorized, "failure")) } else { Ok(t) }
 }
 
 pub fn temp_dir() -> PathBuf {
index 4a14332d4999cfda4e64e92aa33b7626955349e7..7045c9be25b0809fb1a747a9d8879b2d7b7e692a 100644 (file)
@@ -1,5 +1,7 @@
 use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
+use crate::sys::unsupported;
 
 #[inline]
 pub fn is_sep_byte(b: u8) -> bool {
@@ -17,3 +19,7 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
 
 pub const MAIN_SEP_STR: &str = "\\";
 pub const MAIN_SEP: char = '\\';
+
+pub(crate) fn absolute(_path: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
index c67a736a9032c551e4ea8d411081eeed691ba604..ab988be24442a0ad774e5a250c283cc22d3ecb1b 100644 (file)
@@ -21,7 +21,7 @@ pub fn now() -> SystemTime {
                 tm_min: rtc.tm_min,
                 tm_hour: rtc.tm_hour,
                 tm_mday: rtc.tm_mday,
-                tm_mon: rtc.tm_mon,
+                tm_mon: rtc.tm_mon - 1,
                 tm_year: rtc.tm_year,
                 tm_wday: rtc.tm_wday,
                 tm_yday: 0,
index 878796065c8f17b906c6e3fb4f2db996e1440cd5..8bd0b9b14afedb4cb14c7b23eb1abee90ffecaf2 100644 (file)
@@ -387,17 +387,17 @@ pub fn created(&self) -> io::Result<SystemTime> {
                         tv_nsec: ext.stx_btime.tv_nsec as _,
                     }))
                 } else {
-                    Err(io::Error::new_const(
+                    Err(io::const_io_error!(
                         io::ErrorKind::Uncategorized,
-                        &"creation time is not available for the filesystem",
+                        "creation time is not available for the filesystem",
                     ))
                 };
             }
         }
 
-        Err(io::Error::new_const(
+        Err(io::const_io_error!(
             io::ErrorKind::Unsupported,
-            &"creation time is not available on this platform \
+            "creation time is not available on this platform \
                             currently",
         ))
     }
index ba63b41534c1a4f55deca27ad7c99d67ec85158d..d13e1ecbbfed4c8627a1f9ecf2ae91a5878c0a14 100644 (file)
@@ -1,8 +1,8 @@
 macro_rules! unimpl {
     () => {
-        return Err(io::Error::new_const(
+        return Err(io::const_io_error!(
             io::ErrorKind::Unsupported,
-            &"No networking available on L4Re.",
+            "No networking available on L4Re.",
         ));
     };
 }
index 2ba6c8d830ede552890c37898353615bf2a69dc8..605cc499b3c92670c7faf9afbbebb338c2ae2f32 100644 (file)
@@ -159,7 +159,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         libc::ENOSPC => StorageFull,
         libc::ENOSYS => Unsupported,
         libc::EMLINK => TooManyLinks,
-        libc::ENAMETOOLONG => FilenameTooLong,
+        libc::ENAMETOOLONG => InvalidFilename,
         libc::ENETDOWN => NetworkDown,
         libc::ENETUNREACH => NetworkUnreachable,
         libc::ENOTCONN => NotConnected,
@@ -322,9 +322,6 @@ pub fn unsupported<T>() -> io::Result<T> {
     }
 
     pub fn unsupported_err() -> io::Error {
-        io::Error::new_const(
-            io::ErrorKind::Unsupported,
-            &"operation not supported on this platform",
-        )
+        io::const_io_error!(io::ErrorKind::Unsupported, "operation not supported on this platform",)
     }
 }
index a82a0172126d4fa51066b4b5313712cb61ffe812..61c15ecd85de3ce0a80355126d86fa899671cdb3 100644 (file)
@@ -154,9 +154,9 @@ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Resul
         let mut pollfd = libc::pollfd { fd: self.as_raw_fd(), events: libc::POLLOUT, revents: 0 };
 
         if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 io::ErrorKind::InvalidInput,
-                &"cannot set a 0 duration timeout",
+                "cannot set a 0 duration timeout",
             ));
         }
 
@@ -165,7 +165,7 @@ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Resul
         loop {
             let elapsed = start.elapsed();
             if elapsed >= timeout {
-                return Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"));
+                return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
             }
 
             let timeout = timeout - elapsed;
@@ -192,9 +192,9 @@ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Resul
                     // for POLLHUP rather than read readiness
                     if pollfd.revents & libc::POLLHUP != 0 {
                         let e = self.take_error()?.unwrap_or_else(|| {
-                            io::Error::new_const(
+                            io::const_io_error!(
                                 io::ErrorKind::Uncategorized,
-                                &"no error set after POLLHUP",
+                                "no error set after POLLHUP",
                             )
                         });
                         return Err(e);
@@ -338,9 +338,9 @@ pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Resul
         let timeout = match dur {
             Some(dur) => {
                 if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
-                    return Err(io::Error::new_const(
+                    return Err(io::const_io_error!(
                         io::ErrorKind::InvalidInput,
-                        &"cannot set a 0 duration timeout",
+                        "cannot set a 0 duration timeout",
                     ));
                 }
 
index 7466c77356c7c40a35a5b1d23359e7ba9f7e799d..b268ef5c36400ba3c2aa97cc97f61792d2e83c4c 100644 (file)
@@ -294,9 +294,9 @@ fn sysctl() -> io::Result<PathBuf> {
                 0,
             ))?;
             if path_len <= 1 {
-                return Err(io::Error::new_const(
+                return Err(io::const_io_error!(
                     io::ErrorKind::Uncategorized,
-                    &"KERN_PROC_PATHNAME sysctl returned zero-length string",
+                    "KERN_PROC_PATHNAME sysctl returned zero-length string",
                 ));
             }
             let mut path: Vec<u8> = Vec::with_capacity(path_len);
@@ -317,9 +317,9 @@ fn procfs() -> io::Result<PathBuf> {
         if curproc_exe.is_file() {
             return crate::fs::read_link(curproc_exe);
         }
-        Err(io::Error::new_const(
+        Err(io::const_io_error!(
             io::ErrorKind::Uncategorized,
-            &"/proc/curproc/exe doesn't point to regular file.",
+            "/proc/curproc/exe doesn't point to regular file.",
         ))
     }
     sysctl().or_else(|_| procfs())
@@ -336,9 +336,9 @@ pub fn current_exe() -> io::Result<PathBuf> {
         cvt(libc::sysctl(mib, 4, argv.as_mut_ptr() as *mut _, &mut argv_len, ptr::null_mut(), 0))?;
         argv.set_len(argv_len as usize);
         if argv[0].is_null() {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 io::ErrorKind::Uncategorized,
-                &"no current exe available",
+                "no current exe available",
             ));
         }
         let argv0 = CStr::from_ptr(argv[0]).to_bytes();
@@ -353,9 +353,9 @@ pub fn current_exe() -> io::Result<PathBuf> {
 #[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
 pub fn current_exe() -> io::Result<PathBuf> {
     match crate::fs::read_link("/proc/self/exe") {
-        Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::Error::new_const(
+        Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!(
             io::ErrorKind::Uncategorized,
-            &"no /proc/self/exe available. Is /proc mounted?",
+            "no /proc/self/exe available. Is /proc mounted?",
         )),
         other => other,
     }
@@ -417,7 +417,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
         );
         if result != 0 {
             use crate::io::ErrorKind;
-            Err(io::Error::new_const(ErrorKind::Uncategorized, &"Error getting executable path"))
+            Err(io::const_io_error!(ErrorKind::Uncategorized, "Error getting executable path"))
         } else {
             let name = CStr::from_ptr((*info.as_ptr()).name.as_ptr()).to_bytes();
             Ok(PathBuf::from(OsStr::from_bytes(name)))
@@ -433,7 +433,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
 #[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
 pub fn current_exe() -> io::Result<PathBuf> {
     use crate::io::ErrorKind;
-    Err(io::Error::new_const(ErrorKind::Unsupported, &"Not yet implemented!"))
+    Err(io::const_io_error!(ErrorKind::Unsupported, "Not yet implemented!"))
 }
 
 #[cfg(target_os = "vxworks")]
index 717add9ec48dbe40aa2823c8b3c13dabc590b203..6d6f4c8b8dc63f4581f1823bf04adfe7cb953ecd 100644 (file)
@@ -1,5 +1,7 @@
+use crate::env;
 use crate::ffi::OsStr;
-use crate::path::Prefix;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
 
 #[inline]
 pub fn is_sep_byte(b: u8) -> bool {
@@ -18,3 +20,43 @@ pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
 
 pub const MAIN_SEP_STR: &str = "/";
 pub const MAIN_SEP: char = '/';
+
+/// Make a POSIX path absolute without changing its semantics.
+pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
+    // This is mostly a wrapper around collecting `Path::components`, with
+    // exceptions made where this conflicts with the POSIX specification.
+    // See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
+    // https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
+
+    let mut components = path.components();
+    let path_os = path.as_os_str().bytes();
+
+    let mut normalized = if path.is_absolute() {
+        // "If a pathname begins with two successive <slash> characters, the
+        // first component following the leading <slash> characters may be
+        // interpreted in an implementation-defined manner, although more than
+        // two leading <slash> characters shall be treated as a single <slash>
+        // character."
+        if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
+            components.next();
+            PathBuf::from("//")
+        } else {
+            PathBuf::new()
+        }
+    } else {
+        env::current_dir()?
+    };
+    normalized.extend(components);
+
+    // "Interfaces using pathname resolution may specify additional constraints
+    // when a pathname that does not name an existing directory contains at
+    // least one non- <slash> character and contains one or more trailing
+    // <slash> characters".
+    // A trailing <slash> is also meaningful if "a symbolic link is
+    // encountered during pathname resolution".
+    if path_os.ends_with(b"/") {
+        normalized.push("");
+    }
+
+    Ok(normalized)
+}
index 7ac2f9d8af75a139609b84d5cb47bd349f83c1a8..97985ddd3316b0e8a40e21bc2355c0a6f12ac1e8 100644 (file)
@@ -476,6 +476,12 @@ pub fn as_i32(&self) -> i32 {
     }
 }
 
+impl From<u8> for ExitCode {
+    fn from(code: u8) -> Self {
+        Self(code)
+    }
+}
+
 pub struct CommandArgs<'a> {
     iter: crate::slice::Iter<'a, CString>,
 }
index ce77c210a6220c28ae2e8f22727b2adeab3c6f33..09bfd9680f5b2c50841d9ee9b9267c1a62e6e7a7 100644 (file)
@@ -23,9 +23,9 @@ pub fn spawn(
         let envp = self.capture_env();
 
         if self.saw_nul() {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 io::ErrorKind::InvalidInput,
-                &"nul byte found in provided data",
+                "nul byte found in provided data",
             ));
         }
 
@@ -38,9 +38,9 @@ pub fn spawn(
 
     pub fn exec(&mut self, default: Stdio) -> io::Error {
         if self.saw_nul() {
-            return io::Error::new_const(
+            return io::const_io_error!(
                 io::ErrorKind::InvalidInput,
-                &"nul byte found in provided data",
+                "nul byte found in provided data",
             );
         }
 
@@ -186,9 +186,9 @@ pub fn wait(&mut self) -> io::Result<ExitStatus> {
             ))?;
         }
         if actual != 1 {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 io::ErrorKind::InvalidData,
-                &"Failed to get exit status of process",
+                "Failed to get exit status of process",
             ));
         }
         Ok(ExitStatus(proc_info.return_code))
@@ -224,9 +224,9 @@ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
             ))?;
         }
         if actual != 1 {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 io::ErrorKind::InvalidData,
-                &"Failed to get exit status of process",
+                "Failed to get exit status of process",
             ));
         }
         Ok(Some(ExitStatus(proc_info.return_code)))
index bce35b380e677075da4f2f2a43024787b5d6b378..9fc2d9fce4dc41b5df8c5fe2b0a5762a03b1bb24 100644 (file)
@@ -44,9 +44,9 @@ pub fn spawn(
         let envp = self.capture_env();
 
         if self.saw_nul() {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 ErrorKind::InvalidInput,
-                &"nul byte found in provided data",
+                "nul byte found in provided data",
             ));
         }
 
@@ -222,10 +222,7 @@ pub fn exec(&mut self, default: Stdio) -> io::Error {
         let envp = self.capture_env();
 
         if self.saw_nul() {
-            return io::Error::new_const(
-                ErrorKind::InvalidInput,
-                &"nul byte found in provided data",
-            );
+            return io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data",);
         }
 
         match self.setup_io(default, true) {
@@ -581,9 +578,9 @@ pub fn kill(&mut self) -> io::Result<()> {
         // and used for another process, and we probably shouldn't be killing
         // random processes, so just return an error.
         if self.status.is_some() {
-            Err(Error::new_const(
+            Err(io::const_io_error!(
                 ErrorKind::InvalidInput,
-                &"invalid argument: can't kill an exited process",
+                "invalid argument: can't kill an exited process",
             ))
         } else {
             cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
index c17822f51253266d1e66d3cbde32b88b9809fc1b..c6714d3aae246ffb8d640b8cb34106dfcfc31d8b 100644 (file)
@@ -24,9 +24,9 @@ pub fn spawn(
         let envp = self.capture_env();
 
         if self.saw_nul() {
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 ErrorKind::InvalidInput,
-                &"nul byte found in provided data",
+                "nul byte found in provided data",
             ));
         }
         let (ours, theirs) = self.setup_io(default, needs_stdin)?;
@@ -142,9 +142,9 @@ pub fn kill(&mut self) -> io::Result<()> {
         // and used for another process, and we probably shouldn't be killing
         // random processes, so just return an error.
         if self.status.is_some() {
-            Err(Error::new_const(
+            Err(io::const_io_error!(
                 ErrorKind::InvalidInput,
-                &"invalid argument: can't kill an exited process",
+                "invalid argument: can't kill an exited process",
             ))
         } else {
             cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(drop)
index 9e02966b57c0d1066486eca3c1fadd507055a364..cf8cf5ad49f73d03f3122f7a81a318928d8e23d5 100644 (file)
@@ -287,7 +287,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
             }
             match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
                 -1 => Err(io::Error::last_os_error()),
-                0 => Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform")),
+                0 => Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
                 cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }),
             }
         } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
@@ -318,7 +318,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
                 if res == -1 {
                     return Err(io::Error::last_os_error());
                 } else if cpus == 0 {
-                    return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+                    return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
                 }
             }
             Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
@@ -344,7 +344,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
             if res == -1 {
                 return Err(io::Error::last_os_error());
             } else if cpus == 0 {
-                return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+                return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
             }
 
             Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
@@ -356,14 +356,14 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
                 let res = libc::get_system_info(&mut sinfo);
 
                 if res != libc::B_OK {
-                    return Err(io::Error::new_const(io::ErrorKind::NotFound, &"The number of hardware threads is not known for the target platform"));
+                    return Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
                 }
 
                 Ok(NonZeroUsize::new_unchecked(sinfo.cpu_count as usize))
             }
         } else {
             // FIXME: implement on vxWorks, Redox, l4re
-            Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Getting the number of hardware threads is not supported on the target platform"))
+            Err(io::const_io_error!(io::ErrorKind::Unsupported, "Getting the number of hardware threads is not supported on the target platform"))
         }
     }
 }
index 824283ef6c41eea84ca6543844632bc3ff4138ee..59ddd1aa92f813d91151254fba2d5734ec887b45 100644 (file)
@@ -154,14 +154,6 @@ pub fn now() -> Instant {
             Instant { t: unsafe { mach_absolute_time() } }
         }
 
-        pub const fn zero() -> Instant {
-            Instant { t: 0 }
-        }
-
-        pub fn actually_monotonic() -> bool {
-            true
-        }
-
         pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
             let diff = self.t.checked_sub(other.t)?;
             let info = info();
@@ -296,17 +288,6 @@ pub fn now() -> Instant {
             Instant { t: now(libc::CLOCK_MONOTONIC) }
         }
 
-        pub const fn zero() -> Instant {
-            Instant { t: Timespec::zero() }
-        }
-
-        pub fn actually_monotonic() -> bool {
-            (cfg!(target_os = "linux") && cfg!(target_arch = "x86_64"))
-                || (cfg!(target_os = "linux") && cfg!(target_arch = "x86"))
-                || (cfg!(target_os = "linux") && cfg!(target_arch = "aarch64"))
-                || cfg!(target_os = "fuchsia")
-        }
-
         pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
             self.t.sub_timespec(&other.t).ok()
         }
index a06b44e96a923ae6fbe6940151d706edda592fb6..5274f53a7dbdb5be7fdcf270c4526d269885b681 100644 (file)
@@ -21,9 +21,9 @@ pub fn unsupported<T>() -> std_io::Result<T> {
 }
 
 pub fn unsupported_err() -> std_io::Error {
-    std_io::Error::new_const(
+    std_io::const_io_error!(
         std_io::ErrorKind::Unsupported,
-        &"operation not supported on this platform",
+        "operation not supported on this platform",
     )
 }
 
index 2886ec1180e54fab37ec126c6e0da7e0ac096092..e150ae143ad99b271338186ba51110a55e2cfd97 100644 (file)
@@ -81,11 +81,11 @@ pub fn getenv(_: &OsStr) -> Option<OsString> {
 }
 
 pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
-    Err(io::Error::new_const(io::ErrorKind::Unsupported, &"cannot set env vars on this platform"))
+    Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
 }
 
 pub fn unsetenv(_: &OsStr) -> io::Result<()> {
-    Err(io::Error::new_const(io::ErrorKind::Unsupported, &"cannot unset env vars on this platform"))
+    Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
 }
 
 pub fn temp_dir() -> PathBuf {
index 7846e43cfb53ee56aa0be7b9c0e2a11781e05725..42a1ff730e37997ca3b6c0362e513cdea51b9d0e 100644 (file)
@@ -162,6 +162,15 @@ pub fn as_i32(&self) -> i32 {
     }
 }
 
+impl From<u8> for ExitCode {
+    fn from(code: u8) -> Self {
+        match code {
+            0 => Self::SUCCESS,
+            1..=255 => Self::FAILURE,
+        }
+    }
+}
+
 pub struct Process(!);
 
 impl Process {
index 8aaf1777f242721db24eb70e917c826e8c13e7e6..6d67b538a96bf5dfa47f86da629cf3f1736c9e34 100644 (file)
@@ -13,14 +13,6 @@ pub fn now() -> Instant {
         panic!("time not implemented on this platform")
     }
 
-    pub const fn zero() -> Instant {
-        Instant(Duration::from_secs(0))
-    }
-
-    pub fn actually_monotonic() -> bool {
-        false
-    }
-
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
         self.0.checked_sub(other.0)
     }
index 5924789d12ba40bb75ef46e06d0efd187b380712..cd6815bfc2136786e36a73b6225852782535453d 100644 (file)
@@ -711,7 +711,7 @@ pub fn __wasilibc_find_relpath(
 
 pub fn osstr2str(f: &OsStr) -> io::Result<&str> {
     f.to_str()
-        .ok_or_else(|| io::Error::new_const(io::ErrorKind::Uncategorized, &"input must be utf-8"))
+        .ok_or_else(|| io::const_io_error!(io::ErrorKind::Uncategorized, "input must be utf-8"))
 }
 
 pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
@@ -757,7 +757,7 @@ fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> {
     for entry in ReadDir::new(fd, dummy_root) {
         let entry = entry?;
         let path = crate::str::from_utf8(&entry.name).map_err(|_| {
-            io::Error::new_const(io::ErrorKind::Uncategorized, &"invalid utf-8 file name found")
+            io::const_io_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found")
         })?;
 
         if entry.file_type()?.is_dir() {
index db0ddecf0c62942e30304e99d2445d9f98cb8b5d..088585654b948fa2f92a2acefc7e120c3ded648e 100644 (file)
@@ -25,14 +25,6 @@ pub fn now() -> Instant {
         Instant(current_time(wasi::CLOCKID_MONOTONIC))
     }
 
-    pub const fn zero() -> Instant {
-        Instant(Duration::from_secs(0))
-    }
-
-    pub fn actually_monotonic() -> bool {
-        true
-    }
-
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
         self.0.checked_sub(other.0)
     }
index 09d3661e4fd52d0b961f5e8fcaf898a3fe21ef71..c7b6290693ea0f4c0f56ccff542260cd25bd719e 100644 (file)
 pub const FILE_ATTRIBUTE_READONLY: DWORD = 0x1;
 pub const FILE_ATTRIBUTE_DIRECTORY: DWORD = 0x10;
 pub const FILE_ATTRIBUTE_REPARSE_POINT: DWORD = 0x400;
+pub const INVALID_FILE_ATTRIBUTES: DWORD = DWORD::MAX;
 
 pub const FILE_SHARE_DELETE: DWORD = 0x4;
 pub const FILE_SHARE_READ: DWORD = 0x1;
 pub const FILE_SHARE_WRITE: DWORD = 0x2;
 
+pub const FILE_OPEN: ULONG = 0x00000001;
 pub const FILE_OPEN_REPARSE_POINT: ULONG = 0x200000;
 pub const OBJ_DONT_REPARSE: ULONG = 0x1000;
 
@@ -1074,6 +1076,7 @@ pub fn GetFullPathNameW(
         lpBuffer: LPWSTR,
         lpFilePart: *mut LPWSTR,
     ) -> DWORD;
+    pub fn GetFileAttributesW(lpFileName: LPCWSTR) -> DWORD;
 }
 
 #[link(name = "ws2_32")]
@@ -1228,15 +1231,20 @@ pub fn WakeByAddressSingle(Address: LPVOID) -> () {
 
 compat_fn! {
     "ntdll":
-    pub fn NtOpenFile(
+    pub fn NtCreateFile(
         FileHandle: *mut HANDLE,
         DesiredAccess: ACCESS_MASK,
         ObjectAttributes: *const OBJECT_ATTRIBUTES,
         IoStatusBlock: *mut IO_STATUS_BLOCK,
+        AllocationSize: *mut i64,
+        FileAttributes: ULONG,
         ShareAccess: ULONG,
-        OpenOptions: ULONG
+        CreateDisposition: ULONG,
+        CreateOptions: ULONG,
+        EaBuffer: *mut c_void,
+        EaLength: ULONG
     ) -> NTSTATUS {
-        panic!("`NtOpenFile` not available");
+        panic!("`NtCreateFile` not available");
     }
     pub fn RtlNtStatusToDosError(
         Status: NTSTATUS
index 028b6b30099dd7a7146b694b5c2ca1cbd32afd6e..cb83ee2469a1c685f204f704550ca8be42d398de 100644 (file)
@@ -511,9 +511,9 @@ fn readlink(&self) -> io::Result<PathBuf> {
                     )
                 }
                 _ => {
-                    return Err(io::Error::new_const(
+                    return Err(io::const_io_error!(
                         io::ErrorKind::Uncategorized,
-                        &"Unsupported reparse point type",
+                        "Unsupported reparse point type",
                     ));
                 }
             };
@@ -712,11 +712,11 @@ fn next(&mut self) -> Option<Self::Item> {
 
 /// Open a link relative to the parent directory, ensure no symlinks are followed.
 fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result<File> {
-    // This is implemented using the lower level `NtOpenFile` function as
+    // This is implemented using the lower level `NtCreateFile` function as
     // unfortunately opening a file relative to a parent is not supported by
     // win32 functions. It is however a fundamental feature of the NT kernel.
     //
-    // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntopenfile
+    // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntcreatefile
     unsafe {
         let mut handle = ptr::null_mut();
         let mut io_status = c::IO_STATUS_BLOCK::default();
@@ -732,14 +732,19 @@ fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result<
             Attributes: ATTRIBUTES.load(Ordering::Relaxed),
             ..c::OBJECT_ATTRIBUTES::default()
         };
-        let status = c::NtOpenFile(
+        let status = c::NtCreateFile(
             &mut handle,
             access,
             &object,
             &mut io_status,
+            crate::ptr::null_mut(),
+            0,
             c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE,
+            c::FILE_OPEN,
             // If `name` is a symlink then open the link rather than the target.
             c::FILE_OPEN_REPARSE_POINT,
+            crate::ptr::null_mut(),
+            0,
         );
         // Convert an NTSTATUS to the more familiar Win32 error codes (aka "DosError")
         if c::nt_success(status) {
@@ -1124,9 +1129,9 @@ pub fn link(original: &Path, link: &Path) -> io::Result<()> {
 
 #[cfg(target_vendor = "uwp")]
 pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
-    return Err(io::Error::new_const(
+    return Err(io::const_io_error!(
         io::ErrorKind::Unsupported,
-        &"hard link are not supported on UWP",
+        "hard link are not supported on UWP",
     ));
 }
 
index ad4492f9d1f92a8c5e74eb1fa393758ef85ab585..dc288176346bcb4dfe4413836e031478060b6f30 100644 (file)
@@ -71,6 +71,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         c::ERROR_FILE_NOT_FOUND => return NotFound,
         c::ERROR_PATH_NOT_FOUND => return NotFound,
         c::ERROR_NO_DATA => return BrokenPipe,
+        c::ERROR_INVALID_NAME => return InvalidFilename,
         c::ERROR_INVALID_PARAMETER => return InvalidInput,
         c::ERROR_NOT_ENOUGH_MEMORY | c::ERROR_OUTOFMEMORY => return OutOfMemory,
         c::ERROR_SEM_TIMEOUT
@@ -104,7 +105,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
         c::ERROR_POSSIBLE_DEADLOCK => return Deadlock,
         c::ERROR_NOT_SAME_DEVICE => return CrossesDevices,
         c::ERROR_TOO_MANY_LINKS => return TooManyLinks,
-        c::ERROR_FILENAME_EXCED_RANGE => return FilenameTooLong,
+        c::ERROR_FILENAME_EXCED_RANGE => return InvalidFilename,
         _ => {}
     }
 
@@ -160,9 +161,9 @@ pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
     fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
         let mut maybe_result: Vec<u16> = s.encode_wide().collect();
         if unrolled_find_u16s(0, &maybe_result).is_some() {
-            return Err(crate::io::Error::new_const(
+            return Err(crate::io::const_io_error!(
                 ErrorKind::InvalidInput,
-                &"strings passed to WinAPI cannot contain NULs",
+                "strings passed to WinAPI cannot contain NULs",
             ));
         }
         maybe_result.push(0);
index 14d5f15d2024822585ad8b3c6cf3e6c4f9d0076a..aa6400aeefa0ddb2cb186c36f8e3ef3c636b2c5e 100644 (file)
@@ -152,9 +152,9 @@ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Resul
         match result {
             Err(ref error) if error.kind() == io::ErrorKind::WouldBlock => {
                 if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
-                    return Err(io::Error::new_const(
+                    return Err(io::const_io_error!(
                         io::ErrorKind::InvalidInput,
-                        &"cannot set a 0 duration timeout",
+                        "cannot set a 0 duration timeout",
                     ));
                 }
 
@@ -185,9 +185,7 @@ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Resul
                 };
 
                 match count {
-                    0 => {
-                        Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out"))
-                    }
+                    0 => Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out")),
                     _ => {
                         if writefds.fd_count != 1 {
                             if let Some(e) = self.take_error()? {
@@ -353,9 +351,9 @@ pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()>
             Some(dur) => {
                 let timeout = sys::dur2timeout(dur);
                 if timeout == 0 {
-                    return Err(io::Error::new_const(
+                    return Err(io::const_io_error!(
                         io::ErrorKind::InvalidInput,
-                        &"cannot set a 0 duration timeout",
+                        "cannot set a 0 duration timeout",
                     ));
                 }
                 timeout
index 79e0eaf6c34c6e813a80eba3c1d3491745030e48..e54fcaed4957d8ab38d440234ed36bd123991209 100644 (file)
@@ -260,3 +260,19 @@ pub(crate) fn maybe_verbatim(path: &Path) -> io::Result<Vec<u16>> {
     )?;
     Ok(path)
 }
+
+/// Make a Windows path absolute.
+pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
+    if path.as_os_str().bytes().starts_with(br"\\?\") {
+        return Ok(path.into());
+    }
+    let path = to_u16s(path)?;
+    let lpfilename = path.as_ptr();
+    fill_utf16_buf(
+        // SAFETY: `fill_utf16_buf` ensures the `buffer` and `size` are valid.
+        // `lpfilename` is a pointer to a null terminated string that is not
+        // invalidated until after `GetFullPathNameW` returns successfully.
+        |buffer, size| unsafe { c::GetFullPathNameW(lpfilename, size, buffer, ptr::null_mut()) },
+        super::os2path,
+    )
+}
index 5ad570427978e5244b0d8d9f4af8c9ae3488d77b..fafd1412d4cb31a54c98b403b3822fade1363d2d 100644 (file)
@@ -149,7 +149,7 @@ fn as_ref(&self) -> &OsStr {
 
 fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
     if str.as_ref().encode_wide().any(|b| b == 0) {
-        Err(io::Error::new_const(ErrorKind::InvalidInput, &"nul byte found in provided data"))
+        Err(io::const_io_error!(ErrorKind::InvalidInput, "nul byte found in provided data"))
     } else {
         Ok(str)
     }
@@ -369,9 +369,9 @@ fn resolve_exe<'a>(
 ) -> io::Result<PathBuf> {
     // Early return if there is no filename.
     if exe_path.is_empty() || path::has_trailing_slash(exe_path) {
-        return Err(io::Error::new_const(
+        return Err(io::const_io_error!(
             io::ErrorKind::InvalidInput,
-            &"program path has no file name",
+            "program path has no file name",
         ));
     }
     // Test if the file name has the `exe` extension.
@@ -394,7 +394,7 @@ fn resolve_exe<'a>(
 
         // Append `.exe` if not already there.
         path = path::append_suffix(path, EXE_SUFFIX.as_ref());
-        if path.try_exists().unwrap_or(false) {
+        if program_exists(&path) {
             return Ok(path);
         } else {
             // It's ok to use `set_extension` here because the intent is to
@@ -415,14 +415,14 @@ fn resolve_exe<'a>(
             if !has_extension {
                 path.set_extension(EXE_EXTENSION);
             }
-            if let Ok(true) = path.try_exists() { Some(path) } else { None }
+            if program_exists(&path) { Some(path) } else { None }
         });
         if let Some(path) = result {
             return Ok(path);
         }
     }
     // If we get here then the executable cannot be found.
-    Err(io::Error::new_const(io::ErrorKind::NotFound, &"program not found"))
+    Err(io::const_io_error!(io::ErrorKind::NotFound, "program not found"))
 }
 
 // Calls `f` for every path that should be used to find an executable.
@@ -485,6 +485,21 @@ fn search_paths<Paths, Exists>(
     None
 }
 
+/// Check if a file exists without following symlinks.
+fn program_exists(path: &Path) -> bool {
+    unsafe {
+        to_u16s(path)
+            .map(|path| {
+                // Getting attributes using `GetFileAttributesW` does not follow symlinks
+                // and it will almost always be successful if the link exists.
+                // There are some exceptions for special system files (e.g. the pagefile)
+                // but these are not executable.
+                c::GetFileAttributesW(path.as_ptr()) != c::INVALID_FILE_ATTRIBUTES
+            })
+            .unwrap_or(false)
+    }
+}
+
 impl Stdio {
     fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
         match *self {
@@ -666,6 +681,12 @@ pub fn as_i32(&self) -> i32 {
     }
 }
 
+impl From<u8> for ExitCode {
+    fn from(code: u8) -> Self {
+        ExitCode(c::DWORD::from(code))
+    }
+}
+
 fn zeroed_startupinfo() -> c::STARTUPINFO {
     c::STARTUPINFO {
         cb: 0,
index f1221767af30e56d43581d5d48183b27d057e7d3..d18c3d855bcce0e5ae1ccec17380cbbd9bd3995e 100644 (file)
@@ -135,6 +135,8 @@ fn windows_env_unicode_case() {
 fn windows_exe_resolver() {
     use super::resolve_exe;
     use crate::io;
+    use crate::sys::fs::symlink;
+    use crate::sys_common::io::test::tmpdir;
 
     let env_paths = || env::var_os("PATH");
 
@@ -178,4 +180,13 @@ fn windows_exe_resolver() {
     // The application's directory is also searched.
     let current_exe = env::current_exe().unwrap();
     assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok());
+
+    // Create a temporary path and add a broken symlink.
+    let temp = tmpdir();
+    let mut exe_path = temp.path().to_owned();
+    exe_path.push("exists.exe");
+    symlink("<DOES NOT EXIST>".as_ref(), &exe_path).unwrap();
+
+    // A broken symlink should still be resolved.
+    assert!(resolve_exe(OsStr::new("exists.exe"), empty_paths, Some(temp.path().as_ref())).is_ok());
 }
index 684b8e3155e84b1a6554424e5bf5afb45748373e..a001d6b9858234a79bce1044e4d8c7e49bcf02b6 100644 (file)
@@ -110,9 +110,9 @@ fn write(
         if data[0] >> 6 != 0b10 {
             // not a continuation byte - reject
             incomplete_utf8.len = 0;
-            return Err(io::Error::new_const(
+            return Err(io::const_io_error!(
                 io::ErrorKind::InvalidData,
-                &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+                "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
             ));
         }
         incomplete_utf8.bytes[incomplete_utf8.len as usize] = data[0];
@@ -132,9 +132,9 @@ fn write(
                 return Ok(1);
             }
             Err(_) => {
-                return Err(io::Error::new_const(
+                return Err(io::const_io_error!(
                     io::ErrorKind::InvalidData,
-                    &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+                    "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
                 ));
             }
         }
@@ -156,9 +156,9 @@ fn write(
                 incomplete_utf8.len = 1;
                 return Ok(1);
             } else {
-                return Err(io::Error::new_const(
+                return Err(io::const_io_error!(
                     io::ErrorKind::InvalidData,
-                    &"Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
+                    "Windows stdio in console mode does not support writing non-UTF-8 byte sequences",
                 ));
             }
         }
@@ -364,9 +364,9 @@ fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> {
             }
             Err(_) => {
                 // We can't really do any better than forget all data and return an error.
-                return Err(io::Error::new_const(
+                return Err(io::const_io_error!(
                     io::ErrorKind::InvalidData,
-                    &"Windows stdin in console mode does not support non-UTF-16 input; \
+                    "Windows stdin in console mode does not support non-UTF-16 input; \
                      encountered unpaired surrogate",
                 ));
             }
index 75f70c2076ee13efc9578ad91804aa82adc8d756..e4bba9255d23e774849196a88f09ee882638be2c 100644 (file)
@@ -107,9 +107,9 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
         sysinfo.dwNumberOfProcessors as usize
     };
     match res {
-        0 => Err(io::Error::new_const(
+        0 => Err(io::const_io_error!(
             io::ErrorKind::NotFound,
-            &"The number of hardware threads is not known for the target platform",
+            "The number of hardware threads is not known for the target platform",
         )),
         cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }),
     }
index 91e4f7654840d7025d7c8e1735bdff30f52300d0..a04908b541cdb58a859eba464d989be62c8ad2df 100644 (file)
@@ -41,14 +41,6 @@ pub fn now() -> Instant {
         perf_counter::PerformanceCounterInstant::now().into()
     }
 
-    pub fn actually_monotonic() -> bool {
-        false
-    }
-
-    pub const fn zero() -> Instant {
-        Instant { t: Duration::from_secs(0) }
-    }
-
     pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
         // On windows there's a threshold below which we consider two timestamps
         // equivalent due to measurement error. For more details + doc link,
index 309f5483874e00c7b8d16b582905a78edfce3862..617ac52e51ca81aeb24b4ddcc289cc31acacbcee 100644 (file)
@@ -4,9 +4,9 @@
 use crate::io::{self, Error, ErrorKind};
 use crate::path::Path;
 
-pub(crate) const NOT_FILE_ERROR: Error = Error::new_const(
+pub(crate) const NOT_FILE_ERROR: Error = io::const_io_error!(
     ErrorKind::InvalidInput,
-    &"the source path is neither a regular file nor a symlink to a regular file",
+    "the source path is neither a regular file nor a symlink to a regular file",
 );
 
 pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
index c5c3df361f34bf86066eee932b74817ae83f2a43..70b29d4a92ed56f64b837474229fd208ee577d52 100644 (file)
@@ -5,7 +5,7 @@
 use crate::convert::{TryFrom, TryInto};
 use crate::ffi::CString;
 use crate::fmt;
-use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut};
+use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
 use crate::mem;
 use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
 use crate::ptr;
@@ -102,7 +102,7 @@ pub fn sockaddr_to_addr(storage: &c::sockaddr_storage, len: usize) -> io::Result
                 *(storage as *const _ as *const c::sockaddr_in6)
             })))
         }
-        _ => Err(Error::new_const(ErrorKind::InvalidInput, &"invalid argument")),
+        _ => Err(io::const_io_error!(ErrorKind::InvalidInput, "invalid argument")),
     }
 }
 
@@ -165,7 +165,7 @@ macro_rules! try_opt {
             ($e:expr, $msg:expr) => {
                 match $e {
                     Some(r) => r,
-                    None => return Err(io::Error::new_const(io::ErrorKind::InvalidInput, &$msg)),
+                    None => return Err(io::const_io_error!(io::ErrorKind::InvalidInput, $msg)),
                 }
             };
         }
index 2d2b96c8bcec74df42b633a76cdf42a187c422e1..df8a726e64ecb380f13bea12112dc0f03a564336 100644 (file)
@@ -31,7 +31,6 @@
 
 #![stable(feature = "time", since = "1.3.0")]
 
-mod monotonic;
 #[cfg(test)]
 mod tests;
 
@@ -50,8 +49,8 @@
 /// A measurement of a monotonically nondecreasing clock.
 /// Opaque and useful only with [`Duration`].
 ///
-/// Instants are always guaranteed to be no less than any previously measured
-/// instant when created, and are often useful for tasks such as measuring
+/// Instants are always guaranteed, barring [platform bugs], to be no less than any previously
+/// measured instant when created, and are often useful for tasks such as measuring
 /// benchmarks or timing how long an operation takes.
 ///
 /// Note, however, that instants are **not** guaranteed to be **steady**. In other
@@ -84,6 +83,8 @@
 /// }
 /// ```
 ///
+/// [platform bugs]: Instant#monotonicity
+///
 /// # OS-specific behaviors
 ///
 /// An `Instant` is a wrapper around system-specific types and it may behave
 /// > structure cannot represent the new point in time.
 ///
 /// [`add`]: Instant::add
+///
+/// ## Monotonicity
+///
+/// On all platforms `Instant` will try to use an OS API that guarantees monotonic behavior
+/// if available, which is the case for all [tier 1] platforms.
+/// In practice such guarantees are – under rare circumstances – broken by hardware, virtualization
+/// or operating system bugs. To work around these bugs and platforms not offering monotonic clocks
+/// [`duration_since`], [`elapsed`] and [`sub`] saturate to zero. In older Rust versions this
+/// lead to a panic instead. [`checked_duration_since`] can be used to detect and handle situations
+/// where monotonicity is violated, or `Instant`s are subtracted in the wrong order.
+///
+/// This workaround obscures programming errors where earlier and later instants are accidentally
+/// swapped. For this reason future rust versions may reintroduce panics.
+///
+/// [tier 1]: https://doc.rust-lang.org/rustc/platform-support.html
+/// [`duration_since`]: Instant::duration_since
+/// [`elapsed`]: Instant::elapsed
+/// [`sub`]: Instant::sub
+/// [`checked_duration_since`]: Instant::checked_duration_since
+///
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[stable(feature = "time2", since = "1.8.0")]
 pub struct Instant(time::Instant);
@@ -247,59 +268,19 @@ impl Instant {
     #[must_use]
     #[stable(feature = "time2", since = "1.8.0")]
     pub fn now() -> Instant {
-        let os_now = time::Instant::now();
-
-        // And here we come upon a sad state of affairs. The whole point of
-        // `Instant` is that it's monotonically increasing. We've found in the
-        // wild, however, that it's not actually monotonically increasing for
-        // one reason or another. These appear to be OS and hardware level bugs,
-        // and there's not really a whole lot we can do about them. Here's a
-        // taste of what we've found:
-        //
-        // * #48514 - OpenBSD, x86_64
-        // * #49281 - linux arm64 and s390x
-        // * #51648 - windows, x86
-        // * #56560 - windows, x86_64, AWS
-        // * #56612 - windows, x86, vm (?)
-        // * #56940 - linux, arm64
-        // * https://bugzilla.mozilla.org/show_bug.cgi?id=1487778 - a similar
-        //   Firefox bug
-        //
-        // It seems that this just happens a lot in the wild.
-        // We're seeing panics across various platforms where consecutive calls
-        // to `Instant::now`, such as via the `elapsed` function, are panicking
-        // as they're going backwards. Placed here is a last-ditch effort to try
-        // to fix things up. We keep a global "latest now" instance which is
-        // returned instead of what the OS says if the OS goes backwards.
-        //
-        // To hopefully mitigate the impact of this, a few platforms are
-        // excluded as "these at least haven't gone backwards yet".
-        //
-        // While issues have been seen on arm64 platforms the Arm architecture
-        // requires that the counter monotonically increases and that it must
-        // provide a uniform view of system time (e.g. it must not be possible
-        // for a core to receive a message from another core with a time stamp
-        // and observe time going backwards (ARM DDI 0487G.b D11.1.2). While
-        // there have been a few 64bit SoCs that have bugs which cause time to
-        // not monoticially increase, these have been fixed in the Linux kernel
-        // and we shouldn't penalize all Arm SoCs for those who refuse to
-        // update their kernels:
-        // SUN50I_ERRATUM_UNKNOWN1 - Allwinner A64 / Pine A64 - fixed in 5.1
-        // FSL_ERRATUM_A008585 - Freescale LS2080A/LS1043A - fixed in 4.10
-        // HISILICON_ERRATUM_161010101 - Hisilicon 1610 - fixed in 4.11
-        // ARM64_ERRATUM_858921 - Cortex A73 - fixed in 4.12
-        if time::Instant::actually_monotonic() {
-            return Instant(os_now);
-        }
-
-        Instant(monotonic::monotonize(os_now))
+        Instant(time::Instant::now())
     }
 
-    /// Returns the amount of time elapsed from another instant to this one.
+    /// Returns the amount of time elapsed from another instant to this one,
+    /// or zero duration if that instant is later than this one.
     ///
     /// # Panics
     ///
-    /// This function will panic if `earlier` is later than `self`.
+    /// Previous rust versions panicked when `earlier` was later than `self`. Currently this
+    /// method saturates. Future versions may reintroduce the panic in some circumstances.
+    /// See [Monotonicity].
+    ///
+    /// [Monotonicity]: Instant#monotonicity
     ///
     /// # Examples
     ///
@@ -311,16 +292,22 @@ pub fn now() -> Instant {
     /// sleep(Duration::new(1, 0));
     /// let new_now = Instant::now();
     /// println!("{:?}", new_now.duration_since(now));
+    /// println!("{:?}", now.duration_since(new_now)); // 0ns
     /// ```
     #[must_use]
     #[stable(feature = "time2", since = "1.8.0")]
     pub fn duration_since(&self, earlier: Instant) -> Duration {
-        self.0.checked_sub_instant(&earlier.0).expect("supplied instant is later than self")
+        self.checked_duration_since(earlier).unwrap_or_default()
     }
 
     /// Returns the amount of time elapsed from another instant to this one,
     /// or None if that instant is later than this one.
     ///
+    /// Due to [monotonicity bugs], even under correct logical ordering of the passed `Instant`s,
+    /// this method can return `None`.
+    ///
+    /// [monotonicity bugs]: Instant#monotonicity
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -364,9 +351,11 @@ pub fn saturating_duration_since(&self, earlier: Instant) -> Duration {
     ///
     /// # Panics
     ///
-    /// This function may panic if the current time is earlier than this
-    /// instant, which is something that can happen if an `Instant` is
-    /// produced synthetically.
+    /// Previous rust versions panicked when self was earlier than the current time. Currently this
+    /// method returns a Duration of zero in that case. Future versions may reintroduce the panic.
+    /// See [Monotonicity].
+    ///
+    /// [Monotonicity]: Instant#monotonicity
     ///
     /// # Examples
     ///
@@ -442,6 +431,16 @@ fn sub_assign(&mut self, other: Duration) {
 impl Sub<Instant> for Instant {
     type Output = Duration;
 
+    /// Returns the amount of time elapsed from another instant to this one,
+    /// or zero duration if that instant is later than this one.
+    ///
+    /// # Panics
+    ///
+    /// Previous rust versions panicked when `other` was later than `self`. Currently this
+    /// method saturates. Future versions may reintroduce the panic in some circumstances.
+    /// See [Monotonicity].
+    ///
+    /// [Monotonicity]: Instant#monotonicity
     fn sub(self, other: Instant) -> Duration {
         self.duration_since(other)
     }
diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs
deleted file mode 100644 (file)
index 64f1624..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-use crate::sys::time;
-
-#[inline]
-pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
-    inner::monotonize(raw)
-}
-
-#[cfg(any(all(target_has_atomic = "64", not(target_has_atomic = "128")), target_arch = "aarch64"))]
-pub mod inner {
-    use crate::sync::atomic::AtomicU64;
-    use crate::sync::atomic::Ordering::*;
-    use crate::sys::time;
-    use crate::time::Duration;
-
-    pub(in crate::time) const ZERO: time::Instant = time::Instant::zero();
-
-    // bits 30 and 31 are never used since the nanoseconds part never exceeds 10^9
-    const UNINITIALIZED: u64 = 0b11 << 30;
-    static MONO: AtomicU64 = AtomicU64::new(UNINITIALIZED);
-
-    #[inline]
-    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
-        monotonize_impl(&MONO, raw)
-    }
-
-    #[inline]
-    pub(in crate::time) fn monotonize_impl(mono: &AtomicU64, raw: time::Instant) -> time::Instant {
-        let delta = raw.checked_sub_instant(&ZERO).unwrap();
-        let secs = delta.as_secs();
-        // occupies no more than 30 bits (10^9 seconds)
-        let nanos = delta.subsec_nanos() as u64;
-
-        // This wraps around every 136 years (2^32 seconds).
-        // To detect backsliding we use wrapping arithmetic and declare forward steps smaller
-        // than 2^31 seconds as expected and everything else as a backslide which will be
-        // monotonized.
-        // This could be a problem for programs that call instants at intervals greater
-        // than 68 years. Interstellar probes may want to ensure that actually_monotonic() is true.
-        let packed = (secs << 32) | nanos;
-        let updated = mono.fetch_update(Relaxed, Relaxed, |old| {
-            (old == UNINITIALIZED || packed.wrapping_sub(old) < u64::MAX / 2).then_some(packed)
-        });
-        match updated {
-            Ok(_) => raw,
-            Err(newer) => {
-                // Backslide occurred. We reconstruct monotonized time from the upper 32 bit of the
-                // passed in value and the 64bits loaded from the atomic
-                let seconds_lower = newer >> 32;
-                let mut seconds_upper = secs & 0xffff_ffff_0000_0000;
-                if secs & 0xffff_ffff > seconds_lower {
-                    // Backslide caused the lower 32bit of the seconds part to wrap.
-                    // This must be the case because the seconds part is larger even though
-                    // we are in the backslide branch, i.e. the seconds count should be smaller or equal.
-                    //
-                    // We assume that backslides are smaller than 2^32 seconds
-                    // which means we need to add 1 to the upper half to restore it.
-                    //
-                    // Example:
-                    // most recent observed time: 0xA1_0000_0000_0000_0000u128
-                    // bits stored in AtomicU64:     0x0000_0000_0000_0000u64
-                    // backslide by 1s
-                    // caller time is             0xA0_ffff_ffff_0000_0000u128
-                    // -> we can fix up the upper half time by adding 1 << 32
-                    seconds_upper = seconds_upper.wrapping_add(0x1_0000_0000);
-                }
-                let secs = seconds_upper | seconds_lower;
-                let nanos = newer as u32;
-                ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
-            }
-        }
-    }
-}
-
-#[cfg(all(target_has_atomic = "128", not(target_arch = "aarch64")))]
-pub mod inner {
-    use crate::sync::atomic::AtomicU128;
-    use crate::sync::atomic::Ordering::*;
-    use crate::sys::time;
-    use crate::time::Duration;
-
-    const ZERO: time::Instant = time::Instant::zero();
-    static MONO: AtomicU128 = AtomicU128::new(0);
-
-    #[inline]
-    pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
-        let delta = raw.checked_sub_instant(&ZERO).unwrap();
-        // Split into seconds and nanos since Duration doesn't have a
-        // constructor that takes a u128
-        let secs = delta.as_secs() as u128;
-        let nanos = delta.subsec_nanos() as u128;
-        let timestamp: u128 = secs << 64 | nanos;
-        let timestamp = MONO.fetch_max(timestamp, Relaxed).max(timestamp);
-        let secs = (timestamp >> 64) as u64;
-        let nanos = timestamp as u32;
-        ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
-    }
-}
-
-#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
-pub mod inner {
-    use crate::cmp;
-    use crate::sys::time;
-    use crate::sys_common::mutex::StaticMutex;
-
-    #[inline]
-    pub(super) fn monotonize(os_now: time::Instant) -> time::Instant {
-        static LOCK: StaticMutex = StaticMutex::new();
-        static mut LAST_NOW: time::Instant = time::Instant::zero();
-        unsafe {
-            let _lock = LOCK.lock();
-            let now = cmp::max(LAST_NOW, os_now);
-            LAST_NOW = now;
-            now
-        }
-    }
-}
index 7279925a6d0bef166ad8b044d6b36bad1626afb8..d1a69ff8697c654422b31191a0b5e878fcc828fb 100644 (file)
@@ -90,10 +90,9 @@ fn instant_math_is_associative() {
 }
 
 #[test]
-#[should_panic]
-fn instant_duration_since_panic() {
+fn instant_duration_since_saturates() {
     let a = Instant::now();
-    let _ = (a - Duration::SECOND).duration_since(a);
+    assert_eq!((a - Duration::SECOND).duration_since(a), Duration::ZERO);
 }
 
 #[test]
@@ -109,6 +108,7 @@ fn instant_checked_duration_since_nopanic() {
 #[test]
 fn instant_saturating_duration_since_nopanic() {
     let a = Instant::now();
+    #[allow(deprecated, deprecated_in_future)]
     let ret = (a - Duration::SECOND).saturating_duration_since(a);
     assert_eq!(ret, Duration::ZERO);
 }
@@ -192,31 +192,6 @@ fn since_epoch() {
     assert!(a < hundred_twenty_years);
 }
 
-#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
-#[test]
-fn monotonizer_wrapping_backslide() {
-    use super::monotonic::inner::{monotonize_impl, ZERO};
-    use core::sync::atomic::AtomicU64;
-
-    let reference = AtomicU64::new(0);
-
-    let time = match ZERO.checked_add_duration(&Duration::from_secs(0xffff_ffff)) {
-        Some(time) => time,
-        None => {
-            // platform cannot represent u32::MAX seconds so it won't have to deal with this kind
-            // of overflow either
-            return;
-        }
-    };
-
-    let monotonized = monotonize_impl(&reference, time);
-    let expected = ZERO.checked_add_duration(&Duration::from_secs(1 << 32)).unwrap();
-    assert_eq!(
-        monotonized, expected,
-        "64bit monotonizer should handle overflows in the seconds part"
-    );
-}
-
 macro_rules! bench_instant_threaded {
     ($bench_name:ident, $thread_count:expr) => {
         #[bench]
index 14a9e3acca499e89ceaa3ca54e25702e855b0388..54873f5549bfda37e7d2fd4f988cabbbd916e2c8 100644 (file)
@@ -3,10 +3,9 @@
 #![cfg_attr(
     any(
         all(target_arch = "arm", any(target_os = "linux", target_os = "android")),
-        all(target_arch = "aarch64", 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"),
-        any(target_arch = "x86", target_arch = "x86_64"),
     ),
     feature(stdsimd)
 )]
@@ -46,7 +45,8 @@ fn aarch64_linux() {
     println!("flagm: {}", is_aarch64_feature_detected!("flagm"));
     println!("ssbs: {}", is_aarch64_feature_detected!("ssbs"));
     println!("sb: {}", is_aarch64_feature_detected!("sb"));
-    println!("pauth: {}", is_aarch64_feature_detected!("pauth"));
+    println!("paca: {}", is_aarch64_feature_detected!("paca"));
+    println!("pacg: {}", is_aarch64_feature_detected!("pacg"));
     println!("dpb: {}", is_aarch64_feature_detected!("dpb"));
     println!("dpb2: {}", is_aarch64_feature_detected!("dpb2"));
     println!("sve2: {}", is_aarch64_feature_detected!("sve2"));
index eaee02ffdf5d820729ccdf2f95fa08b08c7d24d2..b4a0e07552cf90ef8f1a5b775bf70e4db94b3d63 160000 (submodule)
@@ -1 +1 @@
-Subproject commit eaee02ffdf5d820729ccdf2f95fa08b08c7d24d2
+Subproject commit b4a0e07552cf90ef8f1a5b775bf70e4db94b3d63
index cb40b4e965b2a56d81184ec3d65d7c14b859208b..b39701a3d428828bf0cb7453553bdbdee6d9fec8 100644 (file)
@@ -109,12 +109,10 @@ fn optgroups() -> getopts::Options {
             unstable-options = Allow use of experimental features",
             "unstable-options",
         )
-        .optflagopt(
+        .optflag(
             "",
             "report-time",
-            "Show execution time of each test. Available values:
-            plain   = do not colorize the execution time (default);
-            colored = colorize output according to the `color` parameter value;
+            "Show execution time of each test.
 
             Threshold values for colorized output can be configured via
             `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION` and
@@ -125,7 +123,6 @@ fn optgroups() -> getopts::Options {
             is 0.5 seconds, and the critical time is 2 seconds.
 
             Not available for --format=terse",
-            "plain|colored",
         )
         .optflag(
             "",
@@ -319,17 +316,12 @@ fn get_time_options(
     allow_unstable: bool,
 ) -> OptPartRes<Option<TestTimeOptions>> {
     let report_time = unstable_optflag!(matches, allow_unstable, "report-time");
-    let colored_opt_str = matches.opt_str("report-time");
-    let mut report_time_colored = report_time && colored_opt_str == Some("colored".into());
     let ensure_test_time = unstable_optflag!(matches, allow_unstable, "ensure-time");
 
     // If `ensure-test-time` option is provided, time output is enforced,
     // so user won't be confused if any of tests will silently fail.
     let options = if report_time || ensure_test_time {
-        if ensure_test_time && !report_time {
-            report_time_colored = true;
-        }
-        Some(TestTimeOptions::new_from_env(ensure_test_time, report_time_colored))
+        Some(TestTimeOptions::new_from_env(ensure_test_time))
     } else {
         None
     };
index 9c261e8cc8effcc707744698bf64f9bb10977d84..920f55ad251a651ca3f484c6d8f2fc1eb2c0d2c2 100644 (file)
@@ -47,7 +47,6 @@ pub struct ConsoleTestState {
     pub passed: usize,
     pub failed: usize,
     pub ignored: usize,
-    pub allowed_fail: usize,
     pub filtered_out: usize,
     pub measured: usize,
     pub exec_time: Option<TestSuiteExecTime>,
@@ -71,7 +70,6 @@ pub fn new(opts: &TestOpts) -> io::Result<ConsoleTestState> {
             passed: 0,
             failed: 0,
             ignored: 0,
-            allowed_fail: 0,
             filtered_out: 0,
             measured: 0,
             exec_time: None,
@@ -112,7 +110,6 @@ pub fn write_log_result(
                     TestResult::TrFailed => "failed".to_owned(),
                     TestResult::TrFailedMsg(ref msg) => format!("failed: {}", msg),
                     TestResult::TrIgnored => "ignored".to_owned(),
-                    TestResult::TrAllowedFail => "failed (allowed)".to_owned(),
                     TestResult::TrBench(ref bs) => fmt_bench_samples(bs),
                     TestResult::TrTimedFail => "failed (time limit exceeded)".to_owned(),
                 },
@@ -126,7 +123,7 @@ pub fn write_log_result(
     }
 
     fn current_test_count(&self) -> usize {
-        self.passed + self.failed + self.ignored + self.measured + self.allowed_fail
+        self.passed + self.failed + self.ignored + self.measured
     }
 }
 
@@ -191,7 +188,6 @@ fn handle_test_result(st: &mut ConsoleTestState, completed_test: CompletedTest)
             st.not_failures.push((test, stdout));
         }
         TestResult::TrIgnored => st.ignored += 1,
-        TestResult::TrAllowedFail => st.allowed_fail += 1,
         TestResult::TrBench(bs) => {
             st.metrics.insert_metric(
                 test.name.as_slice(),
index 424d3ef7b4106fd29139f73563a31e4a4b36cb9f..c089bfc4791b5e2bf9b8162c1e72b9bba4ff9d75 100644 (file)
@@ -124,15 +124,6 @@ fn write_result(
                 self.write_event("test", desc.name.as_slice(), "ignored", exec_time, stdout, None)
             }
 
-            TestResult::TrAllowedFail => self.write_event(
-                "test",
-                desc.name.as_slice(),
-                "allowed_failure",
-                exec_time,
-                stdout,
-                None,
-            ),
-
             TestResult::TrBench(ref bs) => {
                 let median = bs.ns_iter_summ.median as usize;
                 let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
@@ -172,14 +163,12 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
              \"event\": \"{}\", \
              \"passed\": {}, \
              \"failed\": {}, \
-             \"allowed_fail\": {}, \
              \"ignored\": {}, \
              \"measured\": {}, \
              \"filtered_out\": {}",
             if state.failed == 0 { "ok" } else { "failed" },
             state.passed,
-            state.failed + state.allowed_fail,
-            state.allowed_fail,
+            state.failed,
             state.ignored,
             state.measured,
             state.filtered_out,
index fa23cf2689671c14d8b7da1e14225bd8334d19d1..54e9860ab548779173d623709d5a33fe4c98eb9e 100644 (file)
@@ -33,7 +33,6 @@ fn write_run_start(
         _shuffle_seed: Option<u64>,
     ) -> io::Result<()> {
         // We write xml header on run start
-        self.out.write_all(b"\n")?;
         self.write_message("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
     }
 
@@ -122,7 +121,7 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
                     ))?;
                 }
 
-                TestResult::TrOk | TestResult::TrAllowedFail => {
+                TestResult::TrOk => {
                     self.write_message(&*format!(
                         "<testcase classname=\"{}\" \
                          name=\"{}\" time=\"{}\"/>",
@@ -138,7 +137,7 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
         self.write_message("</testsuite>")?;
         self.write_message("</testsuites>")?;
 
-        self.out.write_all(b"\n\n")?;
+        self.out.write_all(b"\n")?;
 
         Ok(state.failed == 0)
     }
index 4a03b4b9147605c392fe76e4d7fa725fb37f9b49..041df5216d7b307c5385a30f25b9963ca3290fb5 100644 (file)
@@ -49,10 +49,6 @@ pub fn write_ignored(&mut self) -> io::Result<()> {
         self.write_short_result("ignored", term::color::YELLOW)
     }
 
-    pub fn write_allowed_fail(&mut self) -> io::Result<()> {
-        self.write_short_result("FAILED (allowed)", term::color::YELLOW)
-    }
-
     pub fn write_time_failed(&mut self) -> io::Result<()> {
         self.write_short_result("FAILED (time limit exceeded)", term::color::RED)
     }
@@ -102,7 +98,7 @@ fn write_time(
         if let (Some(opts), Some(time)) = (self.time_options, exec_time) {
             let time_str = format!(" <{}>", time);
 
-            let color = if opts.colored {
+            let color = if self.use_color {
                 if opts.is_critical(desc, time) {
                     Some(term::color::RED)
                 } else if opts.is_warn(desc, time) {
@@ -219,7 +215,6 @@ fn write_result(
             TestResult::TrOk => self.write_ok()?,
             TestResult::TrFailed | TestResult::TrFailedMsg(_) => self.write_failed()?,
             TestResult::TrIgnored => self.write_ignored()?,
-            TestResult::TrAllowedFail => self.write_allowed_fail()?,
             TestResult::TrBench(ref bs) => {
                 self.write_bench()?;
                 self.write_plain(&format!(": {}", fmt_bench_samples(bs)))?;
@@ -263,22 +258,10 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
             self.write_pretty("FAILED", term::color::RED)?;
         }
 
-        let s = if state.allowed_fail > 0 {
-            format!(
-                ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out",
-                state.passed,
-                state.failed + state.allowed_fail,
-                state.allowed_fail,
-                state.ignored,
-                state.measured,
-                state.filtered_out
-            )
-        } else {
-            format!(
-                ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
-                state.passed, state.failed, state.ignored, state.measured, state.filtered_out
-            )
-        };
+        let s = format!(
+            ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
+            state.passed, state.failed, state.ignored, state.measured, state.filtered_out
+        );
 
         self.write_plain(&s)?;
 
index 1f2c410cd96f3902493d9a17eab2fc5bc95a466c..12aca7cd9a42dd7af12b5cea216bd1e164a751a4 100644 (file)
@@ -54,10 +54,6 @@ pub fn write_ignored(&mut self) -> io::Result<()> {
         self.write_short_result("i", term::color::YELLOW)
     }
 
-    pub fn write_allowed_fail(&mut self) -> io::Result<()> {
-        self.write_short_result("a", term::color::YELLOW)
-    }
-
     pub fn write_bench(&mut self) -> io::Result<()> {
         self.write_pretty("bench", term::color::CYAN)
     }
@@ -207,7 +203,6 @@ fn write_result(
                 self.write_failed()
             }
             TestResult::TrIgnored => self.write_ignored(),
-            TestResult::TrAllowedFail => self.write_allowed_fail(),
             TestResult::TrBench(ref bs) => {
                 if self.is_multithreaded {
                     self.write_test_name(desc)?;
@@ -244,22 +239,10 @@ fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> {
             self.write_pretty("FAILED", term::color::RED)?;
         }
 
-        let s = if state.allowed_fail > 0 {
-            format!(
-                ". {} passed; {} failed ({} allowed); {} ignored; {} measured; {} filtered out",
-                state.passed,
-                state.failed + state.allowed_fail,
-                state.allowed_fail,
-                state.ignored,
-                state.measured,
-                state.filtered_out
-            )
-        } else {
-            format!(
-                ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
-                state.passed, state.failed, state.ignored, state.measured, state.filtered_out
-            )
-        };
+        let s = format!(
+            ". {} passed; {} failed; {} ignored; {} measured; {} filtered out",
+            state.passed, state.failed, state.ignored, state.measured, state.filtered_out
+        );
 
         self.write_plain(&s)?;
 
index c5c56ca9c7ff9c57305d49946bdf6fec0b3aaa12..8c216a1e0e70e2d40206073610ac6b7be29a1cf1 100644 (file)
@@ -19,7 +19,6 @@ pub enum TestResult {
     TrFailed,
     TrFailedMsg(String),
     TrIgnored,
-    TrAllowedFail,
     TrBench(BenchSamples),
     TrTimedFail,
 }
@@ -42,8 +41,6 @@ pub fn calc_result<'a>(
 
             if maybe_panic_str.map(|e| e.contains(msg)).unwrap_or(false) {
                 TestResult::TrOk
-            } else if desc.allow_fail {
-                TestResult::TrAllowedFail
             } else if let Some(panic_str) = maybe_panic_str {
                 TestResult::TrFailedMsg(format!(
                     r#"panic did not contain expected string
@@ -64,7 +61,6 @@ pub fn calc_result<'a>(
         (&ShouldPanic::Yes, Ok(())) | (&ShouldPanic::YesWithMessage(_), Ok(())) => {
             TestResult::TrFailedMsg("test did not panic as expected".to_string())
         }
-        _ if desc.allow_fail => TestResult::TrAllowedFail,
         _ => TestResult::TrFailed,
     };
 
@@ -90,11 +86,10 @@ pub fn get_result_from_exit_code(
     time_opts: &Option<time::TestTimeOptions>,
     exec_time: &Option<time::TestExecTime>,
 ) -> TestResult {
-    let result = match (desc.allow_fail, code) {
-        (_, TR_OK) => TestResult::TrOk,
-        (true, TR_FAILED) => TestResult::TrAllowedFail,
-        (false, TR_FAILED) => TestResult::TrFailed,
-        (_, _) => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)),
+    let result = match code {
+        TR_OK => TestResult::TrOk,
+        TR_FAILED => TestResult::TrFailed,
+        _ => TestResult::TrFailedMsg(format!("got unexpected return code {}", code)),
     };
 
     // If test is already failed (or allowed to fail), do not change the result.
index 7f0b6193d09acc311d81842ceb9b7a6f7ee5e0c9..d566dbc09f434bfd09f6318bffc287ae58b6736e 100644 (file)
@@ -62,10 +62,11 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
                 name: StaticTestName("1"),
                 ignore: true,
                 should_panic: ShouldPanic::No,
-                allow_fail: false,
                 compile_fail: false,
                 no_run: false,
                 test_type: TestType::Unknown,
+                #[cfg(bootstrap)]
+                allow_fail: false,
             },
             testfn: DynTestFn(Box::new(move || {})),
         },
@@ -74,10 +75,11 @@ fn one_ignored_one_unignored_test() -> Vec<TestDescAndFn> {
                 name: StaticTestName("2"),
                 ignore: false,
                 should_panic: ShouldPanic::No,
-                allow_fail: false,
                 compile_fail: false,
                 no_run: false,
                 test_type: TestType::Unknown,
+                #[cfg(bootstrap)]
+                allow_fail: false,
             },
             testfn: DynTestFn(Box::new(move || {})),
         },
@@ -94,10 +96,11 @@ fn f() {
             name: StaticTestName("whatever"),
             ignore: true,
             should_panic: ShouldPanic::No,
-            allow_fail: false,
             compile_fail: false,
             no_run: false,
             test_type: TestType::Unknown,
+            #[cfg(bootstrap)]
+            allow_fail: false,
         },
         testfn: DynTestFn(Box::new(f)),
     };
@@ -115,10 +118,11 @@ fn f() {}
             name: StaticTestName("whatever"),
             ignore: true,
             should_panic: ShouldPanic::No,
-            allow_fail: false,
             compile_fail: false,
             no_run: false,
             test_type: TestType::Unknown,
+            #[cfg(bootstrap)]
+            allow_fail: false,
         },
         testfn: DynTestFn(Box::new(f)),
     };
@@ -140,10 +144,11 @@ fn f() {
             name: StaticTestName("whatever"),
             ignore: false,
             should_panic: ShouldPanic::Yes,
-            allow_fail: false,
             compile_fail: false,
             no_run: false,
             test_type: TestType::Unknown,
+            #[cfg(bootstrap)]
+            allow_fail: false,
         },
         testfn: DynTestFn(Box::new(f)),
     };
@@ -165,10 +170,11 @@ fn f() {
             name: StaticTestName("whatever"),
             ignore: false,
             should_panic: ShouldPanic::YesWithMessage("error message"),
-            allow_fail: false,
             compile_fail: false,
             no_run: false,
             test_type: TestType::Unknown,
+            #[cfg(bootstrap)]
+            allow_fail: false,
         },
         testfn: DynTestFn(Box::new(f)),
     };
@@ -195,10 +201,11 @@ fn f() {
             name: StaticTestName("whatever"),
             ignore: false,
             should_panic: ShouldPanic::YesWithMessage(expected),
-            allow_fail: false,
             compile_fail: false,
             no_run: false,
             test_type: TestType::Unknown,
+            #[cfg(bootstrap)]
+            allow_fail: false,
         },
         testfn: DynTestFn(Box::new(f)),
     };
@@ -229,10 +236,11 @@ fn f() {
             name: StaticTestName("whatever"),
             ignore: false,
             should_panic: ShouldPanic::YesWithMessage(expected),
-            allow_fail: false,
             compile_fail: false,
             no_run: false,
             test_type: TestType::Unknown,
+            #[cfg(bootstrap)]
+            allow_fail: false,
         },
         testfn: DynTestFn(Box::new(f)),
     };
@@ -255,10 +263,11 @@ fn f() {}
                 name: StaticTestName("whatever"),
                 ignore: false,
                 should_panic,
-                allow_fail: false,
                 compile_fail: false,
                 no_run: false,
                 test_type: TestType::Unknown,
+                #[cfg(bootstrap)]
+                allow_fail: false,
             },
             testfn: DynTestFn(Box::new(f)),
         };
@@ -289,10 +298,11 @@ fn f() {}
             name: StaticTestName("whatever"),
             ignore: false,
             should_panic: ShouldPanic::No,
-            allow_fail: false,
             compile_fail: false,
             no_run: false,
             test_type: TestType::Unknown,
+            #[cfg(bootstrap)]
+            allow_fail: false,
         },
         testfn: DynTestFn(Box::new(f)),
     };
@@ -324,10 +334,11 @@ fn f() {}
             name: StaticTestName("whatever"),
             ignore: false,
             should_panic: ShouldPanic::No,
-            allow_fail: false,
             compile_fail: false,
             no_run: false,
             test_type,
+            #[cfg(bootstrap)]
+            allow_fail: false,
         },
         testfn: DynTestFn(Box::new(f)),
     };
@@ -363,10 +374,11 @@ fn typed_test_desc(test_type: TestType) -> TestDesc {
         name: StaticTestName("whatever"),
         ignore: false,
         should_panic: ShouldPanic::No,
-        allow_fail: false,
         compile_fail: false,
         no_run: false,
         test_type,
+        #[cfg(bootstrap)]
+        allow_fail: false,
     }
 }
 
@@ -382,7 +394,6 @@ fn test_time_options_threshold() {
 
     let options = TestTimeOptions {
         error_on_excess: false,
-        colored: false,
         unit_threshold: unit.clone(),
         integration_threshold: integration.clone(),
         doctest_threshold: doc.clone(),
@@ -476,10 +487,11 @@ pub fn exclude_should_panic_option() {
             name: StaticTestName("3"),
             ignore: false,
             should_panic: ShouldPanic::Yes,
-            allow_fail: false,
             compile_fail: false,
             no_run: false,
             test_type: TestType::Unknown,
+            #[cfg(bootstrap)]
+            allow_fail: false,
         },
         testfn: DynTestFn(Box::new(move || {})),
     });
@@ -500,10 +512,11 @@ fn tests() -> Vec<TestDescAndFn> {
                     name: StaticTestName(name),
                     ignore: false,
                     should_panic: ShouldPanic::No,
-                    allow_fail: false,
                     compile_fail: false,
                     no_run: false,
                     test_type: TestType::Unknown,
+                    #[cfg(bootstrap)]
+                    allow_fail: false,
                 },
                 testfn: DynTestFn(Box::new(move || {})),
             })
@@ -589,10 +602,11 @@ fn testfn() {}
                 name: DynTestName((*name).clone()),
                 ignore: false,
                 should_panic: ShouldPanic::No,
-                allow_fail: false,
                 compile_fail: false,
                 no_run: false,
                 test_type: TestType::Unknown,
+                #[cfg(bootstrap)]
+                allow_fail: false,
             },
             testfn: DynTestFn(Box::new(testfn)),
         };
@@ -740,10 +754,11 @@ fn f(_: &mut Bencher) {}
         name: StaticTestName("f"),
         ignore: false,
         should_panic: ShouldPanic::No,
-        allow_fail: false,
         compile_fail: false,
         no_run: false,
         test_type: TestType::Unknown,
+        #[cfg(bootstrap)]
+        allow_fail: false,
     };
 
     crate::bench::benchmark(TestId(0), desc, tx, true, f);
@@ -762,10 +777,11 @@ fn f(b: &mut Bencher) {
         name: StaticTestName("f"),
         ignore: false,
         should_panic: ShouldPanic::No,
-        allow_fail: false,
         compile_fail: false,
         no_run: false,
         test_type: TestType::Unknown,
+        #[cfg(bootstrap)]
+        allow_fail: false,
     };
 
     crate::bench::benchmark(TestId(0), desc, tx, true, f);
@@ -778,20 +794,22 @@ fn should_sort_failures_before_printing_them() {
         name: StaticTestName("a"),
         ignore: false,
         should_panic: ShouldPanic::No,
-        allow_fail: false,
         compile_fail: false,
         no_run: false,
         test_type: TestType::Unknown,
+        #[cfg(bootstrap)]
+        allow_fail: false,
     };
 
     let test_b = TestDesc {
         name: StaticTestName("b"),
         ignore: false,
         should_panic: ShouldPanic::No,
-        allow_fail: false,
         compile_fail: false,
         no_run: false,
         test_type: TestType::Unknown,
+        #[cfg(bootstrap)]
+        allow_fail: false,
     };
 
     let mut out = PrettyFormatter::new(OutputLocation::Raw(Vec::new()), false, 10, false, None);
@@ -802,7 +820,6 @@ fn should_sort_failures_before_printing_them() {
         passed: 0,
         failed: 0,
         ignored: 0,
-        allowed_fail: 0,
         filtered_out: 0,
         measured: 0,
         exec_time: None,
index e0b6eadffa119a519a8dbc3c270acd694301756c..8c64e5d1b733944b6b41257ec767e73556d1e97d 100644 (file)
@@ -137,14 +137,13 @@ pub struct TestTimeOptions {
     /// Denotes if the test critical execution time limit excess should be considered
     /// a test failure.
     pub error_on_excess: bool,
-    pub colored: bool,
     pub unit_threshold: TimeThreshold,
     pub integration_threshold: TimeThreshold,
     pub doctest_threshold: TimeThreshold,
 }
 
 impl TestTimeOptions {
-    pub fn new_from_env(error_on_excess: bool, colored: bool) -> Self {
+    pub fn new_from_env(error_on_excess: bool) -> Self {
         let unit_threshold = TimeThreshold::from_env_var(time_constants::UNIT_ENV_NAME)
             .unwrap_or_else(Self::default_unit);
 
@@ -155,7 +154,7 @@ pub fn new_from_env(error_on_excess: bool, colored: bool) -> Self {
         let doctest_threshold = TimeThreshold::from_env_var(time_constants::DOCTEST_ENV_NAME)
             .unwrap_or_else(Self::default_doctest);
 
-        Self { error_on_excess, colored, unit_threshold, integration_threshold, doctest_threshold }
+        Self { error_on_excess, unit_threshold, integration_threshold, doctest_threshold }
     }
 
     pub fn is_warn(&self, test: &TestDesc, exec_time: &TestExecTime) -> bool {
index 37bb38fb0df4efb64d557d31d515e83cd2a7183d..43e5a10ebbe95a02f6184410fb9368e7556a1f1f 100644 (file)
@@ -118,10 +118,11 @@ pub struct TestDesc {
     pub name: TestName,
     pub ignore: bool,
     pub should_panic: options::ShouldPanic,
-    pub allow_fail: bool,
     pub compile_fail: bool,
     pub no_run: bool,
     pub test_type: TestType,
+    #[cfg(bootstrap)]
+    pub allow_fail: bool,
 }
 
 impl TestDesc {
@@ -150,9 +151,6 @@ pub fn test_mode(&self) -> Option<&'static str> {
             }
             options::ShouldPanic::No => {}
         }
-        if self.allow_fail {
-            return Some("allow fail");
-        }
         if self.compile_fail {
             return Some("compile fail");
         }
index 5e15fe75a2463632f14850d7433168c16936eed8..c8c5528b104ebeb24e6e76592f3d0137ec9cda96 100644 (file)
@@ -42,6 +42,9 @@ pub enum _Unwind_Reason_Code {
 #[cfg(all(target_arch = "aarch64", target_pointer_width = "32"))]
 pub const unwinder_private_data_size: usize = 5;
 
+#[cfg(target_arch = "m68k")]
+pub const unwinder_private_data_size: usize = 2;
+
 #[cfg(target_arch = "mips")]
 pub const unwinder_private_data_size: usize = 2;
 
index b68b2163f873a07291342ffef28dc7e7edbf8bd3..592a137e379dea7a77e041124fd319d0d7d73cba 100644 (file)
@@ -44,14 +44,22 @@ libc = "0.2"
 serde = { version = "1.0.8", features = ["derive"] }
 serde_json = "1.0.2"
 toml = "0.5"
-time = "0.1"
 ignore = "0.4.10"
 opener = "0.5"
 once_cell = "1.7.2"
 
 [target.'cfg(windows)'.dependencies.winapi]
 version = "0.3"
-features = ["fileapi", "ioapiset", "jobapi2", "handleapi", "winioctl", "psapi", "impl-default"]
+features = [
+    "fileapi",
+    "ioapiset",
+    "jobapi2",
+    "handleapi",
+    "winioctl",
+    "psapi",
+    "impl-default",
+    "timezoneapi",
+]
 
 [dev-dependencies]
-pretty_assertions = "0.6"
+pretty_assertions = "0.7"
index e730a2557e0bf38fd1f7a961b059c25c34c85a9b..9c41ab69c8be3784e4e07f12acc9c06d60b03844 100644 (file)
@@ -30,6 +30,7 @@ fn main() {
         println!("{}", suggestion);
     }
 
+    let pre_commit = config.src.join(".git").join("hooks").join("pre-commit");
     Build::new(config).build();
 
     if suggest_setup {
@@ -42,6 +43,19 @@ fn main() {
         println!("{}", suggestion);
     }
 
+    // Give a warning if the pre-commit script is in pre-commit and not pre-push.
+    // HACK: Since the commit script uses hard links, we can't actually tell if it was installed by x.py setup or not.
+    // We could see if it's identical to src/etc/pre-push.sh, but pre-push may have been modified in the meantime.
+    // Instead, look for this comment, which is almost certainly not in any custom hook.
+    if std::fs::read_to_string(pre_commit).map_or(false, |contents| {
+        contents.contains("https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570")
+    }) {
+        println!(
+            "warning: You have the pre-push script installed to .git/hooks/pre-commit. \
+                  Consider moving it to .git/hooks/pre-push instead, which runs less often."
+        );
+    }
+
     if suggest_setup || changelog_suggestion.is_some() {
         println!("note: this message was printed twice to make it more likely to be seen");
     }
index 6d7ab15326c5fc194fd94670d26c5e692cb27d7a..6c1128b393fed9207bb2662cdc5beeffa0f69260 100644 (file)
@@ -63,7 +63,7 @@ def support_xz():
     except tarfile.CompressionError:
         return False
 
-def get(base, url, path, checksums, verbose=False, do_verify=True):
+def get(base, url, path, checksums, verbose=False, do_verify=True, help_on_error=None):
     with tempfile.NamedTemporaryFile(delete=False) as temp_file:
         temp_path = temp_file.name
 
@@ -82,7 +82,7 @@ def get(base, url, path, checksums, verbose=False, do_verify=True):
                         print("ignoring already-download file",
                             path, "due to failed verification")
                     os.unlink(path)
-        download(temp_path, "{}/{}".format(base, url), True, verbose)
+        download(temp_path, "{}/{}".format(base, url), True, verbose, help_on_error=help_on_error)
         if do_verify and not verify(temp_path, sha256, verbose):
             raise RuntimeError("failed verification")
         if verbose:
@@ -95,17 +95,17 @@ def get(base, url, path, checksums, verbose=False, do_verify=True):
             os.unlink(temp_path)
 
 
-def download(path, url, probably_big, verbose):
+def download(path, url, probably_big, verbose, help_on_error=None):
     for _ in range(0, 4):
         try:
-            _download(path, url, probably_big, verbose, True)
+            _download(path, url, probably_big, verbose, True, help_on_error=help_on_error)
             return
         except RuntimeError:
             print("\nspurious failure, trying again")
-    _download(path, url, probably_big, verbose, False)
+    _download(path, url, probably_big, verbose, False, help_on_error=help_on_error)
 
 
-def _download(path, url, probably_big, verbose, exception):
+def _download(path, url, probably_big, verbose, exception, help_on_error=None):
     if probably_big or verbose:
         print("downloading {}".format(url))
     # see https://serverfault.com/questions/301128/how-to-download
@@ -126,7 +126,8 @@ def _download(path, url, probably_big, verbose, exception):
              "--connect-timeout", "30",  # timeout if cannot connect within 30 seconds
              "--retry", "3", "-Sf", "-o", path, url],
             verbose=verbose,
-            exception=exception)
+            exception=exception,
+            help_on_error=help_on_error)
 
 
 def verify(path, expected, verbose):
@@ -167,7 +168,7 @@ def unpack(tarball, tarball_suffix, dst, verbose=False, match=None):
     shutil.rmtree(os.path.join(dst, fname))
 
 
-def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs):
+def run(args, verbose=False, exception=False, is_bootstrap=False, help_on_error=None, **kwargs):
     """Run a child program in a new process"""
     if verbose:
         print("running: " + ' '.join(args))
@@ -178,6 +179,8 @@ def run(args, verbose=False, exception=False, is_bootstrap=False, **kwargs):
     code = ret.wait()
     if code != 0:
         err = "failed to run: " + ' '.join(args)
+        if help_on_error is not None:
+            err += "\n" + help_on_error
         if verbose or exception:
             raise RuntimeError(err)
         # For most failures, we definitely do want to print this error, or the user will have no
@@ -624,6 +627,14 @@ class RustBuild(object):
         filename = "rust-dev-nightly-" + self.build + tarball_suffix
         tarball = os.path.join(rustc_cache, filename)
         if not os.path.exists(tarball):
+            help_on_error = "error: failed to download llvm from ci"
+            help_on_error += "\nhelp: old builds get deleted after a certain time"
+            help_on_error += "\nhelp: if trying to compile an old commit of rustc,"
+            help_on_error += " disable `download-ci-llvm` in config.toml:"
+            help_on_error += "\n"
+            help_on_error += "\n[llvm]"
+            help_on_error += "\ndownload-ci-llvm = false"
+            help_on_error += "\n"
             get(
                 base,
                 "{}/{}".format(url, filename),
@@ -631,6 +642,7 @@ class RustBuild(object):
                 self.checksums_sha256,
                 verbose=self.verbose,
                 do_verify=False,
+                help_on_error=help_on_error,
             )
         unpack(tarball, tarball_suffix, self.llvm_root(),
                 match="rust-dev",
@@ -1221,9 +1233,9 @@ def bootstrap(help_triggered):
     build.verbose = args.verbose
     build.clean = args.clean
 
-    # Read from `RUST_BOOTSTRAP_CONFIG`, then `--config`, then fallback to `config.toml` (if it
+    # Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then fallback to `config.toml` (if it
     # exists).
-    toml_path = os.getenv('RUST_BOOTSTRAP_CONFIG') or args.config
+    toml_path = args.config or os.getenv('RUST_BOOTSTRAP_CONFIG')
     if not toml_path and os.path.exists('config.toml'):
         toml_path = 'config.toml'
 
index d40b924e0ff5fbde6ce732d9abd81c9a5fdb830e..6e39ea00f808c20ae34cf367a0b01f8b4b0cdc70 100644 (file)
@@ -3,6 +3,8 @@
 
 fn main() {
     println!("cargo:rerun-if-changed=build.rs");
+    println!("cargo:rerun-if-env-changed=RUSTC");
+    println!("cargo:rerun-if-env-changed=PATH");
     println!("cargo:rustc-env=BUILD_TRIPLE={}", env::var("HOST").unwrap());
 
     // This may not be a canonicalized path.
index 683cfc630e7715f6a8bfef208a3c5f8cd37f0833..d6f77fe6cd6d0c06e54ea744d7a7d746044a1dc9 100644 (file)
@@ -108,6 +108,7 @@ pub struct Config {
     pub llvm_polly: bool,
     pub llvm_clang: bool,
     pub llvm_from_ci: bool,
+    pub llvm_build_config: HashMap<String, String>,
 
     pub use_lld: bool,
     pub lld_enabled: bool,
@@ -477,6 +478,7 @@ struct Llvm {
         polly: Option<bool>,
         clang: Option<bool>,
         download_ci_llvm: Option<StringOrBool>,
+        build_config: Option<HashMap<String, String>>,
     }
 }
 
@@ -807,6 +809,7 @@ pub fn parse(args: &[String]) -> Config {
             config.llvm_allow_old_toolchain = llvm.allow_old_toolchain.unwrap_or(false);
             config.llvm_polly = llvm.polly.unwrap_or(false);
             config.llvm_clang = llvm.clang.unwrap_or(false);
+            config.llvm_build_config = llvm.build_config.clone().unwrap_or(Default::default());
             config.llvm_from_ci = match llvm.download_ci_llvm {
                 Some(StringOrBool::String(s)) => {
                     assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s);
@@ -876,6 +879,7 @@ pub fn parse(args: &[String]) -> Config {
                 check_ci_llvm!(llvm.allow_old_toolchain);
                 check_ci_llvm!(llvm.polly);
                 check_ci_llvm!(llvm.clang);
+                check_ci_llvm!(llvm.build_config);
                 check_ci_llvm!(llvm.plugins);
 
                 // CI-built LLVM can be either dynamic or static.
index 66b63cd1278c525f98649b45c697b41b79321989..029049d5434352cdf868e74abf4ab96c594446bf 100644 (file)
@@ -24,7 +24,6 @@
 use crate::tool::{self, Tool};
 use crate::util::{exe, is_dylib, timeit};
 use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
-use time::{self, Timespec};
 
 pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
     format!("{}-{}", component, builder.rust_package_vers())
@@ -422,33 +421,15 @@ fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
             let man_src = builder.src.join("src/doc/man");
             let man_dst = image.join("share/man/man1");
 
-            // Reproducible builds: If SOURCE_DATE_EPOCH is set, use that as the time.
-            let time = env::var("SOURCE_DATE_EPOCH")
-                .map(|timestamp| {
-                    let epoch = timestamp
-                        .parse()
-                        .map_err(|err| format!("could not parse SOURCE_DATE_EPOCH: {}", err))
-                        .unwrap();
-
-                    time::at(Timespec::new(epoch, 0))
-                })
-                .unwrap_or_else(|_| time::now());
-
-            let month_year = t!(time::strftime("%B %Y", &time));
             // don't use our `bootstrap::util::{copy, cp_r}`, because those try
             // to hardlink, and we don't want to edit the source templates
             for file_entry in builder.read_dir(&man_src) {
                 let page_src = file_entry.path();
                 let page_dst = man_dst.join(file_entry.file_name());
+                let src_text = t!(std::fs::read_to_string(&page_src));
+                let new_text = src_text.replace("<INSERT VERSION HERE>", &builder.version);
+                t!(std::fs::write(&page_dst, &new_text));
                 t!(fs::copy(&page_src, &page_dst));
-                // template in month/year and version number
-                builder.replace_in_file(
-                    &page_dst,
-                    &[
-                        ("<INSERT DATE HERE>", &month_year),
-                        ("<INSERT VERSION HERE>", &builder.version),
-                    ],
-                );
             }
 
             // Debugger scripts
@@ -753,6 +734,8 @@ fn filter_fn(exclude_dirs: &[&str], dir: &str, path: &Path) -> bool {
             "llvm-project\\llvm",
             "llvm-project/compiler-rt",
             "llvm-project\\compiler-rt",
+            "llvm-project/cmake",
+            "llvm-project\\cmake",
         ];
         if spath.contains("llvm-project")
             && !spath.ends_with("llvm-project")
@@ -1894,12 +1877,6 @@ fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) {
     } else {
         cmd.env("CFG_MINGW", "0").env("CFG_ABI", "MSVC");
     }
-
-    if target.contains("x86_64") {
-        cmd.env("CFG_PLATFORM", "x64");
-    } else {
-        cmd.env("CFG_PLATFORM", "x86");
-    }
 }
 
 /// Maybe add LLVM object files to the given destination lib-dir. Allows either static or dynamic linking.
index e5f84d417bf0b24f558889ec45cf5b0746677f7a..6f010cc9f8c18cd74334424c04a42ac5a7869500 100644 (file)
 use std::cell::{Cell, RefCell};
 use std::collections::{HashMap, HashSet};
 use std::env;
-use std::fs::{self, File, OpenOptions};
-use std::io::{Read, Seek, SeekFrom, Write};
+use std::fs::{self, File};
 use std::path::{Path, PathBuf};
 use std::process::{self, Command};
 use std::str;
@@ -527,7 +526,7 @@ fn dir_is_empty(dir: &Path) -> bool {
         // Try passing `--progress` to start, then run git again without if that fails.
         let update = |progress: bool| {
             let mut git = Command::new("git");
-            git.args(&["submodule", "update", "--init", "--recursive"]);
+            git.args(&["submodule", "update", "--init", "--recursive", "--depth=1"]);
             if progress {
                 git.arg("--progress");
             }
@@ -1335,23 +1334,6 @@ pub fn copy(&self, src: &Path, dst: &Path) {
         }
     }
 
-    /// Search-and-replaces within a file. (Not maximally efficiently: allocates a
-    /// new string for each replacement.)
-    pub fn replace_in_file(&self, path: &Path, replacements: &[(&str, &str)]) {
-        if self.config.dry_run {
-            return;
-        }
-        let mut contents = String::new();
-        let mut file = t!(OpenOptions::new().read(true).write(true).open(path));
-        t!(file.read_to_string(&mut contents));
-        for &(target, replacement) in replacements {
-            contents = contents.replace(target, replacement);
-        }
-        t!(file.seek(SeekFrom::Start(0)));
-        t!(file.set_len(0));
-        t!(file.write_all(contents.as_bytes()));
-    }
-
     /// Copies the `src` directory recursively to `dst`. Both are assumed to exist
     /// when this function is called.
     pub fn cp_r(&self, src: &Path, dst: &Path) {
index 4a754e6da12097293417c5f401728bf0c7e07ae2..f00875239040db8b67d298b0019bcf4939952c11 100644 (file)
@@ -31,6 +31,29 @@ pub struct Meta {
     root: String,
 }
 
+// Linker flags to pass to LLVM's CMake invocation.
+#[derive(Debug, Clone, Default)]
+struct LdFlags {
+    // CMAKE_EXE_LINKER_FLAGS
+    exe: OsString,
+    // CMAKE_SHARED_LINKER_FLAGS
+    shared: OsString,
+    // CMAKE_MODULE_LINKER_FLAGS
+    module: OsString,
+}
+
+impl LdFlags {
+    fn push_all(&mut self, s: impl AsRef<OsStr>) {
+        let s = s.as_ref();
+        self.exe.push(" ");
+        self.exe.push(s);
+        self.shared.push(" ");
+        self.shared.push(s);
+        self.module.push(" ");
+        self.module.push(s);
+    }
+}
+
 // 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
@@ -146,6 +169,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 
         // https://llvm.org/docs/CMake.html
         let mut cfg = cmake::Config::new(builder.src.join(root));
+        let mut ldflags = LdFlags::default();
 
         let profile = match (builder.config.llvm_optimize, builder.config.llvm_release_debuginfo) {
             (false, _) => "Debug",
@@ -238,18 +262,19 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             cfg.define("LLVM_LINK_LLVM_DYLIB", "ON");
         }
 
-        // For distribution we want the LLVM tools to be *statically* linked to libstdc++
-        if builder.config.llvm_tools_enabled {
-            if !target.contains("msvc") {
+        // For distribution we want the LLVM tools to be *statically* linked to libstdc++.
+        // We also do this if the user explicitly requested static libstdc++.
+        if builder.config.llvm_tools_enabled || builder.config.llvm_static_stdcpp {
+            if !target.contains("msvc") && !target.contains("netbsd") {
                 if target.contains("apple") {
-                    cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++");
+                    ldflags.push_all("-static-libstdc++");
                 } else {
-                    cfg.define("CMAKE_EXE_LINKER_FLAGS", "-Wl,-Bsymbolic -static-libstdc++");
+                    ldflags.push_all("-Wl,-Bsymbolic -static-libstdc++");
                 }
             }
         }
 
-        if !target.contains("freebsd") && target.starts_with("riscv") {
+        if target.starts_with("riscv") && !target.contains("freebsd") {
             // RISC-V GCC erroneously requires linking against
             // `libatomic` when using 1-byte and 2-byte C++
             // atomics but the LLVM build system check cannot
@@ -257,12 +282,8 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             // FreeBSD uses Clang as its system compiler and
             // provides no libatomic in its base system so does
             // not want this.
-            if !builder.config.llvm_tools_enabled {
-                cfg.define("CMAKE_EXE_LINKER_FLAGS", "-latomic");
-            } else {
-                cfg.define("CMAKE_EXE_LINKER_FLAGS", "-latomic -static-libstdc++");
-            }
-            cfg.define("CMAKE_SHARED_LINKER_FLAGS", "-latomic");
+            ldflags.exe.push(" -latomic");
+            ldflags.shared.push(" -latomic");
         }
 
         if target.contains("msvc") {
@@ -309,7 +330,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
 
         // Workaround for ppc32 lld limitation
         if target == "powerpc-unknown-freebsd" {
-            cfg.define("CMAKE_EXE_LINKER_FLAGS", "-fuse-ld=bfd");
+            ldflags.exe.push(" -fuse-ld=bfd");
         }
 
         // https://llvm.org/docs/HowToCrossCompileLLVM.html
@@ -351,7 +372,11 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
             cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES");
         }
 
-        configure_cmake(builder, target, &mut cfg, true);
+        configure_cmake(builder, target, &mut cfg, true, ldflags);
+
+        for (key, val) in &builder.config.llvm_build_config {
+            cfg.define(key, val);
+        }
 
         // FIXME: we don't actually need to build all LLVM tools and all LLVM
         //        libraries here, e.g., we just want a few components and a few
@@ -395,6 +420,7 @@ fn configure_cmake(
     target: TargetSelection,
     cfg: &mut cmake::Config,
     use_compiler_launcher: bool,
+    mut ldflags: LdFlags,
 ) {
     // Do not print installation messages for up-to-date files.
     // LLVM and LLD builds can produce a lot of those and hit CI limits on log size.
@@ -503,31 +529,38 @@ fn configure_cmake(
     }
 
     cfg.build_arg("-j").build_arg(builder.jobs().to_string());
-    let mut cflags = builder.cflags(target, GitRepo::Llvm).join(" ");
+    let mut cflags: OsString = builder.cflags(target, GitRepo::Llvm).join(" ").into();
     if let Some(ref s) = builder.config.llvm_cflags {
-        cflags.push_str(&format!(" {}", s));
+        cflags.push(" ");
+        cflags.push(s);
     }
     // Some compiler features used by LLVM (such as thread locals) will not work on a min version below iOS 10.
     if target.contains("apple-ios") {
         if target.contains("86-") {
-            cflags.push_str(" -miphonesimulator-version-min=10.0");
+            cflags.push(" -miphonesimulator-version-min=10.0");
         } else {
-            cflags.push_str(" -miphoneos-version-min=10.0");
+            cflags.push(" -miphoneos-version-min=10.0");
         }
     }
     if builder.config.llvm_clang_cl.is_some() {
-        cflags.push_str(&format!(" --target={}", target))
+        cflags.push(&format!(" --target={}", target));
     }
-    cfg.define("CMAKE_C_FLAGS", cflags);
-    let mut cxxflags = builder.cflags(target, GitRepo::Llvm).join(" ");
-    if builder.config.llvm_static_stdcpp && !target.contains("msvc") && !target.contains("netbsd") {
-        cxxflags.push_str(" -static-libstdc++");
+    if let Some(flags) = env::var_os("CFLAGS") {
+        cflags.push(" ");
+        cflags.push(flags);
     }
+    cfg.define("CMAKE_C_FLAGS", cflags);
+    let mut cxxflags: OsString = builder.cflags(target, GitRepo::Llvm).join(" ").into();
     if let Some(ref s) = builder.config.llvm_cxxflags {
-        cxxflags.push_str(&format!(" {}", s));
+        cxxflags.push(" ");
+        cxxflags.push(s);
     }
     if builder.config.llvm_clang_cl.is_some() {
-        cxxflags.push_str(&format!(" --target={}", target))
+        cxxflags.push(&format!(" --target={}", target));
+    }
+    if let Some(flags) = env::var_os("CXXFLAGS") {
+        cxxflags.push(" ");
+        cxxflags.push(flags);
     }
     cfg.define("CMAKE_CXX_FLAGS", cxxflags);
     if let Some(ar) = builder.ar(target) {
@@ -546,12 +579,18 @@ fn configure_cmake(
         }
     }
 
-    if let Some(ref s) = builder.config.llvm_ldflags {
-        cfg.define("CMAKE_SHARED_LINKER_FLAGS", s);
-        cfg.define("CMAKE_MODULE_LINKER_FLAGS", s);
-        cfg.define("CMAKE_EXE_LINKER_FLAGS", s);
+    if let Some(ref flags) = builder.config.llvm_ldflags {
+        ldflags.push_all(flags);
     }
 
+    if let Some(flags) = env::var_os("LDFLAGS") {
+        ldflags.push_all(&flags);
+    }
+
+    cfg.define("CMAKE_SHARED_LINKER_FLAGS", &ldflags.shared);
+    cfg.define("CMAKE_MODULE_LINKER_FLAGS", &ldflags.module);
+    cfg.define("CMAKE_EXE_LINKER_FLAGS", &ldflags.exe);
+
     if env::var_os("SCCACHE_ERROR_LOG").is_some() {
         cfg.env("RUSTC_LOG", "sccache=warn");
     }
@@ -594,7 +633,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
         t!(fs::create_dir_all(&out_dir));
 
         let mut cfg = cmake::Config::new(builder.src.join("src/llvm-project/lld"));
-        configure_cmake(builder, target, &mut cfg, true);
+        configure_cmake(builder, target, &mut cfg, true, LdFlags::default());
 
         // This is an awful, awful hack. Discovered when we migrated to using
         // clang-cl to compile LLVM/LLD it turns out that LLD, when built out of
@@ -784,7 +823,7 @@ fn run(self, builder: &Builder<'_>) -> Self::Output {
         // Unfortunately sccache currently lacks support to build them successfully.
         // Disable compiler launcher on Darwin targets to avoid potential issues.
         let use_compiler_launcher = !self.target.contains("apple-darwin");
-        configure_cmake(builder, self.target, &mut cfg, use_compiler_launcher);
+        configure_cmake(builder, self.target, &mut cfg, use_compiler_launcher, LdFlags::default());
 
         t!(fs::create_dir_all(&out_dir));
         cfg.out_dir(out_dir);
index 5bc0a505bf6954602f44fb94b872126e09c15467..9a9ef0b76955d503127bc64bd7b6be057b575be7 100644 (file)
@@ -1,7 +1,9 @@
 use crate::TargetSelection;
 use crate::{t, VERSION};
+use std::env::consts::EXE_SUFFIX;
 use std::fmt::Write as _;
-use std::path::{Path, PathBuf};
+use std::fs::File;
+use std::path::{Path, PathBuf, MAIN_SEPARATOR};
 use std::process::Command;
 use std::str::FromStr;
 use std::{
@@ -109,7 +111,8 @@ pub fn setup(src_path: &Path, profile: Profile) {
     println!("`x.py` will now use the configuration at {}", include_path.display());
 
     let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
-    let stage_path = ["build", build.rustc_target_arg(), "stage1"].join("/");
+    let stage_path =
+        ["build", build.rustc_target_arg(), "stage1"].join(&MAIN_SEPARATOR.to_string());
 
     println!();
 
@@ -171,6 +174,13 @@ fn attempt_toolchain_link(stage_path: &str) {
         return;
     }
 
+    if !ensure_stage1_toolchain_placeholder_exists(stage_path) {
+        println!(
+            "Failed to create a template for stage 1 toolchain or confirm that it already exists"
+        );
+        return;
+    }
+
     if try_link_toolchain(&stage_path[..]) {
         println!(
             "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"
@@ -219,6 +229,33 @@ fn try_link_toolchain(stage_path: &str) -> bool {
         .map_or(false, |output| output.status.success())
 }
 
+fn ensure_stage1_toolchain_placeholder_exists(stage_path: &str) -> bool {
+    let pathbuf = PathBuf::from(stage_path);
+
+    if fs::create_dir_all(pathbuf.join("lib")).is_err() {
+        return false;
+    };
+
+    let pathbuf = pathbuf.join("bin");
+    if fs::create_dir_all(&pathbuf).is_err() {
+        return false;
+    };
+
+    let pathbuf = pathbuf.join(format!("rustc{}", EXE_SUFFIX));
+
+    if pathbuf.exists() {
+        return true;
+    }
+
+    // Take care not to overwrite the file
+    let result = File::options().append(true).create(true).open(&pathbuf);
+    if result.is_err() {
+        return false;
+    }
+
+    return true;
+}
+
 // Used to get the path for `Subcommand::Setup`
 pub fn interactive_path() -> io::Result<Profile> {
     fn abbrev_all() -> impl Iterator<Item = ((String, String), Profile)> {
@@ -271,9 +308,9 @@ fn install_git_hook_maybe(src_path: &Path) -> io::Result<()> {
     let mut input = String::new();
     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` on each commit
-to ensure your code is up to par. If you decide later that this behavior is undesirable,
-simply delete the `pre-commit` file from .git/hooks."
+If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` before
+pushing your code to ensure your code is up to par. If you decide later that this behavior is
+undesirable, simply delete the `pre-push` file from .git/hooks."
     );
 
     let should_install = loop {
@@ -293,21 +330,21 @@ fn install_git_hook_maybe(src_path: &Path) -> io::Result<()> {
     };
 
     if should_install {
-        let src = src_path.join("src").join("etc").join("pre-commit.sh");
+        let src = src_path.join("src").join("etc").join("pre-push.sh");
         let git = t!(Command::new("git").args(&["rev-parse", "--git-common-dir"]).output().map(
             |output| {
                 assert!(output.status.success(), "failed to run `git`");
                 PathBuf::from(t!(String::from_utf8(output.stdout)).trim())
             }
         ));
-        let dst = git.join("hooks").join("pre-commit");
+        let dst = git.join("hooks").join("pre-push");
         match fs::hard_link(src, &dst) {
             Err(e) => println!(
                 "error: could not create hook {}: do you already have the git hook installed?\n{}",
                 dst.display(),
                 e
             ),
-            Ok(_) => println!("Linked `src/etc/pre-commit.sh` to `.git/hooks/pre-commit`"),
+            Ok(_) => println!("Linked `src/etc/pre-commit.sh` to `.git/hooks/pre-push`"),
         };
     } else {
         println!("Ok, skipping installation!");
index 267c3964d0d692d2e8e975fa5868943a547c00fc..adfd895ead04e8b0e14f4d97be6382675036710d 100644 (file)
@@ -108,37 +108,37 @@ elif sys.platform == 'darwin':
     from ctypes import *
     libc = cdll.LoadLibrary('/usr/lib/libc.dylib')
 
-    PROESSOR_CPU_LOAD_INFO = c_int(2)
+    class host_cpu_load_info_data_t(Structure):
+        _fields_ = [("cpu_ticks", c_uint * 4)]
+
+    host_statistics = libc.host_statistics
+    host_statistics.argtypes = [
+        c_uint,
+        c_int,
+        POINTER(host_cpu_load_info_data_t),
+        POINTER(c_int)
+    ]
+    host_statistics.restype = c_int
+
     CPU_STATE_USER = 0
     CPU_STATE_SYSTEM = 1
     CPU_STATE_IDLE = 2
     CPU_STATE_NICE = 3
-    c_int_p = POINTER(c_int)
-
     class State:
         def __init__(self):
-            num_cpus_u = c_uint(0)
-            cpu_info = c_int_p()
-            cpu_info_cnt = c_int(0)
-            err = libc.host_processor_info(
+            stats = host_cpu_load_info_data_t()
+            count = c_int(4) # HOST_CPU_LOAD_INFO_COUNT
+            err = libc.host_statistics(
                 libc.mach_host_self(),
-                PROESSOR_CPU_LOAD_INFO,
-                byref(num_cpus_u),
-                byref(cpu_info),
-                byref(cpu_info_cnt),
+                c_int(3), # HOST_CPU_LOAD_INFO
+                byref(stats),
+                byref(count),
             )
             assert err == 0
-            self.user = 0
-            self.system = 0
-            self.idle = 0
-            self.nice = 0
-            cur = 0
-            while cur < cpu_info_cnt.value:
-                self.user += cpu_info[cur + CPU_STATE_USER]
-                self.system += cpu_info[cur + CPU_STATE_SYSTEM]
-                self.idle += cpu_info[cur + CPU_STATE_IDLE]
-                self.nice += cpu_info[cur + CPU_STATE_NICE]
-                cur += num_cpus_u.value
+            self.system = stats.cpu_ticks[CPU_STATE_SYSTEM]
+            self.user = stats.cpu_ticks[CPU_STATE_USER]
+            self.idle = stats.cpu_ticks[CPU_STATE_IDLE]
+            self.nice = stats.cpu_ticks[CPU_STATE_NICE]
 
         def idle_since(self, prev):
             user = self.user - prev.user
index ee4fd759b469b60ddb82b9ae29eedacf3933117d..79c2c1d93d7187bd9f5e1c9b7c32ce09ed856276 100644 (file)
@@ -1,17 +1,4 @@
 FROM ubuntu:20.04
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        curl \
-        ca-certificates
-WORKDIR /tmp
-RUN curl -f https://curl.se/ca/cacert.pem -o cacert.pem
-
-FROM ubuntu:16.04
-
-# The ca-certificates in ubuntu-16 is too old, so update the certificates
-# with something more recent.
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
index b11a1d3feb2eefa5f44efd2a915f26d553b71f4c..dd1c83b41325209a537c06f4358b432192b9a373 100644 (file)
@@ -1,17 +1,4 @@
 FROM ubuntu:20.04
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        curl \
-        ca-certificates
-WORKDIR /tmp
-RUN curl -f https://curl.se/ca/cacert.pem -o cacert.pem
-
-FROM ubuntu:16.04
-
-# The ca-certificates in ubuntu-16 is too old, so update the certificates
-# with something more recent.
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
index 55ca23b293d5e2336b801b15991e71097f30d84c..32e3bc22ad795cf5619ed75f5771b9fdf933d16f 100644 (file)
@@ -1,17 +1,4 @@
 FROM ubuntu:20.04
-RUN apt-get update && \
-    apt-get install -y --no-install-recommends \
-        curl \
-        ca-certificates
-WORKDIR /tmp
-RUN curl -f https://curl.se/ca/cacert.pem -o cacert.pem
-
-FROM ubuntu:16.04
-
-# The ca-certificates in ubuntu-16 is too old, so update the certificates
-# with something more recent.
-COPY --from=0 /tmp/cacert.pem /tmp/cacert.pem
-ENV CURL_CA_BUNDLE /tmp/cacert.pem
 
 COPY scripts/cross-apt-packages.sh /scripts/
 RUN sh /scripts/cross-apt-packages.sh
index ef49904b53d6a62e9806fbc8ee2a0ba6514817d9..51645a81853fdf03cf6fa8e89c3bb2f9b8e7202c 100644 (file)
@@ -1,6 +1,6 @@
-FROM ubuntu:16.04
+FROM ubuntu:20.04
 
-RUN apt-get update && apt-get install -y --no-install-recommends \
+RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
   g++ \
   make \
   ninja-build \
index c547e12f5b6cec21a683c8af94cf23b52c671186..f1c42b248f4bd236d5781b6ba969d407abbfa2ca 100644 (file)
@@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
 # https://github.com/puppeteer/puppeteer/issues/375
 #
 # We also specify the version in case we need to update it to go around cache limitations.
-RUN npm install -g browser-ui-test@0.5.8 --unsafe-perm=true
+RUN npm install -g browser-ui-test@0.7.2 --unsafe-perm=true
 
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
index 1a1472ea861f94e10a3fe8894bfd8a00e1ec9836..8abf4244a38dd8c79c6525fdcdc671b3909f9c98 100644 (file)
@@ -486,9 +486,9 @@ jobs:
               NO_OVERFLOW_CHECKS: 1
             <<: *job-macos-xl
 
-          - name: x86_64-apple
-            env:
-              SCRIPT: ./x.py --stage 2 test
+          - name: x86_64-apple-1
+            env: &env-x86_64-apple-tests
+              SCRIPT: ./x.py --stage 2 test --exclude src/test/ui --exclude src/test/rustdoc --exclude src/test/run-make-fulldeps
               RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.8
@@ -498,6 +498,12 @@ jobs:
               NO_OVERFLOW_CHECKS: 1
             <<: *job-macos-xl
 
+          - name: x86_64-apple-2
+            env:
+              SCRIPT: ./x.py --stage 2 test src/test/ui src/test/rustdoc src/test/run-make-fulldeps
+              <<: *env-x86_64-apple-tests
+            <<: *job-macos-xl
+
           # This target only needs to support 11.0 and up as nothing else supports the hardware
           - name: dist-aarch64-apple
             env:
index 29ef13a60fbc431d08c4ea71a81d71b149cbf45b..eaf92b033a1a84be842a7e4cce06730689c7d6cf 100755 (executable)
@@ -14,10 +14,10 @@ python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
     --llvm-profile-generate
 
 # Profile libcore compilation in opt-level=0 and opt-level=3
-RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
-    --crate-type=lib ../library/core/src/lib.rs
-RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
-    --crate-type=lib -Copt-level=3 ../library/core/src/lib.rs
+RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc \
+    --edition=2021 --crate-type=lib ../library/core/src/lib.rs
+RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc \
+    --edition=2021 --crate-type=lib -Copt-level=3 ../library/core/src/lib.rs
 
 # Merge the profile data we gathered for LLVM
 # Note that this uses the profdata from the clang we used to build LLVM,
@@ -37,10 +37,10 @@ python3 ../x.py build --target=$PGO_HOST --host=$PGO_HOST \
     --rust-profile-generate=/tmp/rustc-pgo
 
 # Profile libcore compilation in opt-level=0 and opt-level=3
-RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
-    --crate-type=lib ../library/core/src/lib.rs
-RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc --edition=2018 \
-    --crate-type=lib -Copt-level=3 ../library/core/src/lib.rs
+RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc \
+    --edition=2021 --crate-type=lib ../library/core/src/lib.rs
+RUSTC_BOOTSTRAP=1 ./build/$PGO_HOST/stage2/bin/rustc \
+    --edition=2021 --crate-type=lib -Copt-level=3 ../library/core/src/lib.rs
 
 cp -r /tmp/rustc-perf ./
 chown -R $(whoami): ./rustc-perf
index 98904efaa4fc968db8ff59cf2744d9f7ed158166..67b768c0b660a069a45f0e5d8ae2f679df1022ab 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 98904efaa4fc968db8ff59cf2744d9f7ed158166
+Subproject commit 67b768c0b660a069a45f0e5d8ae2f679df1022ab
index 3788e3c864e820ed22556caccb32953fdd651c2a..4e7170806d47b0db97261bef8df9112375f604e5 100644 (file)
@@ -1,4 +1,4 @@
-.TH RUSTC "1" "<INSERT DATE HERE>" "rustc <INSERT VERSION HERE>" "User Commands"
+.TH RUSTC "1" "April 2019" "rustc <INSERT VERSION HERE>" "User Commands"
 .SH NAME
 rustc \- The Rust compiler
 .SH SYNOPSIS
index d7f78e8f6f4de7ddf10e6547932ada586e2a319b..e6185347972827c90427f88d8460a4e0e20416b8 100644 (file)
@@ -1,4 +1,4 @@
-.TH RUSTDOC "1" "<INSERT DATE HERE>" "rustdoc <INSERT VERSION HERE>" "User Commands"
+.TH RUSTDOC "1" "July 2018" "rustdoc <INSERT VERSION HERE>" "User Commands"
 .SH NAME
 rustdoc \- generate documentation from Rust source code
 .SH SYNOPSIS
index 9493715a6280a1f74be759c7e1ef9999b5d13e6f..90993eeac93dbf9388992de92965f99cf6f29a03 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9493715a6280a1f74be759c7e1ef9999b5d13e6f
+Subproject commit 90993eeac93dbf9388992de92965f99cf6f29a03
index 411c2f0d5cebf48453ae2d136ad0c5e611d39aec..70fc73a6b908e08e66aa0306856c5211312f6c05 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 411c2f0d5cebf48453ae2d136ad0c5e611d39aec
+Subproject commit 70fc73a6b908e08e66aa0306856c5211312f6c05
index 8763adb62c712df69b1d39ea3e692b6d696cc4d9..62f58394ba7b203f55ac35ddcc4c0b79578f5706 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8763adb62c712df69b1d39ea3e692b6d696cc4d9
+Subproject commit 62f58394ba7b203f55ac35ddcc4c0b79578f5706
index 146408900ab2472a21e9e44ca2124ea7a2c2509a..aecd892ce8b3b0f39b9d47bd144b37c1a441d338 100644 (file)
@@ -15,7 +15,9 @@
 - [Platform Support](platform-support.md)
     - [Template for target-specific documentation](platform-support/TEMPLATE.md)
     - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
+    - [armv7-unknown-linux-uclibceabi](platform-support/armv7-unknown-linux-uclibceabi.md)
     - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
+    - [aarch64-unknown-none-hermitkernel](platform-support/aarch64-unknown-none-hermitkernel.md)
     - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
     - [*-unknown-openbsd](platform-support/openbsd.md)
     - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
@@ -26,6 +28,7 @@
     - [Custom Targets](targets/custom.md)
     - [Known Issues](targets/known-issues.md)
 - [Profile-guided Optimization](profile-guided-optimization.md)
+- [Instrumentation-based Code Coverage](instrument-coverage.md)
 - [Linker-plugin based LTO](linker-plugin-lto.md)
 - [Exploit Mitigations](exploit-mitigations.md)
 - [Contributing to `rustc`](contributing.md)
index 0201b88417a8b8f2ef4a3c0cfcf4435c36a77472..3b0cf92bbb763d1450443947a5792ea71b83f02e 100644 (file)
@@ -177,6 +177,15 @@ The default depends on the [opt-level](#opt-level):
 | s         | 75 |
 | z         | 25 |
 
+## instrument-coverage
+
+This option enables instrumentation-based code coverage support. See the
+chapter on [instrumentation-based code coverage] for more information.
+
+Note that while the `-C instrument-coverage` option is stable, the profile data
+format produced by the resulting instrumentation may change, and may not work
+with coverage tools other than those built and shipped with the compiler.
+
 ## link-arg
 
 This flag lets you append a single extra argument to the linker invocation.
@@ -597,5 +606,6 @@ effective only for x86 targets.
 
 [option-emit]: ../command-line-arguments.md#option-emit
 [option-o-optimize]: ../command-line-arguments.md#option-o-optimize
+[instrumentation-based code coverage]: ../instrument-coverage.md
 [profile-guided optimization]: ../profile-guided-optimization.md
 [option-g-debug]: ../command-line-arguments.md#option-g-debug
diff --git a/src/doc/rustc/src/instrument-coverage.md b/src/doc/rustc/src/instrument-coverage.md
new file mode 100644 (file)
index 0000000..b949891
--- /dev/null
@@ -0,0 +1,330 @@
+# `instrument-coverage`
+
+## Introduction
+
+The Rust compiler includes two code coverage implementations:
+
+-   A GCC-compatible, gcov-based coverage implementation, enabled with `-Z profile`, which derives coverage data based on DebugInfo.
+-   A source-based code coverage implementation, enabled with `-C instrument-coverage`, which uses LLVM's native, efficient coverage instrumentation to generate very precise coverage data.
+
+This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-C instrument-coverage` compiler flag.
+
+## How it works
+
+When `-C instrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by:
+
+-   Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed.
+-   Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 5_, if compiling with LLVM 12, or _Version 6_, if compiling with LLVM 13 or higher), to define the code regions (start and end positions in the source code) being counted.
+
+When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats.
+
+[`llvm.instrprof.increment`]: https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic
+[llvm code coverage mapping format]: https://llvm.org/docs/CoverageMappingFormat.html
+
+> **Note**: `-C instrument-coverage` also automatically enables `-C symbol-mangling-version=v0` (tracking issue [#60705]). The `v0` symbol mangler is strongly recommended. The `v0` demangler can be overridden by explicitly adding `-Z unstable-options -C symbol-mangling-version=legacy`.
+
+[#60705]: https://github.com/rust-lang/rust/issues/60705
+
+## Enable coverage profiling in the Rust compiler
+
+Rust's source-based code coverage requires the Rust "profiler runtime". Without it, compiling with `-C instrument-coverage` generates an error that the profiler runtime is missing.
+
+The Rust `nightly` distribution channel includes the profiler runtime, by default.
+
+> **Important**: If you are building the Rust compiler from the source distribution, the profiler runtime is _not_ enabled in the default `config.toml.example`. Edit your `config.toml` file and ensure the `profiler` feature is set it to `true` (either under the `[build]` section, or under the settings for an individual `[target.<triple>]`):
+>
+> ```toml
+> # Build the profiler runtime (required when compiling with options that depend
+> # on this runtime, such as `-C profile-generate` or `-C instrument-coverage`).
+> profiler = true
+> ```
+
+### Building the demangler
+
+LLVM coverage reporting tools generate results that can include function names and other symbol references, and the raw coverage results report symbols using the compiler's "mangled" version of the symbol names, which can be difficult to interpret. To work around this issue, LLVM coverage tools also support a user-specified symbol name demangler.
+
+One option for a Rust demangler is [`rustfilt`], which can be installed with:
+
+```shell
+cargo install rustfilt
+```
+
+Another option, if you are building from the Rust compiler source distribution, is to use the `rust-demangler` tool included in the Rust source distribution, which can be built with:
+
+```shell
+$ ./x.py build rust-demangler
+```
+
+[`rustfilt`]: https://crates.io/crates/rustfilt
+
+## Compiling with coverage enabled
+
+Set the `-C instrument-coverage` compiler flag in order to enable LLVM source-based code coverage profiling.
+
+The default option generates coverage for all functions, including unused (never called) functions and generics. The compiler flag supports an optional value to tailor this behavior. (See [`-C instrument-coverage=<options>`](#-c-instrument-coverageoptions), below.)
+
+With `cargo`, you can instrument your program binary _and_ dependencies at the same time.
+
+For example (if your project's Cargo.toml builds a binary by default):
+
+```shell
+$ cd your-project
+$ cargo clean
+$ RUSTFLAGS="-C instrument-coverage" cargo build
+```
+
+If `cargo` is not configured to use your `profiler`-enabled version of `rustc`, set the path explicitly via the `RUSTC` environment variable. Here is another example, using a `stage1` build of `rustc` to compile an `example` binary (from the [`json5format`] crate):
+
+```shell
+$ RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \
+    RUSTFLAGS="-C instrument-coverage" \
+    cargo build --example formatjson5
+```
+
+> **Note**: that some compiler options, combined with `-C instrument-coverage`, can produce LLVM IR and/or linked binaries that are incompatible with LLVM coverage maps. For example, coverage requires references to actual functions in LLVM IR. If any covered function is optimized out, the coverage tools may not be able to process the coverage results. If you need to pass additional options, with coverage enabled, test them early, to confirm you will get the coverage results you expect.
+
+## Running the instrumented binary to generate raw coverage profiling data
+
+In the previous example, `cargo` generated the coverage-instrumented binary `formatjson5`:
+
+```shell
+$ echo "{some: 'thing'}" | target/debug/examples/formatjson5 -
+```
+
+```json5
+{
+    some: "thing",
+}
+```
+
+After running this program, a new file, `default.profraw`, should be in the current working directory. It's often preferable to set a specific file name or path. You can change the output file using the environment variable `LLVM_PROFILE_FILE`:
+
+```shell
+$ echo "{some: 'thing'}" \
+    | LLVM_PROFILE_FILE="formatjson5.profraw" target/debug/examples/formatjson5 -
+...
+$ ls formatjson5.profraw
+formatjson5.profraw
+```
+
+If `LLVM_PROFILE_FILE` contains a path to a non-existent directory, the missing directory structure will be created. Additionally, the following special pattern strings are rewritten:
+
+-   `%p` - The process ID.
+-   `%h` - The hostname of the machine running the program.
+-   `%t` - The value of the TMPDIR environment variable.
+-   `%Nm` - the instrumented binary’s signature: The runtime creates a pool of N raw profiles, used for on-line profile merging. The runtime takes care of selecting a raw profile from the pool, locking it, and updating it before the program exits. `N` must be between `1` and `9`, and defaults to `1` if omitted (with simply `%m`).
+-   `%c` - Does not add anything to the filename, but enables a mode (on some platforms, including Darwin) in which profile counter updates are continuously synced to a file. This means that if the instrumented program crashes, or is killed by a signal, perfect coverage information can still be recovered.
+
+## Installing LLVM coverage tools
+
+LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 12 or higher, and processing the *raw* data may require exactly the LLVM version used by the compiler. (`llvm-cov --version` typically shows the tool's LLVM version number, and `rustc --verbose --version` shows the version of LLVM used by the Rust compiler.)
+
+-   You can install compatible versions of these tools via the `rustup` component `llvm-tools-preview`. This component is the recommended path, though the specific tools available and their interface is not currently subject to Rust's usual stability guarantees. In this case, you may also find `cargo-binutils` useful as a wrapper around these tools.
+-   You can install a compatible version of LLVM tools from your operating system distribution, or from your distribution of LLVM.
+-   If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`.
+
+The examples in this document show how to use the llvm tools directly.
+
+## Creating coverage reports
+
+Raw profiles have to be indexed before they can be used to generate coverage reports. This is done using [`llvm-profdata merge`], which can combine multiple raw profiles and index them at the same time:
+
+```shell
+$ llvm-profdata merge -sparse formatjson5.profraw -o formatjson5.profdata
+```
+
+Finally, the `.profdata` file is used, in combination with the coverage map (from the program binary) to generate coverage reports using [`llvm-cov report`], for a coverage summaries; and [`llvm-cov show`], to see detailed coverage of lines and regions (character ranges) overlaid on the original source code.
+
+These commands have several display and filtering options. For example:
+
+```shell
+$ llvm-cov show -Xdemangler=rustfilt target/debug/examples/formatjson5 \
+    -instr-profile=formatjson5.profdata \
+    -show-line-counts-or-regions \
+    -show-instantiations \
+    -name=add_quoted_string
+```
+
+<img alt="Screenshot of sample `llvm-cov show` result, for function add_quoted_string" src="img/llvm-cov-show-01.png" class="center"/>
+<br/>
+<br/>
+
+Some of the more notable options in this example include:
+
+-   `--Xdemangler=rustfilt` - the command name or path used to demangle Rust symbols (`rustfilt` in the example, but this could also be a path to the `rust-demangler` tool)
+-   `target/debug/examples/formatjson5` - the instrumented binary (from which to extract the coverage map)
+-   `--instr-profile=<path-to-file>.profdata` - the location of the `.profdata` file created by `llvm-profdata merge` (from the `.profraw` file generated by the instrumented binary)
+-   `--name=<exact-function-name>` - to show coverage for a specific function (or, consider using another filter option, such as `--name-regex=<pattern>`)
+
+[`llvm-profdata merge`]: https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge
+[`llvm-cov report`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report
+[`llvm-cov show`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-show
+
+> **Note**: Coverage can also be disabled on an individual function by annotating the function with the [`no_coverage` attribute] (which requires the feature flag `#![feature(no_coverage)]`).
+
+[`no_coverage` attribute]: ../unstable-book/language-features/no-coverage.html
+
+## Interpreting reports
+
+There are four statistics tracked in a coverage summary:
+
+-   Function coverage is the percentage of functions that have been executed at least once. A function is considered to be executed if any of its instantiations are executed.
+-   Instantiation coverage is the percentage of function instantiations that have been executed at least once. Generic functions and functions generated from macros are two kinds of functions that may have multiple instantiations.
+-   Line coverage is the percentage of code lines that have been executed at least once. Only executable lines within function bodies are considered to be code lines.
+-   Region coverage is the percentage of code regions that have been executed at least once. A code region may span multiple lines: for example, in a large function body with no control flow. In other cases, a single line can contain multiple code regions: `return x || (y && z)` has countable code regions for `x` (which may resolve the expression, if `x` is `true`), `|| (y && z)` (executed only if `x` was `false`), and `return` (executed in either situation).
+
+Of these four statistics, function coverage is usually the least granular while region coverage is the most granular. The project-wide totals for each statistic are listed in the summary.
+
+## Test coverage
+
+A typical use case for coverage analysis is test coverage. Rust's source-based coverage tools can both measure your tests' code coverage as percentage, and pinpoint functions and branches not tested.
+
+The following example (using the [`json5format`] crate, for demonstration purposes) show how to generate and analyze coverage results for all tests in a crate.
+
+Since `cargo test` both builds and runs the tests, we set both the additional `RUSTFLAGS`, to add the `-C instrument-coverage` flag, and `LLVM_PROFILE_FILE`, to set a custom filename for the raw profiling data generated during the test runs. Since there may be more than one test binary, apply `%m` in the filename pattern. This generates unique names for each test binary. (Otherwise, each executed test binary would overwrite the coverage results from the previous binary.)
+
+```shell
+$ RUSTFLAGS="-C instrument-coverage" \
+    LLVM_PROFILE_FILE="json5format-%m.profraw" \
+    cargo test --tests
+```
+
+Make note of the test binary file paths, displayed after the word "`Running`" in the test output:
+
+```text
+   ...
+   Compiling json5format v0.1.3 ($HOME/json5format)
+    Finished test [unoptimized + debuginfo] target(s) in 14.60s
+
+     Running target/debug/deps/json5format-fececd4653271682
+running 25 tests
+...
+test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+
+     Running target/debug/deps/lib-30768f9c53506dc5
+running 31 tests
+...
+test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+```
+
+You should have one or more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them:
+
+```shell
+$ llvm-profdata merge -sparse json5format-*.profraw -o json5format.profdata
+```
+
+Then run the `cov` tool, with the `profdata` file and all test binaries:
+
+```shell
+$ llvm-cov report \
+    --use-color --ignore-filename-regex='/.cargo/registry' \
+    --instr-profile=json5format.profdata \
+    --object target/debug/deps/lib-30768f9c53506dc5 \
+    --object target/debug/deps/json5format-fececd4653271682
+$ llvm-cov show \
+    --use-color --ignore-filename-regex='/.cargo/registry' \
+    --instr-profile=json5format.profdata \
+    --object target/debug/deps/lib-30768f9c53506dc5 \
+    --object target/debug/deps/json5format-fececd4653271682 \
+    --show-instantiations --show-line-counts-or-regions \
+    --Xdemangler=rustfilt | less -R
+```
+
+> **Note**: The command line option `--ignore-filename-regex=/.cargo/registry`, which excludes the sources for dependencies from the coverage results.\_
+
+### Tips for listing the binaries automatically
+
+For `bash` users, one suggested way to automatically complete the `cov` command with the list of binaries is with a command like:
+
+```bash
+$ llvm-cov report \
+    $( \
+      for file in \
+        $( \
+          RUSTFLAGS="-C instrument-coverage" \
+            cargo test --tests --no-run --message-format=json \
+              | jq -r "select(.profile.test == true) | .filenames[]" \
+              | grep -v dSYM - \
+        ); \
+      do \
+        printf "%s %s " -object $file; \
+      done \
+    ) \
+  --instr-profile=json5format.profdata --summary-only # and/or other options
+```
+
+Adding `--no-run --message-format=json` to the _same_ `cargo test` command used to run
+the tests (including the same environment variables and flags) generates output in a JSON
+format that `jq` can easily query.
+
+The `printf` command takes this list and generates the `--object <binary>` arguments
+for each listed test binary.
+
+### Including doc tests
+
+The previous examples run `cargo test` with `--tests`, which excludes doc tests.[^79417]
+
+To include doc tests in the coverage results, drop the `--tests` flag, and apply the
+`-C instrument-coverage` flag, and some doc-test-specific options in the
+`RUSTDOCFLAGS` environment variable. (The `llvm-profdata` command does not change.)
+
+```bash
+$ RUSTFLAGS="-C instrument-coverage" \
+  RUSTDOCFLAGS="-C instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \
+  LLVM_PROFILE_FILE="json5format-%m.profraw" \
+    cargo test
+$ llvm-profdata merge -sparse json5format-*.profraw -o json5format.profdata
+```
+
+The `-Z unstable-options --persist-doctests` flag is required, to save the test binaries
+(with their coverage maps) for `llvm-cov`.
+
+```bash
+$ llvm-cov report \
+    $( \
+      for file in \
+        $( \
+          RUSTFLAGS="-C instrument-coverage" \
+          RUSTDOCFLAGS="-C instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \
+            cargo test --no-run --message-format=json \
+              | jq -r "select(.profile.test == true) | .filenames[]" \
+              | grep -v dSYM - \
+        ) \
+        target/debug/doctestbins/*/rust_out; \
+      do \
+        [[ -x $file ]] && printf "%s %s " -object $file; \
+      done \
+    ) \
+  --instr-profile=json5format.profdata --summary-only # and/or other options
+```
+
+> **Note**: The differences in this `llvm-cov` invocation, compared with the
+> version without doc tests, include:
+
+-   The `cargo test ... --no-run` command is updated with the same environment variables
+    and flags used to _build_ the tests, _including_ the doc tests. (`LLVM_PROFILE_FILE`
+    is only used when _running_ the tests.)
+-   The file glob pattern `target/debug/doctestbins/*/rust_out` adds the `rust_out`
+    binaries generated for doc tests (note, however, that some `rust_out` files may not
+    be executable binaries).
+-   `[[ -x $file ]] &&` filters the files passed on to the `printf`, to include only
+    executable binaries.
+
+[^79417]:
+    There is ongoing work to resolve a known issue
+    [(#79417)](https://github.com/rust-lang/rust/issues/79417) that doc test coverage
+    generates incorrect source line numbers in `llvm-cov show` results.
+
+## `-C instrument-coverage=<options>`
+
+-   `-C instrument-coverage=all`: Instrument all functions, including unused functions and unused generics. (This is the same as `-C instrument-coverage`, with no value.)
+-   `-C instrument-coverage=off`: Do not instrument any functions. (This is the same as simply not including the `-C instrument-coverage` option.)
+-   `-Zunstable-options -C instrument-coverage=except-unused-generics`: Instrument all functions except unused generics.
+-   `-Zunstable-options -C instrument-coverage=except-unused-functions`: Instrument only used (called) functions and instantiated generic functions.
+
+## Other references
+
+Rust's implementation and workflow for source-based code coverage is based on the same library and tools used to implement [source-based code coverage in Clang]. (This document is partially based on the Clang guide.)
+
+[source-based code coverage in clang]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
+[`json5format`]: https://crates.io/crates/json5format
index a31e08f0d12a6f8c225010004fd2b4a77b9c544e..d4a5f0e5a98c2541f5aa41aff583d9f92c8c78a8 100644 (file)
@@ -204,7 +204,8 @@ target | std | host | notes
 `aarch64-apple-tvos` | * |  | ARM64 tvOS
 [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ |  | ARM64 SOLID with TOPPERS/ASP3
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
-`aarch64-unknown-hermit` | ? |  |
+`aarch64-unknown-hermit` | ✓ |  | ARM64 HermitCore
+[`aarch64-unknown-none-hermitkernel`](platform-support/aarch64-unknown-none-hermitkernel.md) | * |  | ARM64 HermitCore kernel
 `aarch64-unknown-uefi` | * |  | ARM64 UEFI
 `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
 `aarch64-unknown-netbsd` | ✓ | ✓ |
@@ -220,7 +221,8 @@ target | std | host | notes
 `armv6-unknown-netbsd-eabihf` | ? |  |
 `armv6k-nintendo-3ds` | * |  | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)
 `armv7-apple-ios` | ✓ |  | ARMv7 iOS, Cortex-a8
-[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7 Linux uClibc
+[`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
 `armv7-unknown-netbsd-eabihf` | ✓ | ✓ |
 `armv7-wrs-vxworks-eabihf` | ? |  |
@@ -244,6 +246,7 @@ target | std | host | notes
 `i686-wrs-vxworks` | ? |  |
 `m68k-unknown-linux-gnu` | ? |  | Motorola 680x0 Linux
 `mips-unknown-linux-uclibc` | ✓ |  | MIPS Linux with uClibc
+`mips64-openwrt-linux-musl` | ? |  | MIPS64 for OpenWrt Linux MUSL
 `mipsel-sony-psp` | * |  | MIPS (LE) Sony PlayStation Portable (PSP)
 `mipsel-unknown-linux-uclibc` | ✓ |  | MIPS (LE) Linux with uClibc
 `mipsel-unknown-none` | * |  | Bare MIPS (LE) softfloat
@@ -284,10 +287,10 @@ target | std | host | notes
 `x86_64-sun-solaris` | ? |  | Deprecated target for 64-bit Solaris 10/11, illumos
 `x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
 `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
-`x86_64-unknown-hermit` | ? |  |
+`x86_64-unknown-hermit` | ✓ |  | HermitCore
 `x86_64-unknown-l4re-uclibc` | ? |  |
 [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * |  | Freestanding/bare-metal x86_64, softfloat
-`x86_64-unknown-none-hermitkernel` | ? |  | HermitCore kernel
+`x86_64-unknown-none-hermitkernel` | * |  | HermitCore kernel
 `x86_64-unknown-none-linuxkernel` | * |  | Linux kernel modules
 [`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
 `x86_64-unknown-uefi` | * |  | 64-bit UEFI
diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-none-hermitkernel.md b/src/doc/rustc/src/platform-support/aarch64-unknown-none-hermitkernel.md
new file mode 100644 (file)
index 0000000..b8967f6
--- /dev/null
@@ -0,0 +1,77 @@
+# `aarch64-unknown-none-hermitkernel`
+
+**Tier: 3**
+
+Required to build the kernel for [HermitCore](https://github.com/hermitcore/hermit-playground)
+or [RustyHermit](https://github.com/hermitcore/rusty-hermit).
+The result is a bare-metal aarch64 binary in ELF format.
+
+## Target maintainers
+
+- Stefan Lankes, https://github.com/stlankes
+
+## Requirements
+
+This target is cross-compiled. There is no support for `std`, but the
+library operating system provides a simple allocator to use `alloc`.
+
+By default, Rust code generated for this target does not use any vector or
+floating-point registers. This allows the generated code to build the library
+operaring system, which may need to avoid the use of such
+registers or which may have special considerations about the use of such
+registers (e.g. saving and restoring them to avoid breaking userspace code
+using the same registers). In contrast to `aarch64-unknown-none-softfloat`,
+the target is completly relocatable, which is a required feature of RustyHermit.
+
+By default, code generated with this target should run on any `aarch64`
+hardware; enabling additional target features may raise this baseline.
+On `aarch64-unknown-none-hermitkernel`, `extern "C"` uses the [standard System V calling
+convention](https://github.com/ARM-software/abi-aa/releases/download/2021Q3/sysvabi64.pdf),
+without red zones.
+
+This target generated binaries in the ELF format.
+
+## Building the target
+
+Typical you should not use the target directly. The target `aarch64-unknown-hermit`
+builds the _user space_ of RustyHermit and supports red zones and floating-point
+operations.
+To build and link the kernel to the application, the crate
+[hermit-sys](https://github.com/hermitcore/rusty-hermit/tree/master/hermit-sys)
+should be used by adding the following lines to the `Cargo.toml` file of
+your application.
+
+```toml
+[target.'cfg(target_os = "hermit")'.dependencies]
+hermit-sys = "0.1.*"
+```
+
+The crate `hermit-sys` uses the target `aarch64-unknown-none-hermitkernel`
+to build the kernel.
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you need to build the crate `hermit-sys` (see
+"Building the target" above).
+
+## Testing
+
+As `aarch64-unknown-none-hermitkernel` does not support `std`
+and does not support running any Rust testsuite.
+
+## Cross-compilation toolchains and C code
+
+If you want to compile C code along with Rust you will need an
+appropriate `aarch64` toolchain.
+
+Rust *may* be able to use an `aarch64-linux-gnu-` toolchain with appropriate
+standalone flags to build for this toolchain (depending on the assumptions of
+that toolchain, see below), or you may wish to use a separate
+`aarch64-unknown-none` (or `aarch64-elf-`) toolchain.
+
+On some `aarch64` hosts that use ELF binaries, you *may* be able to use the host
+C toolchain, if it does not introduce assumptions about the host environment
+that don't match the expectations of a standalone environment. Otherwise, you
+may need a separate toolchain for standalone/freestanding development, just as
+when cross-compiling from a non-`aarch64` platform.
diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
new file mode 100644 (file)
index 0000000..d58b857
--- /dev/null
@@ -0,0 +1,121 @@
+# `armv7-unknown-linux-uclibceabi`
+
+**Tier: 3**
+
+This target supports ARMv7 softfloat CPUs and uses the uclibc-ng standard library. This is a common configuration on many consumer routers (e.g., Netgear R7000, Asus RT-AC68U).
+
+## Target maintainers
+
+* [@lancethepants](https://github.com/lancethepants)
+
+## Requirements
+
+This target is cross compiled, and requires a cross toolchain.
+
+This target supports host tools and std.
+
+## Building the target
+
+You will need to download or build a `'C'` cross toolchain that targets ARMv7 softfloat and that uses the uclibc-ng standard library. If your target hardware is something like a router or an embedded device, keep in mind that manufacturer supplied SDKs for this class of CPU could be outdated and potentially unsuitable for bootstrapping rust.
+
+[Here](https://github.com/lancethepants/tomatoware-toolchain) is a sample toolchain that is built using [buildroot](https://buildroot.org/). It uses modern toolchain components, older thus universal kernel headers (2.6.36.4), and is used for a project called [Tomatoware](https://github.com/lancethepants/tomatoware). This toolchain is patched so that its sysroot is located at /mmc (e.g., /mmc/bin, /mmc/lib, /mmc/include). This is useful in scenarios where the root filesystem is read-only but you are able attach external storage loaded with user applications. Tomatoware is an example of this that even allows you to run various compilers and developer tools natively on the target device.
+
+Utilizing the Tomatoware toolchain this target can be built for cross compilation and native compilation (host tools) with project
+
+[rust-bootstrap-armv7-unknown-linux-uclibceabi](https://github.com/lancethepants/rust-bootstrap-armv7-unknown-linux-uclibceabi).
+
+
+Here is a sample config if using your own toolchain.
+
+```toml
+[build]
+build-stage = 2
+target = ["armv7-unknown-linux-uclibceabi"]
+
+[target.armv7-unknown-linux-uclibceabi]
+cc = "/path/to/arm-unknown-linux-uclibcgnueabi-gcc"
+cxx = "/path/to/arm-unknown-linux-uclibcgnueabi-g++"
+ar = "path/to/arm-unknown-linux-uclibcgnueabi-ar"
+ranlib = "path/to/arm-unknown-linux-uclibcgnueabi-"
+linker = "/path/to/arm-unknown-linux-uclibcgnueabi-"
+```
+
+## Building Rust programs
+
+The following assumes you are using the Tomatoware toolchain and environment. Adapt if you are using your own toolchain.
+
+### Native compilation
+
+Since this target supports host tools, you can natively build rust applications directly on your target device. This can be convenient because it removes the complexities of cross compiling and you can immediately test and deploy your binaries. One downside is that compiling on your ARMv7 CPU will probably be much slower than cross compilation on your x86 machine.
+
+To setup native compilation:
+
+* Download Tomatoware to your device using the latest nightly release found [here](https://files.lancethepants.com/Tomatoware/Nightly/).
+* Extract `tar zxvf arm-soft-mmc.tgz -C /mmc`
+* Add `/mmc/bin:/mmc:sbin/` to your PATH, or `source /mmc/etc/profile`
+* `apt update && apt install rust`
+
+If you bootstrap rust on your own using the project above, it will create a .deb file that you then can install with
+```text
+dpkg -i rust_1.xx.x-x_arm.deb
+```
+
+After completing these steps you can use rust normally in a native environment.
+
+### Cross Compilation
+
+To cross compile, you'll need to:
+
+* Build the rust cross toochain using  [rust-bootstrap-armv7-unknown-linux-uclibceabi](https://github.com/lancethepants/rust-bootstrap-armv7-unknown-linux-uclibceabi) or your own built toolchain.
+* Link your built toolchain with
+
+    ```text
+    rustup toolchain link stage2 \
+    ${HOME}/rust-bootstrap-armv7-unknown-linux-uclibceabi/src/rust/rust/build/x86_64-unknown-linux-gnu/stage2
+    ```
+* Build with:
+    ```text
+    CC=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
+    CXX=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-g++ \
+    AR=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-ar \
+    CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_LINKER=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
+    CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_RUSTFLAGS='-Clink-arg=-s -Clink-arg=-Wl,--dynamic-linker=/mmc/lib/ld-uClibc.so.1 -Clink-arg=-Wl,-rpath,/mmc/lib' \
+    cargo +stage2 build --target armv7-unknown-linux-uclibceabi --release
+    ```
+* Copy the binary to your target device and run.
+
+We specify `CC`, `CXX`, and `AR` because somtimes a project or a subproject requires the use of your `'C'` cross toolchain. Since Tomatoware has a modified sysroot we also pass via RUSTFLAGS the location of the dynamic-linker and rpath.
+
+### Test with QEMU
+
+To test a cross-compiled binary on your build system follow the instructions for `Cross Compilation`, install `qemu-arm-static`, and run with the following.
+```text
+CC=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
+CXX=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-g++ \
+AR=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-ar \
+CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_LINKER=/opt/tomatoware/arm-soft-mmc/bin/arm-linux-gcc \
+CARGO_TARGET_ARMV7_UNKNOWN_LINUX_UCLIBCEABI_RUNNER="qemu-arm-static -L /opt/tomatoware/arm-soft-mmc/arm-tomatoware-linux-uclibcgnueabi/sysroot/" \
+cargo +stage2 run --target armv7-unknown-linux-uclibceabi --release
+```
+### Run in a chroot
+
+It's also possible to build in a chroot environment. This is a convenient way to work without needing to access the target hardware.
+
+To build the chroot:
+
+* `sudo debootstrap --arch armel bullseye $HOME/debian`
+* `sudo chroot $HOME/debian/ /bin/bash`
+* `mount proc /proc -t proc`
+* `mount -t sysfs /sys sys/`
+* `export PATH=/mmc/bin:/mmc/sbin:$PATH`
+
+From here you can setup your environment (e.g., add user, install wget).
+
+* Download Tomatoware to the chroot environment using the latest nightly release found [here](https://files.lancethepants.com/Tomatoware/Nightly/).
+* Extract `tar zxvf arm-soft-mmc.tgz -C /mmc`
+* Add `/mmc/bin:/mmc:sbin/` to your PATH, or `source /mmc/etc/profile`
+* `sudo /mmc/bin/apt update && sudo /mmc/bin/apt install rust`
+
+After completing these steps you can use rust normally in a chroot environment.
+
+Remember when using `sudo` the root user's PATH could differ from your user's PATH.
diff --git a/src/doc/rustc/src/platform-support/mips64-openwrt-linux-musl.md b/src/doc/rustc/src/platform-support/mips64-openwrt-linux-musl.md
new file mode 100644 (file)
index 0000000..07470ee
--- /dev/null
@@ -0,0 +1,28 @@
+# `mips64-openwrt-linux-musl`
+**Tier: 3**
+
+## Target maintainers
+- Donald Hoskins `grommish@gmail.com`, https://github.com/Itus-Shield
+
+## Requirements
+This target is cross-compiled. There is no support for `std`. There is no
+default allocator, but it's possible to use `alloc` by supplying an allocator.
+
+By default, Rust code generated for this target uses `-msoft-float` and is
+dynamically linked.
+
+This target generated binaries in the ELF format.
+
+## Building the target
+This target is built exclusively within the `OpenWrt` build system via
+the `rust-lang` HOST package
+
+## Building Rust programs
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above).
+
+## Testing
+As `mips64-openwrt-linux-musl` supports a variety of different environments and does
+not support `std`, this target does not support running the Rust testsuite at this
+time.
index 23a9f31e8e7da00c10434cb47c6e630ade13afae..0e0eb85db746a33d8368ec7603ca35dd912189b8 100644 (file)
@@ -267,7 +267,7 @@ Controls the format of the output. Valid options:
 
 Writes the results of the tests to the given file.
 
-#### `--report-time` _FORMAT_
+#### `--report-time`
 
 ⚠️ 🚧 This option is [unstable](#unstable-options), and requires the `-Z
 unstable-options` flag. See [tracking issue
index 9de2e733de7c722a7aa323e42725dabf4525ad6c..3ce57f88938f76d39f495db068a6a01b94893b41 100644 (file)
@@ -381,7 +381,7 @@ the same CSS rules as the official `light` theme.
 `--check-theme` flag, it discards all other flags and only performs the CSS rule
 comparison operation.
 
-### `--crate-version`: control the crate version
+## `--crate-version`: control the crate version
 
 Using this flag looks like this:
 
@@ -418,9 +418,22 @@ Rustdoc only supports Rust source code and Markdown input formats. If the
 file ends in `.md` or `.markdown`, `rustdoc` treats it as a Markdown file.
 Otherwise, it assumes that the input file is Rust.
 
+# Unstable command line arguments
+
 ## `--nocapture`
 
 When this flag is used with `--test`, the output (stdout and stderr) of your tests won't be
 captured by rustdoc. Instead, the output will be directed to your terminal,
 as if you had run the test executable manually. This is especially useful
 for debugging your tests!
+
+## `--check`
+
+When this flag is supplied, rustdoc will type check and lint your code, but will not generate any
+documentation or run your doctests.
+
+Using this flag looks like:
+
+```bash
+rustdoc -Z unstable-options --check src/lib.rs
+```
diff --git a/src/doc/unstable-book/src/compiler-flags/cf-protection.md b/src/doc/unstable-book/src/compiler-flags/cf-protection.md
new file mode 100644 (file)
index 0000000..cc580ca
--- /dev/null
@@ -0,0 +1,40 @@
+# `cf-protection`
+
+This option enables control-flow enforcement technology (CET) on x86; a more detailed description of
+CET is available [here]. Similar to `clang`, this flag takes one of the following values:
+
+- `none` - Disable CET completely (this is the default).
+- `branch` - Enable indirect branch tracking (`IBT`).
+- `return` - Enable shadow stack (`SHSTK`).
+- `full` - Enable both `branch` and `return`.
+
+[here]: https://www.intel.com/content/www/us/en/develop/articles/technical-look-control-flow-enforcement-technology.html
+
+This flag only applies to the LLVM backend: it sets the `cf-protection-branch` and
+`cf-protection-return` flags on LLVM modules. Note, however, that all compiled modules linked
+together must have the flags set for the compiled output to be CET-enabled. Currently, Rust's
+standard library does not ship with CET enabled by default, so you may need to rebuild all standard
+modules with a `cargo` command like:
+
+```sh
+$ RUSTFLAGS="-Z cf-protection=full" RUSTC="rustc-custom" cargo +nightly build -Z build-std --target x86_64-unknown-linux-gnu
+```
+
+### Detection
+
+An ELF binary is CET-enabled if it has the `IBT` and `SHSTK` tags, e.g.:
+
+```sh
+$ readelf -a target/x86_64-unknown-linux-gnu/debug/example | grep feature:
+      Properties: x86 feature: IBT, SHSTK
+```
+
+### Troubleshooting
+
+To display modules that are not CET enabled, examine the linker errors available when `cet-report` is enabled:
+
+```sh
+$ RUSTC_LOG=rustc_codegen_ssa::back::link=info rustc-custom -v -Z cf-protection=full -C link-arg="-Wl,-z,cet-report=warning" -o example example.rs
+...
+/usr/bin/ld: /.../build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d73f7266be14cb8b.rlib(std-d73f7266be14cb8b.std.f7443020-cgu.12.rcgu.o): warning: missing IBT and SHSTK properties
+```
diff --git a/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md b/src/doc/unstable-book/src/compiler-flags/instrument-coverage.md
deleted file mode 100644 (file)
index 39eb407..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-# `instrument-coverage`
-
-The tracking issue for this feature is: [#79121].
-
-[#79121]: https://github.com/rust-lang/rust/issues/79121
-
----
-
-## Introduction
-
-The Rust compiler includes two code coverage implementations:
-
--   A GCC-compatible, gcov-based coverage implementation, enabled with `-Z profile`, which derives coverage data based on DebugInfo.
--   A source-based code coverage implementation, enabled with `-Z instrument-coverage`, which uses LLVM's native, efficient coverage instrumentation to generate very precise coverage data.
-
-This document describes how to enable and use the LLVM instrumentation-based coverage, via the `-Z instrument-coverage` compiler flag.
-
-## How it works
-
-When `-Z instrument-coverage` is enabled, the Rust compiler enhances rust-based libraries and binaries by:
-
--   Automatically injecting calls to an LLVM intrinsic ([`llvm.instrprof.increment`]), at functions and branches in compiled code, to increment counters when conditional sections of code are executed.
--   Embedding additional information in the data section of each library and binary (using the [LLVM Code Coverage Mapping Format] _Version 5_, if compiling with LLVM 12, or _Version 6_, if compiling with LLVM 13 or higher), to define the code regions (start and end positions in the source code) being counted.
-
-When running a coverage-instrumented program, the counter values are written to a `profraw` file at program termination. LLVM bundles tools that read the counter results, combine those results with the coverage map (embedded in the program binary), and generate coverage reports in multiple formats.
-
-[`llvm.instrprof.increment`]: https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic
-[llvm code coverage mapping format]: https://llvm.org/docs/CoverageMappingFormat.html
-
-> **Note**: `-Z instrument-coverage` also automatically enables `-C symbol-mangling-version=v0` (tracking issue [#60705]). The `v0` symbol mangler is strongly recommended, but be aware that this demangler is also experimental. The `v0` demangler can be overridden by explicitly adding `-Z unstable-options -C symbol-mangling-version=legacy`.
-
-[#60705]: https://github.com/rust-lang/rust/issues/60705
-
-## Enable coverage profiling in the Rust compiler
-
-Rust's source-based code coverage requires the Rust "profiler runtime". Without it, compiling with `-Z instrument-coverage` generates an error that the profiler runtime is missing.
-
-The Rust `nightly` distribution channel includes the profiler runtime, by default.
-
-> **Important**: If you are building the Rust compiler from the source distribution, the profiler runtime is _not_ enabled in the default `config.toml.example`. Edit your `config.toml` file and ensure the `profiler` feature is set it to `true` (either under the `[build]` section, or under the settings for an individual `[target.<triple>]`):
->
-> ```toml
-> # Build the profiler runtime (required when compiling with options that depend
-> # on this runtime, such as `-C profile-generate` or `-Z  instrument-coverage`).
-> profiler = true
-> ```
-
-### Building the demangler
-
-LLVM coverage reporting tools generate results that can include function names and other symbol references, and the raw coverage results report symbols using the compiler's "mangled" version of the symbol names, which can be difficult to interpret. To work around this issue, LLVM coverage tools also support a user-specified symbol name demangler.
-
-One option for a Rust demangler is [`rustfilt`], which can be installed with:
-
-```shell
-cargo install rustfilt
-```
-
-Another option, if you are building from the Rust compiler source distribution, is to use the `rust-demangler` tool included in the Rust source distribution, which can be built with:
-
-```shell
-$ ./x.py build rust-demangler
-```
-
-[`rustfilt`]: https://crates.io/crates/rustfilt
-
-## Compiling with coverage enabled
-
-Set the `-Z instrument-coverage` compiler flag in order to enable LLVM source-based code coverage profiling.
-
-The default option generates coverage for all functions, including unused (never called) functions and generics. The compiler flag supports an optional value to tailor this behavior. (See [`-Z instrument-coverage=<options>`](#-z-instrument-coverageoptions), below.)
-
-With `cargo`, you can instrument your program binary _and_ dependencies at the same time.
-
-For example (if your project's Cargo.toml builds a binary by default):
-
-```shell
-$ cd your-project
-$ cargo clean
-$ RUSTFLAGS="-Z instrument-coverage" cargo build
-```
-
-If `cargo` is not configured to use your `profiler`-enabled version of `rustc`, set the path explicitly via the `RUSTC` environment variable. Here is another example, using a `stage1` build of `rustc` to compile an `example` binary (from the [`json5format`] crate):
-
-```shell
-$ RUSTC=$HOME/rust/build/x86_64-unknown-linux-gnu/stage1/bin/rustc \
-    RUSTFLAGS="-Z instrument-coverage" \
-    cargo build --example formatjson5
-```
-
-> **Note**: that some compiler options, combined with `-Z instrument-coverage`, can produce LLVM IR and/or linked binaries that are incompatible with LLVM coverage maps. For example, coverage requires references to actual functions in LLVM IR. If any covered function is optimized out, the coverage tools may not be able to process the coverage results. If you need to pass additional options, with coverage enabled, test them early, to confirm you will get the coverage results you expect.
-
-## Running the instrumented binary to generate raw coverage profiling data
-
-In the previous example, `cargo` generated the coverage-instrumented binary `formatjson5`:
-
-```shell
-$ echo "{some: 'thing'}" | target/debug/examples/formatjson5 -
-```
-
-```json5
-{
-    some: "thing",
-}
-```
-
-After running this program, a new file, `default.profraw`, should be in the current working directory. It's often preferable to set a specific file name or path. You can change the output file using the environment variable `LLVM_PROFILE_FILE`:
-
-```shell
-$ echo "{some: 'thing'}" \
-    | LLVM_PROFILE_FILE="formatjson5.profraw" target/debug/examples/formatjson5 -
-...
-$ ls formatjson5.profraw
-formatjson5.profraw
-```
-
-If `LLVM_PROFILE_FILE` contains a path to a non-existent directory, the missing directory structure will be created. Additionally, the following special pattern strings are rewritten:
-
--   `%p` - The process ID.
--   `%h` - The hostname of the machine running the program.
--   `%t` - The value of the TMPDIR environment variable.
--   `%Nm` - the instrumented binary’s signature: The runtime creates a pool of N raw profiles, used for on-line profile merging. The runtime takes care of selecting a raw profile from the pool, locking it, and updating it before the program exits. `N` must be between `1` and `9`, and defaults to `1` if omitted (with simply `%m`).
--   `%c` - Does not add anything to the filename, but enables a mode (on some platforms, including Darwin) in which profile counter updates are continuously synced to a file. This means that if the instrumented program crashes, or is killed by a signal, perfect coverage information can still be recovered.
-
-## Installing LLVM coverage tools
-
-LLVM's supplies two tools—`llvm-profdata` and `llvm-cov`—that process coverage data and generate reports. There are several ways to find and/or install these tools, but note that the coverage mapping data generated by the Rust compiler requires LLVM version 12 or higher. (`llvm-cov --version` typically shows the tool's LLVM version number.):
-
--   The LLVM tools may be installed (or installable) directly to your OS (such as via `apt-get`, for Linux).
--   If you are building the Rust compiler from source, you can optionally use the bundled LLVM tools, built from source. Those tool binaries can typically be found in your build platform directory at something like: `rust/build/x86_64-unknown-linux-gnu/llvm/bin/llvm-*`.
--   You can install compatible versions of these tools via `rustup`.
-
-The `rustup` option is guaranteed to install a compatible version of the LLVM tools, but they can be hard to find. We recommend [`cargo-binutils`], which installs Rust-specific wrappers around these and other LLVM tools, so you can invoke them via `cargo` commands!
-
-```shell
-$ rustup component add llvm-tools-preview
-$ cargo install cargo-binutils
-$ cargo profdata -- --help  # note the additional "--" preceding the tool-specific arguments
-```
-
-[`cargo-binutils`]: https://crates.io/crates/cargo-binutils
-
-## Creating coverage reports
-
-Raw profiles have to be indexed before they can be used to generate coverage reports. This is done using [`llvm-profdata merge`] (or `cargo profdata -- merge`), which can combine multiple raw profiles and index them at the same time:
-
-```shell
-$ llvm-profdata merge -sparse formatjson5.profraw -o formatjson5.profdata
-```
-
-Finally, the `.profdata` file is used, in combination with the coverage map (from the program binary) to generate coverage reports using [`llvm-cov report`] (or `cargo cov -- report`), for a coverage summaries; and [`llvm-cov show`] (or `cargo cov -- show`), to see detailed coverage of lines and regions (character ranges) overlaid on the original source code.
-
-These commands have several display and filtering options. For example:
-
-```shell
-$ llvm-cov show -Xdemangler=rustfilt target/debug/examples/formatjson5 \
-    -instr-profile=formatjson5.profdata \
-    -show-line-counts-or-regions \
-    -show-instantiations \
-    -name=add_quoted_string
-```
-
-<img alt="Screenshot of sample `llvm-cov show` result, for function add_quoted_string" src="img/llvm-cov-show-01.png" class="center"/>
-<br/>
-<br/>
-
-Some of the more notable options in this example include:
-
--   `--Xdemangler=rustfilt` - the command name or path used to demangle Rust symbols (`rustfilt` in the example, but this could also be a path to the `rust-demangler` tool)
--   `target/debug/examples/formatjson5` - the instrumented binary (from which to extract the coverage map)
--   `--instr-profile=<path-to-file>.profdata` - the location of the `.profdata` file created by `llvm-profdata merge` (from the `.profraw` file generated by the instrumented binary)
--   `--name=<exact-function-name>` - to show coverage for a specific function (or, consider using another filter option, such as `--name-regex=<pattern>`)
-
-[`llvm-profdata merge`]: https://llvm.org/docs/CommandGuide/llvm-profdata.html#profdata-merge
-[`llvm-cov report`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-report
-[`llvm-cov show`]: https://llvm.org/docs/CommandGuide/llvm-cov.html#llvm-cov-show
-
-> **Note**: Coverage can also be disabled on an individual function by annotating the function with the [`no_coverage` attribute] (which requires the feature flag `#![feature(no_coverage)]`).
-
-[`no_coverage` attribute]: ../language-features/no-coverage.md
-
-## Interpreting reports
-
-There are four statistics tracked in a coverage summary:
-
--   Function coverage is the percentage of functions that have been executed at least once. A function is considered to be executed if any of its instantiations are executed.
--   Instantiation coverage is the percentage of function instantiations that have been executed at least once. Generic functions and functions generated from macros are two kinds of functions that may have multiple instantiations.
--   Line coverage is the percentage of code lines that have been executed at least once. Only executable lines within function bodies are considered to be code lines.
--   Region coverage is the percentage of code regions that have been executed at least once. A code region may span multiple lines: for example, in a large function body with no control flow. In other cases, a single line can contain multiple code regions: `return x || (y && z)` has countable code regions for `x` (which may resolve the expression, if `x` is `true`), `|| (y && z)` (executed only if `x` was `false`), and `return` (executed in either situation).
-
-Of these four statistics, function coverage is usually the least granular while region coverage is the most granular. The project-wide totals for each statistic are listed in the summary.
-
-## Test coverage
-
-A typical use case for coverage analysis is test coverage. Rust's source-based coverage tools can both measure your tests' code coverage as percentage, and pinpoint functions and branches not tested.
-
-The following example (using the [`json5format`] crate, for demonstration purposes) show how to generate and analyze coverage results for all tests in a crate.
-
-Since `cargo test` both builds and runs the tests, we set both the additional `RUSTFLAGS`, to add the `-Z instrument-coverage` flag, and `LLVM_PROFILE_FILE`, to set a custom filename for the raw profiling data generated during the test runs. Since there may be more than one test binary, apply `%m` in the filename pattern. This generates unique names for each test binary. (Otherwise, each executed test binary would overwrite the coverage results from the previous binary.)
-
-```shell
-$ RUSTFLAGS="-Z instrument-coverage" \
-    LLVM_PROFILE_FILE="json5format-%m.profraw" \
-    cargo test --tests
-```
-
-Make note of the test binary file paths, displayed after the word "`Running`" in the test output:
-
-```text
-   ...
-   Compiling json5format v0.1.3 ($HOME/json5format)
-    Finished test [unoptimized + debuginfo] target(s) in 14.60s
-
-     Running target/debug/deps/json5format-fececd4653271682
-running 25 tests
-...
-test result: ok. 25 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
-
-     Running target/debug/deps/lib-30768f9c53506dc5
-running 31 tests
-...
-test result: ok. 31 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
-```
-
-You should have one or more `.profraw` files now, one for each test binary. Run the `profdata` tool to merge them:
-
-```shell
-$ cargo profdata -- merge \
-    -sparse json5format-*.profraw -o json5format.profdata
-```
-
-Then run the `cov` tool, with the `profdata` file and all test binaries:
-
-```shell
-$ cargo cov -- report \
-    --use-color --ignore-filename-regex='/.cargo/registry' \
-    --instr-profile=json5format.profdata \
-    --object target/debug/deps/lib-30768f9c53506dc5 \
-    --object target/debug/deps/json5format-fececd4653271682
-$ cargo cov -- show \
-    --use-color --ignore-filename-regex='/.cargo/registry' \
-    --instr-profile=json5format.profdata \
-    --object target/debug/deps/lib-30768f9c53506dc5 \
-    --object target/debug/deps/json5format-fececd4653271682 \
-    --show-instantiations --show-line-counts-or-regions \
-    --Xdemangler=rustfilt | less -R
-```
-
-> **Note**: The command line option `--ignore-filename-regex=/.cargo/registry`, which excludes the sources for dependencies from the coverage results.\_
-
-### Tips for listing the binaries automatically
-
-For `bash` users, one suggested way to automatically complete the `cov` command with the list of binaries is with a command like:
-
-```bash
-$ cargo cov -- report \
-    $( \
-      for file in \
-        $( \
-          RUSTFLAGS="-Z instrument-coverage" \
-            cargo test --tests --no-run --message-format=json \
-              | jq -r "select(.profile.test == true) | .filenames[]" \
-              | grep -v dSYM - \
-        ); \
-      do \
-        printf "%s %s " -object $file; \
-      done \
-    ) \
-  --instr-profile=json5format.profdata --summary-only # and/or other options
-```
-
-Adding `--no-run --message-format=json` to the _same_ `cargo test` command used to run
-the tests (including the same environment variables and flags) generates output in a JSON
-format that `jq` can easily query.
-
-The `printf` command takes this list and generates the `--object <binary>` arguments
-for each listed test binary.
-
-### Including doc tests
-
-The previous examples run `cargo test` with `--tests`, which excludes doc tests.[^79417]
-
-To include doc tests in the coverage results, drop the `--tests` flag, and apply the
-`-Z instrument-coverage` flag, and some doc-test-specific options in the
-`RUSTDOCFLAGS` environment variable. (The `cargo profdata` command does not change.)
-
-```bash
-$ RUSTFLAGS="-Z instrument-coverage" \
-  RUSTDOCFLAGS="-Z instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \
-  LLVM_PROFILE_FILE="json5format-%m.profraw" \
-    cargo test
-$ cargo profdata -- merge \
-    -sparse json5format-*.profraw -o json5format.profdata
-```
-
-The `-Z unstable-options --persist-doctests` flag is required, to save the test binaries
-(with their coverage maps) for `llvm-cov`.
-
-```bash
-$ cargo cov -- report \
-    $( \
-      for file in \
-        $( \
-          RUSTFLAGS="-Z instrument-coverage" \
-          RUSTDOCFLAGS="-Z instrument-coverage -Z unstable-options --persist-doctests target/debug/doctestbins" \
-            cargo test --no-run --message-format=json \
-              | jq -r "select(.profile.test == true) | .filenames[]" \
-              | grep -v dSYM - \
-        ) \
-        target/debug/doctestbins/*/rust_out; \
-      do \
-        [[ -x $file ]] && printf "%s %s " -object $file; \
-      done \
-    ) \
-  --instr-profile=json5format.profdata --summary-only # and/or other options
-```
-
-> **Note**: The differences in this `cargo cov` command, compared with the version without
-> doc tests, include:
-
--   The `cargo test ... --no-run` command is updated with the same environment variables
-    and flags used to _build_ the tests, _including_ the doc tests. (`LLVM_PROFILE_FILE`
-    is only used when _running_ the tests.)
--   The file glob pattern `target/debug/doctestbins/*/rust_out` adds the `rust_out`
-    binaries generated for doc tests (note, however, that some `rust_out` files may not
-    be executable binaries).
--   `[[ -x $file ]] &&` filters the files passed on to the `printf`, to include only
-    executable binaries.
-
-[^79417]:
-    There is ongoing work to resolve a known issue
-    [(#79417)](https://github.com/rust-lang/rust/issues/79417) that doc test coverage
-    generates incorrect source line numbers in `llvm-cov show` results.
-
-## `-Z instrument-coverage=<options>`
-
--   `-Z instrument-coverage=all`: Instrument all functions, including unused functions and unused generics. (This is the same as `-Z instrument-coverage`, with no value.)
--   `-Z instrument-coverage=except-unused-generics`: Instrument all functions except unused generics.
--   `-Z instrument-coverage=except-unused-functions`: Instrument only used (called) functions and instantiated generic functions.
--   `-Z instrument-coverage=off`: Do not instrument any functions. (This is the same as simply not including the `-Z instrument-coverage` option.)
-
-## Other references
-
-Rust's implementation and workflow for source-based code coverage is based on the same library and tools used to implement [source-based code coverage in Clang]. (This document is partially based on the Clang guide.)
-
-[source-based code coverage in clang]: https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
-[`json5format`]: https://crates.io/crates/json5format
index ac0093f77aec22c57ae92a3b34c54293e67077ab..9e6a1fb000575f8316c78c937fb69c666b40e04d 100644 (file)
@@ -21,11 +21,8 @@ Sample usage command:
 Available options:
 
 ```sh
---report-time [plain|colored]
-                Show execution time of each test. Available values:
-                plain = do not colorize the execution time (default);
-                colored = colorize output according to the `color`
-                parameter value;
+--report-time
+                Show execution time of each test.
                 Threshold values for colorized output can be
                 configured via
                 `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION`
diff --git a/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md b/src/doc/unstable-book/src/compiler-flags/source-based-code-coverage.md
deleted file mode 100644 (file)
index cb65978..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-# `source-based-code-coverage`
-
-See compiler flag [`-Z instrument-coverage`].
-
-[`-z instrument-coverage`]: ./instrument-coverage.html
index 1063c23b6dfba4f0650e89c12d6eed6a2ea42ecd..670c4df414f31ae2c34dd8da8da51a3dcce93cff 100644 (file)
@@ -1,8 +1,8 @@
 # `asm_const`
 
-The tracking issue for this feature is: [#72016]
+The tracking issue for this feature is: [#93332]
 
-[#72016]: https://github.com/rust-lang/rust/issues/72016
+[#93332]: https://github.com/rust-lang/rust/issues/93332
 
 ------------------------
 
index 37fd67447c1340867ca51fd03e7facf0da993153..0a48eb4f81a128fb8e0927f0d214b2da544001d3 100644 (file)
@@ -1,8 +1,8 @@
 # `asm_experimental_arch`
 
-The tracking issue for this feature is: [#72016]
+The tracking issue for this feature is: [#93335]
 
-[#72016]: https://github.com/rust-lang/rust/issues/72016
+[#93335]: https://github.com/rust-lang/rust/issues/93335
 
 ------------------------
 
index 7544e20807e9247cc939f513dde3731c6a58d4af..103d91caf4ccd4c4e716cd3aeaed69e8086e078a 100644 (file)
@@ -1,8 +1,8 @@
 # `asm_sym`
 
-The tracking issue for this feature is: [#72016]
+The tracking issue for this feature is: [#93333]
 
-[#72016]: https://github.com/rust-lang/rust/issues/72016
+[#93333]: https://github.com/rust-lang/rust/issues/93333
 
 ------------------------
 
index 414193fe801774de89c1596fe032d4d0c16cf036..809e6d75b35bfedf38fee6c4e805cc69f0fd26da 100644 (file)
@@ -1,8 +1,8 @@
 # `asm_unwind`
 
-The tracking issue for this feature is: [#72016]
+The tracking issue for this feature is: [#93334]
 
-[#72016]: https://github.com/rust-lang/rust/issues/72016
+[#93334]: https://github.com/rust-lang/rust/issues/93334
 
 ------------------------
 
index 2801d9b5e7778314a4e1c59a43d99053093ec84b..fb32918d5e439450e1ec61a14e5b83f63259ddf2 100644 (file)
@@ -6,9 +6,20 @@ The tracking issue for this feature is: [#74990]
 
 ------------------------
 
-Introduces four new ABI strings: "C-unwind", "stdcall-unwind",
-"thiscall-unwind", and "system-unwind". These enable unwinding from other
-languages (such as C++) into Rust frames and from Rust into other languages.
+Introduces new ABI strings:
+- "C-unwind"
+- "cdecl-unwind"
+- "stdcall-unwind"
+- "fastcall-unwind"
+- "vectorcall-unwind"
+- "thiscall-unwind"
+- "aapcs-unwind"
+- "win64-unwind"
+- "sysv64-unwind"
+- "system-unwind"
+
+These enable unwinding from other languages (such as C++) into Rust frames and
+from Rust into other languages.
 
 See [RFC 2945] for more information.
 
index c7be0167de9fdb8233f84cb35333688c3e0e36de..eb2b9c848aa6f419870e9424428b03119963585f 100644 (file)
@@ -41,7 +41,7 @@
           <If Condition="(base.table.table.ctrl.pointer[i] &amp; 0x80) == 0">
             <!-- Bucket is populated -->
             <Exec>n--</Exec>
-            <Item Name="{((tuple$&lt;$T1, $T2&gt;*)base.table.table.ctrl.pointer)[-(i + 1)].__0}">((tuple$&lt;$T1, $T2&gt;*)base.table.table.ctrl.pointer)[-(i + 1)].__1</Item>
+            <Item Name="{((tuple$&lt;$T1,$T2&gt;*)base.table.table.ctrl.pointer)[-(i + 1)].__0}">((tuple$&lt;$T1,$T2&gt;*)base.table.table.ctrl.pointer)[-(i + 1)].__1</Item>
           </If>
           <Exec>i++</Exec>
         </Loop>
diff --git a/src/etc/pre-commit.sh b/src/etc/pre-commit.sh
deleted file mode 100755 (executable)
index 9045adb..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/usr/bin/env bash
-#
-# Call `tidy --bless` before each commit
-# Copy this script to .git/hooks to activate,
-# and remove it from .git/hooks to deactivate.
-#
-
-set -Eeuo pipefail
-
-# https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570
-unset GIT_DIR
-ROOT_DIR="$(git rev-parse --show-toplevel)"
-COMMAND="$ROOT_DIR/x.py test tidy --bless"
-
-if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
-  COMMAND="python $COMMAND"
-fi
-
-echo "Running pre-commit script '$COMMAND'"
-
-cd "$ROOT_DIR"
-
-$COMMAND
diff --git a/src/etc/pre-push.sh b/src/etc/pre-push.sh
new file mode 100755 (executable)
index 0000000..a78725f
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+#
+# Call `tidy --bless` before each commit
+# Copy this script to .git/hooks to activate,
+# and remove it from .git/hooks to deactivate.
+#
+
+set -Eeuo pipefail
+
+# https://github.com/rust-lang/rust/issues/77620#issuecomment-705144570
+unset GIT_DIR
+ROOT_DIR="$(git rev-parse --show-toplevel)"
+COMMAND="$ROOT_DIR/x.py test tidy --bless"
+
+if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then
+  COMMAND="python $COMMAND"
+fi
+
+echo "Running pre-push script '$COMMAND'"
+
+cd "$ROOT_DIR"
+
+$COMMAND
index 45285c1f442c45d030c4d0578363e03ce869d571..4371a914b48041c932114de3d477d758ec8ddd9b 100644 (file)
@@ -17,7 +17,7 @@ serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 smallvec = "1.6.1"
 tempfile = "3"
-itertools = "0.9"
+itertools = "0.10"
 regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
 tracing = "0.1"
index 18a4d8a475380f328ec17ef2792a5114c1e66231..a3154d8f03bf82ee752993d13839e2ff8ebaf20d 100644 (file)
@@ -297,7 +297,7 @@ fn handle_lifetimes<'cx>(
                     .get(name)
                     .unwrap_or(&empty)
                     .iter()
-                    .map(|region| GenericBound::Outlives(Self::get_lifetime(region, names_map)))
+                    .map(|region| GenericBound::Outlives(Self::get_lifetime(*region, names_map)))
                     .collect();
 
                 if bounds.is_empty() {
index a2e612955b3498cecb506dc756b9d2735af0e0e4..f0ae01f3803f408349c0f3c5cc286b17f461cf13 100644 (file)
@@ -564,7 +564,7 @@ fn build_module(
         let hir_id = tcx.hir().local_def_id_to_hir_id(did);
         rustc_hir_pretty::id_to_string(&tcx.hir(), hir_id)
     } else {
-        tcx.rendered_const(did)
+        tcx.rendered_const(did).clone()
     }
 }
 
index 95404b33822e363e1b26fcb545066d954f6056ab..187bc13357a90f380e7868adf4f6caef8641f656 100644 (file)
@@ -218,9 +218,9 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
     }
 }
 
-impl Clean<Option<Lifetime>> for ty::RegionKind {
+impl Clean<Option<Lifetime>> for ty::Region<'_> {
     fn clean(&self, _cx: &mut DocContext<'_>) -> Option<Lifetime> {
-        match *self {
+        match **self {
             ty::ReStatic => Some(Lifetime::statik()),
             ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) => {
                 Some(Lifetime(name))
@@ -327,7 +327,7 @@ impl<'tcx> Clean<Option<WherePredicate>>
     fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
         let ty::OutlivesPredicate(a, b) = self;
 
-        if let (ty::ReEmpty(_), ty::ReEmpty(_)) = (a, b) {
+        if a.is_empty() && b.is_empty() {
             return None;
         }
 
@@ -342,7 +342,7 @@ impl<'tcx> Clean<Option<WherePredicate>> for ty::OutlivesPredicate<Ty<'tcx>, ty:
     fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
         let ty::OutlivesPredicate(ty, lt) = self;
 
-        if let ty::ReEmpty(_) = lt {
+        if lt.is_empty() {
             return None;
         }
 
@@ -1014,7 +1014,8 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
                     {
                         m.header.constness = hir::Constness::NotConst;
                     }
-                    MethodItem(m, Some(self.defaultness))
+                    let defaultness = cx.tcx.associated_item(self.def_id).defaultness;
+                    MethodItem(m, Some(defaultness))
                 }
                 hir::ImplItemKind::TyAlias(ref hir_ty) => {
                     let type_ = hir_ty.clean(cx);
@@ -1454,7 +1455,7 @@ fn normalize<'tcx>(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
 impl<'tcx> Clean<Type> for Ty<'tcx> {
     fn clean(&self, cx: &mut DocContext<'_>) -> Type {
         trace!("cleaning type: {:?}", self);
-        let ty = normalize(cx, self).unwrap_or(self);
+        let ty = normalize(cx, *self).unwrap_or(*self);
         match *ty.kind() {
             ty::Never => Primitive(PrimitiveType::Never),
             ty::Bool => Primitive(PrimitiveType::Bool),
@@ -1533,9 +1534,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
                 for pb in obj.projection_bounds() {
                     bindings.push(TypeBinding {
                         name: cx.tcx.associated_item(pb.item_def_id()).name,
-                        kind: TypeBindingKind::Equality {
-                            term: pb.skip_binder().term.clean(cx).into(),
-                        },
+                        kind: TypeBindingKind::Equality { term: pb.skip_binder().term.clean(cx) },
                     });
                 }
 
@@ -1642,7 +1641,7 @@ impl<'tcx> Clean<Constant> for ty::Const<'tcx> {
     fn clean(&self, cx: &mut DocContext<'_>) -> Constant {
         // FIXME: instead of storing the stringified expression, store `self` directly instead.
         Constant {
-            type_: self.ty.clean(cx),
+            type_: self.ty().clean(cx),
             kind: ConstantKind::TyConst { expr: self.to_string() },
         }
     }
index 0bad153280822f971d101f4aad49b5e651e6ffd3..ea18d915deb7a96e5fb97c4c0cf6067e9203f271 100644 (file)
@@ -51,9 +51,7 @@
     // Look for equality predicates on associated types that can be merged into
     // general bound predicates
     equalities.retain(|&(ref lhs, ref rhs)| {
-        let (self_, trait_did, name) = if let Some(p) = lhs.projection() {
-            p
-        } else {
+        let Some((self_, trait_did, name)) = lhs.projection() else {
             return true;
         };
         let generic = match self_ {
index 02633698273608e52684b8ef846f01f939e36c2a..74184427dd5732e413ce6cf56c1383b46e42e32c 100644 (file)
@@ -953,7 +953,7 @@ fn add_doc_fragment(out: &mut String, frag: &DocFragment) {
 /// A link that has not yet been rendered.
 ///
 /// This link will be turned into a rendered link by [`Item::links`].
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 crate struct ItemLink {
     /// The original link written in the markdown
     crate link: String,
@@ -1036,8 +1036,7 @@ impl Attributes {
         // Additional documentation should be shown before the original documentation
         let other_attrs = additional_attrs
             .into_iter()
-            .map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
-            .flatten()
+            .flat_map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id))))
             .chain(attrs.iter().map(|attr| (attr, None)))
             .filter_map(clean_attr)
             .collect();
@@ -1973,7 +1972,7 @@ impl Path {
     /// Checks if this is a `T::Name` path for an associated type.
     crate fn is_assoc_ty(&self) -> bool {
         match self.res {
-            Res::SelfTy(..) if self.segments.len() != 1 => true,
+            Res::SelfTy { .. } if self.segments.len() != 1 => true,
             Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true,
             Res::Def(DefKind::AssocTy, _) => true,
             _ => false,
index dabf1e878c9fb38d3f5aaaf04f128a2cd7cd7c30..1d312df1f785890522d1bc0fa700a7d79fbe4a95 100644 (file)
@@ -89,7 +89,7 @@ fn external_generic_args(
     let args: Vec<_> = substs
         .iter()
         .filter_map(|kind| match kind.unpack() {
-            GenericArgKind::Lifetime(lt) => match lt {
+            GenericArgKind::Lifetime(lt) => match *lt {
                 ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrAnon(_), .. }) => {
                     Some(GenericArg::Lifetime(Lifetime::elided()))
                 }
@@ -226,8 +226,8 @@ pub(super) fn external_path(
     })
 }
 
-crate fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String {
-    match n.val {
+crate fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String {
+    match n.val() {
         ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted }) => {
             let mut s = if let Some(def) = def.as_local() {
                 let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def.did);
@@ -297,15 +297,15 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
         .collect()
 }
 
-fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &ty::Const<'_>) -> String {
+fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: ty::Const<'_>) -> String {
     // Use a slightly different format for integer types which always shows the actual value.
     // For all other types, fallback to the original `pretty_print_const`.
-    match (ct.val, ct.ty.kind()) {
+    match (ct.val(), ct.ty().kind()) {
         (ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Uint(ui)) => {
             format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
         }
         (ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Int(i)) => {
-            let ty = tcx.lift(ct.ty).unwrap();
+            let ty = tcx.lift(ct.ty()).unwrap();
             let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
             let data = int.assert_bits(size);
             let sign_extended_data = size.sign_extend(data) as i128;
@@ -355,7 +355,7 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &ty::Const<'_>) ->
 
     match path.res {
         Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
-        Res::SelfTy(..) if path.segments.len() == 1 => Generic(kw::SelfUpper),
+        Res::SelfTy { .. } if path.segments.len() == 1 => Generic(kw::SelfUpper),
         Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
         _ => {
             let _ = register_res(cx, path.res);
@@ -397,11 +397,11 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &ty::Const<'_>) ->
             | Union | Mod | ForeignTy | Const | Static | Macro(..) | TraitAlias),
             i,
         ) => (i, kind.into()),
-        // This is part of a trait definition; document the trait.
-        Res::SelfTy(Some(trait_def_id), _) => (trait_def_id, ItemType::Trait),
-        // This is an inherent impl; it doesn't have its own page.
-        Res::SelfTy(None, Some((impl_def_id, _))) => return impl_def_id,
-        Res::SelfTy(None, None)
+        // This is part of a trait definition or trait impl; document the trait.
+        Res::SelfTy { trait_: Some(trait_def_id), alias_to: _ } => (trait_def_id, ItemType::Trait),
+        // This is an inherent impl or a type definition; it doesn't have its own page.
+        Res::SelfTy { trait_: None, alias_to: Some((item_def_id, _)) } => return item_def_id,
+        Res::SelfTy { trait_: None, alias_to: None }
         | Res::PrimTy(_)
         | Res::ToolMod
         | Res::SelfCtor(_)
index 959f83a021139e09877a1364864cb1b40028b449..6e483d27f336b52e1933b8b1c1e45c52b54c09af 100644 (file)
@@ -439,13 +439,12 @@ fn println_condition(condition: Condition) {
             matches
                 .opt_str("default-theme")
                 .iter()
-                .map(|theme| {
+                .flat_map(|theme| {
                     vec![
                         ("use-system-theme".to_string(), "false".to_string()),
                         ("theme".to_string(), theme.to_string()),
                     ]
                 })
-                .flatten()
                 .collect(),
             matches
                 .opt_strs("default-setting")
index 1f14a333c005dbc67e63a272b0112497665f0351..893e126283b01aee60205b9231b081df5e4dfc4e 100644 (file)
@@ -256,7 +256,6 @@ impl<'tcx> DocContext<'tcx> {
         output_dir: None,
         file_loader: None,
         diagnostic_output: DiagnosticOutput::Default,
-        stderr: None,
         lint_caps,
         parse_sess_created: None,
         register_lints: Some(box crate::lint::register_lints),
index 024fe6345d295a694b3f2e8b91ac378c4b41795d..3a9fb6d14203ee6bcba30f944cb45ee8937833af 100644 (file)
@@ -97,7 +97,6 @@
         output_dir: None,
         file_loader: None,
         diagnostic_output: DiagnosticOutput::Default,
-        stderr: None,
         lint_caps,
         parse_sess_created: None,
         register_lints: Some(box crate::lint::register_lints),
@@ -659,7 +658,7 @@ fn drop(&mut self) {
     } else {
         let returns_result = everything_else.trim_end().ends_with("(())");
         // Give each doctest main function a unique name.
-        // This is for example needed for the tooling around `-Z instrument-coverage`.
+        // This is for example needed for the tooling around `-C instrument-coverage`.
         let inner_fn_name = if let Some(test_id) = test_id {
             format!("_doctest_main_{}", test_id)
         } else {
@@ -684,7 +683,7 @@ fn drop(&mut self) {
         };
         // Note on newlines: We insert a line/newline *before*, and *after*
         // the doctest and adjust the `line_offset` accordingly.
-        // In the case of `-Z instrument-coverage`, this means that the generated
+        // In the case of `-C instrument-coverage`, this means that the generated
         // inner `main` function spans from the doctest opening codeblock to the
         // closing one. For example
         // /// ``` <- start of the inner main
@@ -951,10 +950,11 @@ fn add_test(&mut self, test: String, config: LangString, line: usize) {
                 },
                 // compiler failures are test failures
                 should_panic: test::ShouldPanic::No,
-                allow_fail: config.allow_fail,
                 compile_fail: config.compile_fail,
                 no_run,
                 test_type: test::TestType::DocTest,
+                #[cfg(bootstrap)]
+                allow_fail: false,
             },
             testfn: test::DynTestFn(box move || {
                 let report_unused_externs = |uext| {
index f4df9ef4a8c9dbe1409e7c4b91bbceab39c3f85c..c0115bfc6d4fab3d0c4716f9d273e1806150e9a3 100644 (file)
@@ -76,7 +76,7 @@ fn write_char(&mut self, c: char) -> fmt::Result {
     }
 
     #[inline]
-    fn write_fmt(self: &mut Self, args: fmt::Arguments<'_>) -> fmt::Result {
+    fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
         self.buffer.write_fmt(args)
     }
 }
index 39f58cdd821d5b569ae6a9f70b3902c3418e6925..06d60b6d06c9ce10d983508e977949107b975e34 100644 (file)
@@ -274,8 +274,7 @@ fn new(info: DecorationInfo) -> Self {
         let (mut starts, mut ends): (Vec<_>, Vec<_>) = info
             .0
             .into_iter()
-            .map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
-            .flatten()
+            .flat_map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi)))
             .unzip();
 
         // Sort the sequences in document order.
index a9a3a0af276b11205f8bf6767fe8bb8570d9c48c..7061a9674e4fb63be45ec59f5704763dcf47cd36 100644 (file)
@@ -236,9 +236,7 @@ fn next(&mut self) -> Option<Self::Item> {
         let should_panic;
         let ignore;
         let edition;
-        let kind = if let Some(Event::Start(Tag::CodeBlock(kind))) = event {
-            kind
-        } else {
+        let Some(Event::Start(Tag::CodeBlock(kind))) = event else {
             return event;
         };
 
@@ -565,7 +563,7 @@ fn next(&mut self) -> Option<Self::Item> {
             self.buf.push_back((Event::Html(format!("</a></h{}>", level).into()), 0..0));
 
             let start_tags = format!(
-                "<h{level} id=\"{id}\" class=\"section-header\">\
+                "<h{level} id=\"{id}\">\
                     <a href=\"#{id}\">",
                 id = id,
                 level = level
@@ -847,7 +845,6 @@ fn error_invalid_codeblock_attr(&self, msg: &str, help: &str) {
     crate test_harness: bool,
     crate compile_fail: bool,
     crate error_codes: Vec<String>,
-    crate allow_fail: bool,
     crate edition: Option<Edition>,
 }
 
@@ -869,7 +866,6 @@ fn default() -> Self {
             test_harness: false,
             compile_fail: false,
             error_codes: Vec::new(),
-            allow_fail: false,
             edition: None,
         }
     }
@@ -943,10 +939,6 @@ fn parse(
                         seen_rust_tags = !seen_other_tags;
                     }
                 }
-                "allow_fail" => {
-                    data.allow_fail = true;
-                    seen_rust_tags = !seen_other_tags;
-                }
                 "rust" => {
                     data.rust = true;
                     seen_rust_tags = true;
@@ -994,12 +986,6 @@ fn parse(
                             "the code block will either not be tested if not marked as a rust one \
                              or will be run (which you might not want)",
                         ))
-                    } else if s == "allow-fail" || s == "allow_fail" || s == "allowfail" {
-                        Some((
-                            "allow_fail",
-                            "the code block will either not be tested if not marked as a rust one \
-                             or will be run (which you might not want)",
-                        ))
                     } else if s == "test-harness" || s == "test_harness" || s == "testharness" {
                         Some((
                             "test_harness",
index d4af3663b624af5b7cded2b37ffe2ab5242914ac..5c0bf0ed942f4169ffde9eae363db910791b9323 100644 (file)
@@ -70,7 +70,6 @@ fn t(lg: LangString) {
         compile_fail: true,
         ..Default::default()
     });
-    t(LangString { original: "allow_fail".into(), allow_fail: true, ..Default::default() });
     t(LangString { original: "no_run,example".into(), no_run: true, ..Default::default() });
     t(LangString {
         original: "sh,should_panic".into(),
@@ -160,25 +159,22 @@ fn t(input: &str, expect: &str) {
         assert_eq!(output, expect, "original: {}", input);
     }
 
-    t(
-        "# Foo bar",
-        "<h2 id=\"foo-bar\" class=\"section-header\"><a href=\"#foo-bar\">Foo bar</a></h2>",
-    );
+    t("# Foo bar", "<h2 id=\"foo-bar\"><a href=\"#foo-bar\">Foo bar</a></h2>");
     t(
         "## Foo-bar_baz qux",
-        "<h3 id=\"foo-bar_baz-qux\" class=\"section-header\">\
+        "<h3 id=\"foo-bar_baz-qux\">\
          <a href=\"#foo-bar_baz-qux\">Foo-bar_baz qux</a></h3>",
     );
     t(
         "### **Foo** *bar* baz!?!& -_qux_-%",
-        "<h4 id=\"foo-bar-baz--qux-\" class=\"section-header\">\
+        "<h4 id=\"foo-bar-baz--qux-\">\
             <a href=\"#foo-bar-baz--qux-\"><strong>Foo</strong> \
             <em>bar</em> baz!?!&amp; -<em>qux</em>-%</a>\
          </h4>",
     );
     t(
         "#### **Foo?** & \\*bar?!*  _`baz`_ ❤ #qux",
-        "<h5 id=\"foo--bar--baz--qux\" class=\"section-header\">\
+        "<h5 id=\"foo--bar--baz--qux\">\
              <a href=\"#foo--bar--baz--qux\"><strong>Foo?</strong> &amp; *bar?!*  \
              <em><code>baz</code></em> ❤ #qux</a>\
          </h5>",
@@ -202,36 +198,12 @@ fn t(map: &mut IdMap, input: &str, expect: &str) {
         assert_eq!(output, expect, "original: {}", input);
     }
 
-    t(
-        &mut map,
-        "# Example",
-        "<h2 id=\"example\" class=\"section-header\"><a href=\"#example\">Example</a></h2>",
-    );
-    t(
-        &mut map,
-        "# Panics",
-        "<h2 id=\"panics\" class=\"section-header\"><a href=\"#panics\">Panics</a></h2>",
-    );
-    t(
-        &mut map,
-        "# Example",
-        "<h2 id=\"example-1\" class=\"section-header\"><a href=\"#example-1\">Example</a></h2>",
-    );
-    t(
-        &mut map,
-        "# Search",
-        "<h2 id=\"search-1\" class=\"section-header\"><a href=\"#search-1\">Search</a></h2>",
-    );
-    t(
-        &mut map,
-        "# Example",
-        "<h2 id=\"example-2\" class=\"section-header\"><a href=\"#example-2\">Example</a></h2>",
-    );
-    t(
-        &mut map,
-        "# Panics",
-        "<h2 id=\"panics-1\" class=\"section-header\"><a href=\"#panics-1\">Panics</a></h2>",
-    );
+    t(&mut map, "# Example", "<h2 id=\"example\"><a href=\"#example\">Example</a></h2>");
+    t(&mut map, "# Panics", "<h2 id=\"panics\"><a href=\"#panics\">Panics</a></h2>");
+    t(&mut map, "# Example", "<h2 id=\"example-1\"><a href=\"#example-1\">Example</a></h2>");
+    t(&mut map, "# Search", "<h2 id=\"search-1\"><a href=\"#search-1\">Search</a></h2>");
+    t(&mut map, "# Example", "<h2 id=\"example-2\"><a href=\"#example-2\">Example</a></h2>");
+    t(&mut map, "# Panics", "<h2 id=\"panics-1\"><a href=\"#panics-1\">Panics</a></h2>");
 }
 
 #[test]
index 59a6187b62be9a804703ebfb01e9bb62bfa1085f..3e3302f8f4db701594d95d1228106cc4b9b0a338 100644 (file)
@@ -1265,7 +1265,7 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
                         if out.is_empty() {
                             write!(
                                 &mut out,
-                                "<div class=\"notable\">Notable traits for {}</div>\
+                                "<span class=\"notable\">Notable traits for {}</span>\
                              <code class=\"content\">",
                                 impl_.for_.print(cx)
                             );
@@ -1297,9 +1297,9 @@ fn notable_traits_decl(decl: &clean::FnDecl, cx: &Context<'_>) -> String {
         out.insert_str(
             0,
             "<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ\
-            <div class=\"notable-traits-tooltiptext\"><span class=\"docblock\">",
+            <span class=\"notable-traits-tooltiptext\"><span class=\"docblock\">",
         );
-        out.push_str("</code></span></div></span></span>");
+        out.push_str("</code></span></span></span></span>");
     }
 
     out.into_inner()
@@ -1431,7 +1431,7 @@ fn doc_impl_item(
                         .map(|item| format!("{}.{}", item.type_(), name));
                     write!(
                         w,
-                        "<div id=\"{}\" class=\"{}{} has-srclink\">",
+                        "<section id=\"{}\" class=\"{}{} has-srclink\">",
                         id, item_type, in_trait_class,
                     );
                     render_rightside(w, cx, item, containing_item, render_mode);
@@ -1446,7 +1446,7 @@ fn doc_impl_item(
                         render_mode,
                     );
                     w.write_str("</h4>");
-                    w.write_str("</div>");
+                    w.write_str("</section>");
                 }
             }
             clean::TypedefItem(ref tydef, _) => {
@@ -1454,7 +1454,7 @@ fn doc_impl_item(
                 let id = cx.derive_id(source_id.clone());
                 write!(
                     w,
-                    "<div id=\"{}\" class=\"{}{} has-srclink\">",
+                    "<section id=\"{}\" class=\"{}{} has-srclink\">",
                     id, item_type, in_trait_class
                 );
                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
@@ -1469,14 +1469,14 @@ fn doc_impl_item(
                     cx,
                 );
                 w.write_str("</h4>");
-                w.write_str("</div>");
+                w.write_str("</section>");
             }
             clean::AssocConstItem(ref ty, _) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
                 write!(
                     w,
-                    "<div id=\"{}\" class=\"{}{} has-srclink\">",
+                    "<section id=\"{}\" class=\"{}{} has-srclink\">",
                     id, item_type, in_trait_class
                 );
                 render_rightside(w, cx, item, containing_item, render_mode);
@@ -1491,12 +1491,12 @@ fn doc_impl_item(
                     cx,
                 );
                 w.write_str("</h4>");
-                w.write_str("</div>");
+                w.write_str("</section>");
             }
             clean::AssocTypeItem(ref bounds, ref default) => {
                 let source_id = format!("{}.{}", item_type, name);
                 let id = cx.derive_id(source_id.clone());
-                write!(w, "<div id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
+                write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,);
                 write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
                 w.write_str("<h4 class=\"code-header\">");
                 assoc_type(
@@ -1509,7 +1509,7 @@ fn doc_impl_item(
                     cx,
                 );
                 w.write_str("</h4>");
-                w.write_str("</div>");
+                w.write_str("</section>");
             }
             clean::StrippedItem(..) => return,
             _ => panic!("can't make docs for trait item with name {:?}", item.name),
@@ -1668,21 +1668,23 @@ fn render_rightside(
         RenderMode::ForDeref { .. } => (None, None),
     };
 
-    write!(w, "<div class=\"rightside\">");
+    let mut rightside = Buffer::new();
     let has_stability = render_stability_since_raw(
-        w,
+        &mut rightside,
         item.stable_since(tcx),
         const_stability,
         containing_item.stable_since(tcx),
         const_stable_since,
     );
-    let mut tmp_buf = Buffer::empty_from(w);
-    write_srclink(cx, item, &mut tmp_buf);
-    if has_stability && !tmp_buf.is_empty() {
-        w.write_str(" · ");
+    let mut srclink = Buffer::empty_from(w);
+    write_srclink(cx, item, &mut srclink);
+    if has_stability && !srclink.is_empty() {
+        rightside.write_str(" · ");
+    }
+    rightside.push_buffer(srclink);
+    if !rightside.is_empty() {
+        write!(w, "<span class=\"rightside\">{}</span>", rightside.into_inner());
     }
-    w.push_buffer(tmp_buf);
-    w.write_str("</div>");
 }
 
 pub(crate) fn render_impl_summary(
@@ -1713,7 +1715,7 @@ pub(crate) fn render_impl_summary(
     } else {
         format!(" data-aliases=\"{}\"", aliases.join(","))
     };
-    write!(w, "<div id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
+    write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
     render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
     write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
     write!(w, "<h3 class=\"code-header in-band\">");
@@ -1737,11 +1739,11 @@ pub(crate) fn render_impl_summary(
     let is_trait = i.inner_impl().trait_.is_some();
     if is_trait {
         if let Some(portability) = portability(&i.impl_item, Some(parent)) {
-            write!(w, "<div class=\"item-info\">{}</div>", portability);
+            write!(w, "<span class=\"item-info\">{}</span>", portability);
         }
     }
 
-    w.write_str("</div>");
+    w.write_str("</section>");
 }
 
 fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
@@ -1802,19 +1804,9 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
     // to navigate the documentation (though slightly inefficiently).
 
     if !it.is_mod() {
-        buffer.write_str("<h2 class=\"location\">In ");
-        for (i, name) in cx.current.iter().take(parentlen).enumerate() {
-            if i > 0 {
-                buffer.write_str("::<wbr>");
-            }
-            write!(
-                buffer,
-                "<a href=\"{}index.html\">{}</a>",
-                &cx.root_path()[..(cx.current.len() - i - 1) * 3],
-                *name
-            );
-        }
-        buffer.write_str("</h2>");
+        let path: String = cx.current.iter().map(|s| s.as_str()).intersperse("::").collect();
+
+        write!(buffer, "<h2 class=\"location\"><a href=\"index.html\">In {}</a></h2>", path);
     }
 
     // Sidebar refers to the enclosing module, not this module.
@@ -1971,16 +1963,12 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
                 // We want links' order to be reproducible so we don't use unstable sort.
                 assoc_consts.sort();
 
-                out.push_str(
-                    "<h3 class=\"sidebar-title\">\
-                        <a href=\"#implementations\">Associated Constants</a>\
-                     </h3>\
-                     <div class=\"sidebar-links\">",
+                print_sidebar_block(
+                    out,
+                    "implementations",
+                    "Associated Constants",
+                    assoc_consts.iter(),
                 );
-                for line in assoc_consts {
-                    write!(out, "{}", line);
-                }
-                out.push_str("</div>");
             }
             let mut methods = v
                 .iter()
@@ -1991,14 +1979,7 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
                 // We want links' order to be reproducible so we don't use unstable sort.
                 methods.sort();
 
-                out.push_str(
-                    "<h3 class=\"sidebar-title\"><a href=\"#implementations\">Methods</a></h3>\
-                     <div class=\"sidebar-links\">",
-                );
-                for line in methods {
-                    write!(out, "{}", line);
-                }
-                out.push_str("</div>");
+                print_sidebar_block(out, "implementations", "Methods", methods.iter());
             }
         }
 
@@ -2037,14 +2018,6 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
                 ret
             };
 
-            let write_sidebar_links = |out: &mut Buffer, links: Vec<String>| {
-                out.push_str("<div class=\"sidebar-links\">");
-                for link in links {
-                    out.push_str(&link);
-                }
-                out.push_str("</div>");
-            };
-
             let (synthetic, concrete): (Vec<&Impl>, Vec<&Impl>) =
                 v.iter().partition::<Vec<_>, _>(|i| i.inner_impl().kind.is_auto());
             let (blanket_impl, concrete): (Vec<&Impl>, Vec<&Impl>) =
@@ -2055,27 +2028,30 @@ fn sidebar_assoc_items(cx: &Context<'_>, out: &mut Buffer, it: &clean::Item) {
             let blanket_format = format_impls(blanket_impl);
 
             if !concrete_format.is_empty() {
-                out.push_str(
-                    "<h3 class=\"sidebar-title\"><a href=\"#trait-implementations\">\
-                        Trait Implementations</a></h3>",
+                print_sidebar_block(
+                    out,
+                    "trait-implementations",
+                    "Trait Implementations",
+                    concrete_format.iter(),
                 );
-                write_sidebar_links(out, concrete_format);
             }
 
             if !synthetic_format.is_empty() {
-                out.push_str(
-                    "<h3 class=\"sidebar-title\"><a href=\"#synthetic-implementations\">\
-                        Auto Trait Implementations</a></h3>",
+                print_sidebar_block(
+                    out,
+                    "synthetic-implementations",
+                    "Auto Trait Implementations",
+                    synthetic_format.iter(),
                 );
-                write_sidebar_links(out, synthetic_format);
             }
 
             if !blanket_format.is_empty() {
-                out.push_str(
-                    "<h3 class=\"sidebar-title\"><a href=\"#blanket-implementations\">\
-                        Blanket Implementations</a></h3>",
+                print_sidebar_block(
+                    out,
+                    "blanket-implementations",
+                    "Blanket Implementations",
+                    blanket_format.iter(),
                 );
-                write_sidebar_links(out, blanket_format);
             }
         }
     }
@@ -2135,20 +2111,14 @@ fn sidebar_deref_methods(
                 } else {
                     "deref-methods"
                 };
-                write!(
-                    out,
-                    "<h3 class=\"sidebar-title\"><a href=\"#{}\">Methods from {}&lt;Target={}&gt;</a></h3>",
-                    id,
+                let title = format!(
+                    "Methods from {}&lt;Target={}&gt;",
                     Escape(&format!("{:#}", impl_.inner_impl().trait_.as_ref().unwrap().print(cx))),
                     Escape(&format!("{:#}", real_target.print(cx))),
                 );
                 // We want links' order to be reproducible so we don't use unstable sort.
                 ret.sort();
-                out.push_str("<div class=\"sidebar-links\">");
-                for link in ret {
-                    write!(out, "{}", link);
-                }
-                out.push_str("</div>");
+                print_sidebar_block(out, id, &title, ret.iter());
             }
         }
 
@@ -2174,27 +2144,19 @@ fn sidebar_struct(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, s: &clea
     let fields = get_struct_fields_name(&s.fields);
 
     if !fields.is_empty() {
-        if let CtorKind::Fictive = s.struct_type {
-            sidebar.push_str(
-                "<h3 class=\"sidebar-title\"><a href=\"#fields\">Fields</a></h3>\
-                <div class=\"sidebar-links\">",
-            );
-
-            for field in fields {
-                sidebar.push_str(&field);
+        match s.struct_type {
+            CtorKind::Fictive => {
+                print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter());
             }
-
-            sidebar.push_str("</div>");
-        } else if let CtorKind::Fn = s.struct_type {
-            sidebar
-                .push_str("<h3 class=\"sidebar-title\"><a href=\"#fields\">Tuple Fields</a></h3>");
+            CtorKind::Fn => print_sidebar_title(&mut sidebar, "fields", "Tuple Fields"),
+            CtorKind::Const => {}
         }
     }
 
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
     }
 }
 
@@ -2222,18 +2184,50 @@ fn extract_for_impl_name(item: &clean::Item, cx: &Context<'_>) -> Option<(String
     }
 }
 
+/// Don't call this function directly!!! Use `print_sidebar_title` or `print_sidebar_block` instead!
+fn print_sidebar_title_inner(buf: &mut Buffer, id: &str, title: &str) {
+    write!(
+        buf,
+        "<h3 class=\"sidebar-title\">\
+             <a href=\"#{}\">{}</a>\
+         </h3>",
+        id, title
+    );
+}
+
+fn print_sidebar_title(buf: &mut Buffer, id: &str, title: &str) {
+    buf.push_str("<div class=\"block\">");
+    print_sidebar_title_inner(buf, id, title);
+    buf.push_str("</div>");
+}
+
+fn print_sidebar_block(
+    buf: &mut Buffer,
+    id: &str,
+    title: &str,
+    items: impl Iterator<Item = impl fmt::Display>,
+) {
+    buf.push_str("<div class=\"block\">");
+    print_sidebar_title_inner(buf, id, title);
+    buf.push_str("<ul>");
+    for item in items {
+        write!(buf, "<li>{}</li>", item);
+    }
+    buf.push_str("</ul></div>");
+}
+
 fn sidebar_trait(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) {
-    buf.write_str("<div class=\"block items\">");
+    buf.write_str("<section>");
 
     fn print_sidebar_section(
         out: &mut Buffer,
         items: &[clean::Item],
-        before: &str,
+        id: &str,
+        title: &str,
         filter: impl Fn(&clean::Item) -> bool,
-        write: impl Fn(&mut Buffer, &str),
-        after: &str,
+        mapper: impl Fn(&str) -> String,
     ) {
-        let mut items = items
+        let mut items: Vec<&str> = items
             .iter()
             .filter_map(|m| match m.name {
                 Some(ref name) if filter(m) => Some(name.as_str()),
@@ -2243,52 +2237,44 @@ fn print_sidebar_section(
 
         if !items.is_empty() {
             items.sort_unstable();
-            out.push_str(before);
-            for item in items.into_iter() {
-                write(out, &item);
-            }
-            out.push_str(after);
+            print_sidebar_block(out, id, title, items.into_iter().map(mapper));
         }
     }
 
     print_sidebar_section(
         buf,
         &t.items,
-        "<h3 class=\"sidebar-title\"><a href=\"#associated-types\">\
-            Associated Types</a></h3><div class=\"sidebar-links\">",
+        "associated-types",
+        "Associated Types",
         |m| m.is_associated_type(),
-        |out, sym| write!(out, "<a href=\"#associatedtype.{0}\">{0}</a>", sym),
-        "</div>",
+        |sym| format!("<a href=\"#associatedtype.{0}\">{0}</a>", sym),
     );
 
     print_sidebar_section(
         buf,
         &t.items,
-        "<h3 class=\"sidebar-title\"><a href=\"#associated-const\">\
-            Associated Constants</a></h3><div class=\"sidebar-links\">",
+        "associated-const",
+        "Associated Constants",
         |m| m.is_associated_const(),
-        |out, sym| write!(out, "<a href=\"#associatedconstant.{0}\">{0}</a>", sym),
-        "</div>",
+        |sym| format!("<a href=\"#associatedconstant.{0}\">{0}</a>", sym),
     );
 
     print_sidebar_section(
         buf,
         &t.items,
-        "<h3 class=\"sidebar-title\"><a href=\"#required-methods\">\
-            Required Methods</a></h3><div class=\"sidebar-links\">",
+        "required-methods",
+        "Required Methods",
         |m| m.is_ty_method(),
-        |out, sym| write!(out, "<a href=\"#tymethod.{0}\">{0}</a>", sym),
-        "</div>",
+        |sym| format!("<a href=\"#tymethod.{0}\">{0}</a>", sym),
     );
 
     print_sidebar_section(
         buf,
         &t.items,
-        "<h3 class=\"sidebar-title\"><a href=\"#provided-methods\">\
-            Provided Methods</a></h3><div class=\"sidebar-links\">",
+        "provided-methods",
+        "Provided Methods",
         |m| m.is_method(),
-        |out, sym| write!(out, "<a href=\"#method.{0}\">{0}</a>", sym),
-        "</div>",
+        |sym| format!("<a href=\"#method.{0}\">{0}</a>", sym),
     );
 
     let cache = cx.cache();
@@ -2303,29 +2289,23 @@ fn print_sidebar_section(
 
         if !res.is_empty() {
             res.sort();
-            buf.push_str(
-                "<h3 class=\"sidebar-title\"><a href=\"#foreign-impls\">\
-                    Implementations on Foreign Types</a></h3>\
-                 <div class=\"sidebar-links\">",
+            print_sidebar_block(
+                buf,
+                "foreign-impls",
+                "Implementations on Foreign Types",
+                res.iter().map(|(name, id)| format!("<a href=\"#{}\">{}</a>", id, Escape(&name))),
             );
-            for (name, id) in res.into_iter() {
-                write!(buf, "<a href=\"#{}\">{}</a>", id, Escape(&name));
-            }
-            buf.push_str("</div>");
         }
     }
 
     sidebar_assoc_items(cx, buf, it);
 
-    buf.push_str("<h3 class=\"sidebar-title\"><a href=\"#implementors\">Implementors</a></h3>");
+    print_sidebar_title(buf, "implementors", "Implementors");
     if t.is_auto {
-        buf.push_str(
-            "<h3 class=\"sidebar-title\"><a \
-                href=\"#synthetic-implementors\">Auto Implementors</a></h3>",
-        );
+        print_sidebar_title(buf, "synthetic-implementors", "Auto Implementors");
     }
 
-    buf.push_str("</div>")
+    buf.push_str("</section>")
 }
 
 fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
@@ -2333,7 +2313,7 @@ fn sidebar_primitive(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
     }
 }
 
@@ -2342,7 +2322,7 @@ fn sidebar_typedef(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
     }
 }
 
@@ -2363,22 +2343,13 @@ fn sidebar_union(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, u: &clean
     let fields = get_struct_fields_name(&u.fields);
 
     if !fields.is_empty() {
-        sidebar.push_str(
-            "<h3 class=\"sidebar-title\"><a href=\"#fields\">Fields</a></h3>\
-            <div class=\"sidebar-links\">",
-        );
-
-        for field in fields {
-            sidebar.push_str(&field);
-        }
-
-        sidebar.push_str("</div>");
+        print_sidebar_block(&mut sidebar, "fields", "Fields", fields.iter());
     }
 
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
     }
 }
 
@@ -2396,47 +2367,166 @@ fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean:
         .collect::<Vec<_>>();
     if !variants.is_empty() {
         variants.sort_unstable();
-        sidebar.push_str(&format!(
-            "<h3 class=\"sidebar-title\"><a href=\"#variants\">Variants</a></h3>\
-             <div class=\"sidebar-links\">{}</div>",
-            variants.join(""),
-        ));
+        print_sidebar_block(&mut sidebar, "variants", "Variants", variants.iter());
     }
 
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
-    }
-}
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
+    }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+enum ItemSection {
+    Reexports,
+    PrimitiveTypes,
+    Modules,
+    Macros,
+    Structs,
+    Enums,
+    Constants,
+    Statics,
+    Traits,
+    Functions,
+    TypeDefinitions,
+    Unions,
+    Implementations,
+    TypeMethods,
+    Methods,
+    StructFields,
+    Variants,
+    AssociatedTypes,
+    AssociatedConstants,
+    ForeignTypes,
+    Keywords,
+    OpaqueTypes,
+    AttributeMacros,
+    DeriveMacros,
+    TraitAliases,
+}
+
+impl ItemSection {
+    const ALL: &'static [Self] = {
+        use ItemSection::*;
+        // NOTE: The order here affects the order in the UI.
+        &[
+            Reexports,
+            PrimitiveTypes,
+            Modules,
+            Macros,
+            Structs,
+            Enums,
+            Constants,
+            Statics,
+            Traits,
+            Functions,
+            TypeDefinitions,
+            Unions,
+            Implementations,
+            TypeMethods,
+            Methods,
+            StructFields,
+            Variants,
+            AssociatedTypes,
+            AssociatedConstants,
+            ForeignTypes,
+            Keywords,
+            OpaqueTypes,
+            AttributeMacros,
+            DeriveMacros,
+            TraitAliases,
+        ]
+    };
 
-fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) {
+    fn id(self) -> &'static str {
+        match self {
+            Self::Reexports => "reexports",
+            Self::Modules => "modules",
+            Self::Structs => "structs",
+            Self::Unions => "unions",
+            Self::Enums => "enums",
+            Self::Functions => "functions",
+            Self::TypeDefinitions => "types",
+            Self::Statics => "statics",
+            Self::Constants => "constants",
+            Self::Traits => "traits",
+            Self::Implementations => "impls",
+            Self::TypeMethods => "tymethods",
+            Self::Methods => "methods",
+            Self::StructFields => "fields",
+            Self::Variants => "variants",
+            Self::Macros => "macros",
+            Self::PrimitiveTypes => "primitives",
+            Self::AssociatedTypes => "associated-types",
+            Self::AssociatedConstants => "associated-consts",
+            Self::ForeignTypes => "foreign-types",
+            Self::Keywords => "keywords",
+            Self::OpaqueTypes => "opaque-types",
+            Self::AttributeMacros => "attributes",
+            Self::DeriveMacros => "derives",
+            Self::TraitAliases => "trait-aliases",
+        }
+    }
+
+    fn name(self) -> &'static str {
+        match self {
+            Self::Reexports => "Re-exports",
+            Self::Modules => "Modules",
+            Self::Structs => "Structs",
+            Self::Unions => "Unions",
+            Self::Enums => "Enums",
+            Self::Functions => "Functions",
+            Self::TypeDefinitions => "Type Definitions",
+            Self::Statics => "Statics",
+            Self::Constants => "Constants",
+            Self::Traits => "Traits",
+            Self::Implementations => "Implementations",
+            Self::TypeMethods => "Type Methods",
+            Self::Methods => "Methods",
+            Self::StructFields => "Struct Fields",
+            Self::Variants => "Variants",
+            Self::Macros => "Macros",
+            Self::PrimitiveTypes => "Primitive Types",
+            Self::AssociatedTypes => "Associated Types",
+            Self::AssociatedConstants => "Associated Constants",
+            Self::ForeignTypes => "Foreign Types",
+            Self::Keywords => "Keywords",
+            Self::OpaqueTypes => "Opaque Types",
+            Self::AttributeMacros => "Attribute Macros",
+            Self::DeriveMacros => "Derive Macros",
+            Self::TraitAliases => "Trait Aliases",
+        }
+    }
+}
+
+fn item_ty_to_section(ty: ItemType) -> ItemSection {
     match ty {
-        ItemType::ExternCrate | ItemType::Import => ("reexports", "Re-exports"),
-        ItemType::Module => ("modules", "Modules"),
-        ItemType::Struct => ("structs", "Structs"),
-        ItemType::Union => ("unions", "Unions"),
-        ItemType::Enum => ("enums", "Enums"),
-        ItemType::Function => ("functions", "Functions"),
-        ItemType::Typedef => ("types", "Type Definitions"),
-        ItemType::Static => ("statics", "Statics"),
-        ItemType::Constant => ("constants", "Constants"),
-        ItemType::Trait => ("traits", "Traits"),
-        ItemType::Impl => ("impls", "Implementations"),
-        ItemType::TyMethod => ("tymethods", "Type Methods"),
-        ItemType::Method => ("methods", "Methods"),
-        ItemType::StructField => ("fields", "Struct Fields"),
-        ItemType::Variant => ("variants", "Variants"),
-        ItemType::Macro => ("macros", "Macros"),
-        ItemType::Primitive => ("primitives", "Primitive Types"),
-        ItemType::AssocType => ("associated-types", "Associated Types"),
-        ItemType::AssocConst => ("associated-consts", "Associated Constants"),
-        ItemType::ForeignType => ("foreign-types", "Foreign Types"),
-        ItemType::Keyword => ("keywords", "Keywords"),
-        ItemType::OpaqueTy => ("opaque-types", "Opaque Types"),
-        ItemType::ProcAttribute => ("attributes", "Attribute Macros"),
-        ItemType::ProcDerive => ("derives", "Derive Macros"),
-        ItemType::TraitAlias => ("trait-aliases", "Trait aliases"),
+        ItemType::ExternCrate | ItemType::Import => ItemSection::Reexports,
+        ItemType::Module => ItemSection::Modules,
+        ItemType::Struct => ItemSection::Structs,
+        ItemType::Union => ItemSection::Unions,
+        ItemType::Enum => ItemSection::Enums,
+        ItemType::Function => ItemSection::Functions,
+        ItemType::Typedef => ItemSection::TypeDefinitions,
+        ItemType::Static => ItemSection::Statics,
+        ItemType::Constant => ItemSection::Constants,
+        ItemType::Trait => ItemSection::Traits,
+        ItemType::Impl => ItemSection::Implementations,
+        ItemType::TyMethod => ItemSection::TypeMethods,
+        ItemType::Method => ItemSection::Methods,
+        ItemType::StructField => ItemSection::StructFields,
+        ItemType::Variant => ItemSection::Variants,
+        ItemType::Macro => ItemSection::Macros,
+        ItemType::Primitive => ItemSection::PrimitiveTypes,
+        ItemType::AssocType => ItemSection::AssociatedTypes,
+        ItemType::AssocConst => ItemSection::AssociatedConstants,
+        ItemType::ForeignType => ItemSection::ForeignTypes,
+        ItemType::Keyword => ItemSection::Keywords,
+        ItemType::OpaqueTy => ItemSection::OpaqueTypes,
+        ItemType::ProcAttribute => ItemSection::AttributeMacros,
+        ItemType::ProcDerive => ItemSection::DeriveMacros,
+        ItemType::TraitAlias => ItemSection::TraitAliases,
         ItemType::Generic => unreachable!(),
     }
 }
@@ -2444,48 +2534,25 @@ fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) {
 fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) {
     let mut sidebar = String::new();
 
-    // Re-exports are handled a bit differently because they can be extern crates or imports.
-    if items.iter().any(|it| {
-        it.name.is_some()
-            && (it.type_() == ItemType::ExternCrate
-                || (it.type_() == ItemType::Import && !it.is_stripped()))
-    }) {
-        let (id, name) = item_ty_to_strs(ItemType::Import);
-        sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
-    }
-
-    // ordering taken from item_module, reorder, where it prioritized elements in a certain order
-    // to print its headings
-    for &myty in &[
-        ItemType::Primitive,
-        ItemType::Module,
-        ItemType::Macro,
-        ItemType::Struct,
-        ItemType::Enum,
-        ItemType::Constant,
-        ItemType::Static,
-        ItemType::Trait,
-        ItemType::Function,
-        ItemType::Typedef,
-        ItemType::Union,
-        ItemType::Impl,
-        ItemType::TyMethod,
-        ItemType::Method,
-        ItemType::StructField,
-        ItemType::Variant,
-        ItemType::AssocType,
-        ItemType::AssocConst,
-        ItemType::ForeignType,
-        ItemType::Keyword,
-    ] {
-        if items.iter().any(|it| !it.is_stripped() && it.type_() == myty && it.name.is_some()) {
-            let (id, name) = item_ty_to_strs(myty);
-            sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name));
-        }
+    let item_sections_in_use: FxHashSet<_> = items
+        .iter()
+        .filter(|it| !it.is_stripped() && it.name.is_some())
+        .map(|it| item_ty_to_section(it.type_()))
+        .collect();
+    for &sec in ItemSection::ALL.iter().filter(|sec| item_sections_in_use.contains(sec)) {
+        sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", sec.id(), sec.name()));
     }
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\"><ul>{}</ul></div>", sidebar);
+        write!(
+            buf,
+            "<section>\
+                 <div class=\"block\">\
+                     <ul>{}</ul>\
+                 </div>\
+             </section>",
+            sidebar
+        );
     }
 }
 
@@ -2494,7 +2561,7 @@ fn sidebar_foreign_type(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item) {
     sidebar_assoc_items(cx, &mut sidebar, it);
 
     if !sidebar.is_empty() {
-        write!(buf, "<div class=\"block items\">{}</div>", sidebar.into_inner());
+        write!(buf, "<section>{}</section>", sidebar.into_inner());
     }
 }
 
@@ -2575,7 +2642,7 @@ fn render_call_locations(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item) {
         w,
         "<div class=\"docblock scraped-example-list\">\
           <span></span>\
-          <h5 id=\"{id}\" class=\"section-header\">\
+          <h5 id=\"{id}\">\
              <a href=\"#{id}\">Examples found in repository</a>\
           </h5>",
         id = id
index 6592a56ba46a806473c2c493492886543fcdcd9f..e84dc6c72409f6ee2bc98089a3ad6144a8e77503 100644 (file)
 use rustc_target::abi::{Layout, Primitive, TagEncoding, Variants};
 
 use super::{
-    collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_strs, notable_traits_decl,
-    render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre,
-    render_impl, render_stability_since_raw, write_srclink, AssocItemLink, Context,
-    ImplRenderingParameters,
+    collect_paths_for_type, document, ensure_trailing_slash, item_ty_to_section,
+    notable_traits_decl, render_assoc_item, render_assoc_items, render_attributes_in_code,
+    render_attributes_in_pre, render_impl, render_stability_since_raw, write_srclink,
+    AssocItemLink, Context, ImplRenderingParameters,
 };
 use crate::clean;
 use crate::formats::item_type::ItemType;
@@ -221,7 +221,9 @@ fn cmp(
     ) -> Ordering {
         let ty1 = i1.type_();
         let ty2 = i2.type_();
-        if ty1 != ty2 {
+        if item_ty_to_section(ty1) != item_ty_to_section(ty2)
+            || (ty1 != ty2 && (ty1 == ItemType::ExternCrate || ty2 == ItemType::ExternCrate))
+        {
             return (reorder(ty1), idx1).cmp(&(reorder(ty2), idx2));
         }
         let s1 = i1.stability(tcx).as_ref().map(|s| s.level);
@@ -270,7 +272,7 @@ fn cmp(
     });
 
     debug!("{:?}", indices);
-    let mut curty = None;
+    let mut last_section = None;
 
     for &idx in &indices {
         let myitem = &items[idx];
@@ -278,24 +280,20 @@ fn cmp(
             continue;
         }
 
-        let myty = Some(myitem.type_());
-        if curty == Some(ItemType::ExternCrate) && myty == Some(ItemType::Import) {
-            // Put `extern crate` and `use` re-exports in the same section.
-            curty = myty;
-        } else if myty != curty {
-            if curty.is_some() {
+        let my_section = item_ty_to_section(myitem.type_());
+        if Some(my_section) != last_section {
+            if last_section.is_some() {
                 w.write_str(ITEM_TABLE_CLOSE);
             }
-            curty = myty;
-            let (short, name) = item_ty_to_strs(myty.unwrap());
+            last_section = Some(my_section);
             write!(
                 w,
                 "<h2 id=\"{id}\" class=\"small-section-header\">\
                     <a href=\"#{id}\">{name}</a>\
                  </h2>\n{}",
                 ITEM_TABLE_OPEN,
-                id = cx.derive_id(short.to_owned()),
-                name = name
+                id = cx.derive_id(my_section.id().to_owned()),
+                name = my_section.name(),
             );
         }
 
@@ -407,7 +405,7 @@ fn cmp(
         }
     }
 
-    if curty.is_some() {
+    if last_section.is_some() {
         w.write_str(ITEM_TABLE_CLOSE);
     }
 }
@@ -1754,9 +1752,7 @@ fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) {
                             <ul>",
                     );
 
-                    let adt = if let Adt(adt, _) = ty_layout.ty.kind() {
-                        adt
-                    } else {
+                    let Adt(adt, _) = ty_layout.ty.kind() else {
                         span_bug!(tcx.def_span(ty_def_id), "not an adt")
                     };
 
index 0ee67467c383beb9ff7c9cb7f152bdae2f7e02d9..e1309c03b5ca890cec0381735049536d693a19e5 100644 (file)
@@ -81,7 +81,7 @@
                     lastpathid += 1;
 
                     if let Some(&(ref fqp, short)) = paths.get(&defid) {
-                        crate_paths.push((short, fqp.last().unwrap().clone()));
+                        crate_paths.push((short, *fqp.last().unwrap()));
                         Some(pathid)
                     } else {
                         None
index 76913a5c1c5b5e077c763701e76ffb515dd172e0..f1e0a89883ab8d2915c862304aa0ed126ee2c3d5 100644 (file)
@@ -108,7 +108,9 @@ html {
 /* General structure and fonts */
 
 body {
-       font: 1rem/1.4 "Source Serif 4", NanumBarunGothic, serif;
+       /* Line spacing at least 1.5 per Web Content Accessibility Guidelines
+          https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html */
+       font: 1rem/1.5 "Source Serif 4", NanumBarunGothic, serif;
        margin: 0;
        position: relative;
        /* We use overflow-wrap: break-word for Safari, which doesn't recognize
@@ -124,13 +126,13 @@ body {
 }
 
 h1 {
-       font-size: 1.5rem;
+       font-size: 1.5rem; /* 24px */
 }
 h2 {
-       font-size: 1.4rem;
+       font-size: 1.375rem; /* 22px */
 }
 h3 {
-       font-size: 1.3rem;
+       font-size: 1.25rem; /* 20px */
 }
 h1, h2, h3, h4, h5, h6 {
        font-weight: 500;
@@ -170,16 +172,18 @@ h2,
        border-bottom: 1px solid;
 }
 h3.code-header {
-       font-size: 1.1rem;
+       font-size: 1.125rem; /* 18px */
 }
 h4.code-header {
        font-size: 1rem;
 }
-h3.code-header, h4.code-header {
+.code-header {
        font-weight: 600;
        border-bottom-style: none;
-       padding: 0;
        margin: 0;
+       padding: 0;
+       margin-top: 0.6em;
+       margin-bottom: 0.4em;
 }
 .impl,
 .impl-items .method,
@@ -192,8 +196,6 @@ h3.code-header, h4.code-header {
 .methods .associatedtype {
        flex-basis: 100%;
        font-weight: 600;
-       margin-top: 16px;
-       margin-bottom: 10px;
        position: relative;
 }
 
@@ -221,19 +223,18 @@ a.srclink,
        font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
 }
 
-.content ul.crate a.crate {
-       font-size: 1rem/1.6;
-}
-
 ol, ul {
-       padding-left: 25px;
+       padding-left: 24px;
 }
 ul ul, ol ul, ul ol, ol ol {
-       margin-bottom: .6em;
+       margin-bottom: .625em;
 }
 
 p {
-       margin: 0 0 .6em 0;
+       /* Paragraph spacing at least 1.5 times line spacing per Web Content Accessibility Guidelines.
+          Line-height is 1.5rem, so line spacing is .5rem; .75em is 1.5 times that.
+          https://www.w3.org/WAI/WCAG21/Understanding/visual-presentation.html */
+       margin: 0 0 .75em 0;
 }
 
 summary {
@@ -303,7 +304,7 @@ code, pre, a.test-arrow, .code-header {
 }
 .docblock code, .docblock-short code {
        border-radius: 3px;
-       padding: 0 0.1em;
+       padding: 0 0.125em;
 }
 .docblock pre code, .docblock-short pre code {
        padding: 0;
@@ -364,7 +365,7 @@ nav.sub {
 }
 
 .sidebar {
-       font-size: 0.9rem;
+       font-size: 0.875rem;
        width: 250px;
        min-width: 200px;
        overflow-y: scroll;
@@ -463,54 +464,50 @@ nav.sub {
 .location a:first-of-type {
        font-weight: 500;
 }
-.location a:hover {
-       text-decoration: underline;
-}
 
 .block {
        padding: 0;
 }
 .block ul, .block li {
        padding: 0;
+       margin: 0;
        list-style: none;
 }
 
-.block a {
+.block a,
+h2.location a {
        display: block;
-       padding: 0.3em;
-       margin-left: -0.3em;
+       padding: 0.25rem;
+       margin-left: -0.25rem;
 
        text-overflow: ellipsis;
        overflow: hidden;
 }
 
-.sidebar-links a {
-       white-space: nowrap;
-}
-
 .sidebar h2 {
        border-bottom: none;
        font-weight: 500;
        padding: 0;
        margin: 0;
-       margin-top: 1rem;
-       margin-bottom: 1rem;
+       margin-top: 0.7rem;
+       margin-bottom: 0.7rem;
 }
 
 .sidebar h3 {
-       font-size: 1.1rem;
+       font-size: 1.125rem; /* 18px */
        font-weight: 500;
        padding: 0;
        margin: 0;
-       margin-top: 0.5rem;
-       margin-bottom: 0.25rem;
 }
 
-.sidebar-links,
-.block {
+.sidebar-elems .block {
        margin-bottom: 2em;
 }
 
+.sidebar-elems .block li a {
+       white-space: nowrap;
+}
+
 .mobile-topbar {
        display: none;
 }
@@ -601,18 +598,18 @@ nav.sub {
        white-space: pre-wrap;
 }
 
-.top-doc .docblock h2 { font-size: 1.3rem; }
-.top-doc .docblock h3 { font-size: 1.15rem; }
+.top-doc .docblock h2 { font-size: 1.375rem; }
+.top-doc .docblock h3 { font-size: 1.25; }
 .top-doc .docblock h4,
 .top-doc .docblock h5 {
-       font-size: 1.1rem;
+       font-size: 1.125rem;
 }
 .top-doc .docblock h6 {
        font-size: 1rem;
 }
 
 .docblock h5 { font-size: 1rem; }
-.docblock h6 { font-size: 0.95rem; }
+.docblock h6 { font-size: 0.875rem; }
 
 .docblock {
        margin-left: 24px;
@@ -626,12 +623,12 @@ nav.sub {
 
 .content .out-of-band {
        flex-grow: 0;
-       font-size: 1.15rem;
+       font-size: 1.125rem;
        font-weight: normal;
        float: right;
 }
 
-.method > .code-header, .trait-impl > .code-header, .invisible > .code-header {
+.method > .code-header, .trait-impl > .code-header {
        max-width: calc(100% - 41px);
        display: block;
 }
@@ -667,7 +664,7 @@ nav.sub {
 .content td { vertical-align: top; }
 .content td:first-child { padding-right: 20px; }
 .content td p:first-child { margin-top: 0; }
-.content td h1, .content td h2 { margin-left: 0; font-size: 1.1rem; }
+.content td h1, .content td h2 { margin-left: 0; font-size: 1.125rem; }
 .content tr:first-child td { border-top: 0; }
 
 .docblock table {
@@ -716,7 +713,7 @@ nav.sub {
 .content .fn .where,
 .content .where.fmt-newline {
        display: block;
-       font-size: 0.8rem;
+       font-size: 0.875rem;
 }
 
 .content .methods > div:not(.notable-traits):not(.method) {
@@ -739,26 +736,18 @@ nav.sub {
 }
 
 .content .item-info code {
-       font-size: 0.81rem;
+       font-size: 0.875rem;
 }
 
 .content .item-info {
        position: relative;
-       margin-left: 33px;
+       margin-left: 24px;
 }
 
 .sub-variant > div > .item-info {
        margin-top: initial;
 }
 
-.content .item-info::before {
-       content: '⬑';
-       font-size: 1.5625rem;
-       position: absolute;
-       top: -6px;
-       left: -19px;
-}
-
 .content .impl-items .docblock, .content .impl-items .item-info {
        margin-bottom: .6em;
 }
@@ -777,6 +766,7 @@ nav.sub {
 
 #main-content > .item-info {
        margin-top: 0;
+       margin-left: 0;
 }
 
 nav.sub {
@@ -849,15 +839,6 @@ h2.small-section-header > .anchor {
        text-decoration: underline;
 }
 
-.invisible > .srclink,
-.method > .code-header + .srclink {
-       position: absolute;
-       top: 0;
-       right: 0;
-       font-size: 1.0625rem;
-       font-weight: normal;
-}
-
 .block a.current.crate { font-weight: 500; }
 
 /*  In most contexts we use `overflow-wrap: anywhere` to ensure that we can wrap
@@ -895,7 +876,7 @@ table,
        display: table-cell;
 }
 .item-left {
-       padding-right: 1.2rem;
+       padding-right: 1.25rem;
 }
 
 .search-container {
@@ -917,8 +898,8 @@ table,
 #crate-search {
        min-width: 115px;
        margin-top: 5px;
-       margin-left: 0.2em;
-       padding-left: 0.3em;
+       margin-left: 0.25em;
+       padding-left: 0.3125em;
        padding-right: 23px;
        border: 0;
        border-radius: 4px;
@@ -951,8 +932,8 @@ table,
        outline: none;
        border: 1px solid;
        border-radius: 2px;
-       padding: 5px 8px;
-       font-size: 1.0625rem;
+       padding: 8px;
+       font-size: 1rem;
        transition: border-color 300ms ease;
        width: 100%;
 }
@@ -1059,12 +1040,12 @@ body.blur > :not(#help) {
 }
 
 .item-info .stab {
-       display: table;
+       display: inline-block;
 }
 .stab {
        padding: 3px;
        margin-bottom: 5px;
-       font-size: 0.9rem;
+       font-size: 0.875rem;
        font-weight: normal;
 }
 .stab p {
@@ -1072,7 +1053,7 @@ body.blur > :not(#help) {
 }
 
 .stab .emoji {
-       font-size: 1.2rem;
+       font-size: 1.25rem;
 }
 
 /* Black one-pixel outline around emoji shapes */
@@ -1088,10 +1069,10 @@ body.blur > :not(#help) {
 .import-item .stab {
        border-radius: 3px;
        display: inline-block;
-       font-size: 0.8rem;
+       font-size: 0.875rem;
        line-height: 1.2;
        margin-bottom: 0;
-       margin-left: .3em;
+       margin-left: 0.3125em;
        padding: 2px;
        vertical-align: text-bottom;
 }
@@ -1117,21 +1098,11 @@ body.blur > :not(#help) {
        font-weight: normal;
        font-size: 1rem;
 }
-.impl .srclink {
-       font-size: 1.0625rem;
-}
 
 .rightside {
        float: right;
 }
 
-.has-srclink {
-       font-size: 1rem;
-       margin-bottom: 12px;
-       /* Push the src link out to the right edge consistently */
-       justify-content: space-between;
-}
-
 .variants_table {
        width: 100%;
 }
@@ -1158,7 +1129,7 @@ a.test-arrow {
        position: absolute;
        padding: 5px 10px 5px 10px;
        border-radius: 5px;
-       font-size: 1.3rem;
+       font-size: 1.375rem;
        top: 5px;
        right: 5px;
        z-index: 1;
@@ -1169,16 +1140,6 @@ a.test-arrow {
 a.test-arrow:hover{
        text-decoration: none;
 }
-.section-header:hover a:before {
-       position: absolute;
-       left: -25px;
-       padding-right: 10px; /* avoid gap that causes hover to disappear */
-       content: '\2002\00a7\2002';
-}
-
-.section-header:hover a {
-       text-decoration: none;
-}
 
 .code-attribute {
        font-weight: 300;
@@ -1196,7 +1157,7 @@ a.test-arrow:hover{
 
 h3.variant {
        font-weight: 600;
-       font-size: 1.1rem;
+       font-size: 1.125rem;
        margin-bottom: 10px;
        border-bottom: none;
 }
@@ -1224,17 +1185,6 @@ h3.variant {
        margin-top: 3px;
 }
 
-.top-doc .docblock > .section-header:first-child {
-       margin-left: 15px;
-}
-.top-doc .docblock > .section-header:first-child:hover > a:before {
-       left: -10px;
-}
-
-.docblock > .section-header:first-child {
-       margin-top: 0;
-}
-
 :target > code, :target > .code-header {
        opacity: 1;
 }
@@ -1336,6 +1286,7 @@ h3.variant {
        margin-bottom: 13px;
        font-size: 1.1875rem;
        font-weight: 600;
+       display: block;
 }
 
 .notable-traits .docblock code.content{
@@ -1407,7 +1358,7 @@ pre.rust {
        left: 0;
        cursor: pointer;
        font-weight: bold;
-       font-size: 1.2rem;
+       font-size: 1.25rem;
        border-bottom: 1px solid;
        display: flex;
        height: 40px;
@@ -1532,12 +1483,9 @@ kbd {
 }
 .table-display .out-of-band {
        position: relative;
-       font-size: 1.1875rem;
+       font-size: 1.125rem;
        display: block;
 }
-#implementors-list > .impl-items .table-display .out-of-band {
-       font-size: 1.0625rem;
-}
 
 .table-display td:hover .anchor {
        display: block;
@@ -1578,7 +1526,7 @@ div.name.expand + .children {
 div.name::before {
        content: "\25B6";
        padding-left: 4px;
-       font-size: 0.7rem;
+       font-size: 0.625rem;
        position: absolute;
        left: -16px;
        top: 4px;
@@ -1611,8 +1559,8 @@ details.rustdoc-toggle > summary.hideme > span {
 details.rustdoc-toggle > summary::before {
        content: "";
        cursor: pointer;
-       width: 17px;
-       height: max(17px, 1.1em);
+       width: 16px;
+       height: 16px;
        background-repeat: no-repeat;
        background-position: top left;
        display: inline-block;
@@ -1659,7 +1607,7 @@ details.rustdoc-toggle > summary.hideme::before {
 details.rustdoc-toggle > summary:not(.hideme)::before {
        position: absolute;
        left: -24px;
-       top: 3px;
+       top: 4px;
 }
 
 .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before {
@@ -1696,8 +1644,8 @@ details.undocumented > summary::before, details.rustdoc-toggle > summary::before
 
 details.rustdoc-toggle[open] > summary::before,
 details.rustdoc-toggle[open] > summary.hideme::before {
-       width: 17px;
-       height: max(17px, 1.1em);
+       width: 16px;
+       height: 16px;
        background-repeat: no-repeat;
        background-position: top left;
        display: inline-block;
@@ -1824,12 +1772,15 @@ details.rustdoc-toggle[open] > summary.hideme::after {
                width: 0;
        }
 
+       .mobile-topbar .location a {
+               padding: 0;
+               margin: 0;
+       }
+
        .mobile-topbar .location {
                border: none;
-               margin: 0;
-               margin-left: auto;
-               padding: 0.3em;
-               padding-right: 0.6em;
+               padding: 0;
+               margin: auto 0.5em auto auto;
                text-overflow: ellipsis;
                overflow: hidden;
                white-space: nowrap;
@@ -1837,7 +1788,7 @@ details.rustdoc-toggle[open] > summary.hideme::after {
                   height is specified in pixels, this also has to be specified in
                   pixels to avoid overflowing the topbar when the user sets a bigger
                   font size. */
-               font-size: 22.4px;
+               font-size: 24px;
        }
 
        .mobile-topbar .logo-container {
@@ -2065,6 +2016,25 @@ details.rustdoc-toggle[open] > summary.hideme::after {
        }
 }
 
+.method-toggle summary,
+.implementors-toggle summary,
+.impl {
+       margin-bottom: 0.75em;
+}
+
+.method-toggle[open] {
+       margin-bottom: 2em;
+}
+
+.implementors-toggle[open]  {
+       margin-bottom: 2em;
+}
+
+#trait-implementations-list .method-toggle,
+#synthetic-implementations-list .method-toggle,
+#blanket-implementations-list .method-toggle {
+       margin-bottom: 1em;
+}
 
 /* Begin: styles for --scrape-examples feature */
 
index 0aaf4f78c34ef1ae18ce79f1c1669749558199a9..e402b3583f3996db04ceac724326a98bc2f2a20d 100644 (file)
@@ -91,7 +91,8 @@ pre, .rustdoc.source .example-wrap {
        background-color: #5c6773;
 }
 
-.sidebar .current {
+.sidebar .current,
+.sidebar a:hover {
        background-color: transparent;
        color: #ffb44c;
 }
@@ -104,15 +105,6 @@ pre, .rustdoc.source .example-wrap {
        color: #ff7733;
 }
 
-.sidebar-elems .location a {
-       color: #fff;
-}
-
-.block a:hover {
-       background: transparent;
-       color: #ffb44c;
-}
-
 .line-numbers span { color: #5c6773; }
 .line-numbers .line-highlighted {
        color: #708090;
@@ -220,6 +212,10 @@ pre.rust a,
 .in-band a {
        color: #c5c5c5;
 }
+.sidebar h2 a,
+.sidebar h3 a {
+       color: white;
+}
 .search-results a {
        color: #0096cf;
 }
index 4fad2359ff0eb66bbc5aa883fa2df8ecbbe5a8d3..0a56055b8cbf67367ff32262c74aefe88b8f29ea 100644 (file)
@@ -61,18 +61,15 @@ pre, .rustdoc.source .example-wrap {
        background-color: rgba(32, 34, 37, .6);
 }
 
-.sidebar .current {
-       background-color: #333;
+.sidebar .current,
+.sidebar a:hover {
+       background: #444;
 }
 
 .source .sidebar {
        background-color: #565656;
 }
 
-.block a:hover {
-       background: #444;
-}
-
 .line-numbers span { color: #3B91E2; }
 .line-numbers .line-highlighted {
        background-color: #0a042f !important;
index 16a777b7e672a58ef807ccbd5cc2ed0833e042c2..dc1715b2a78f33116cc183b8fef0b3683d224dd8 100644 (file)
@@ -63,7 +63,8 @@ pre, .rustdoc.source .example-wrap {
        background-color: rgba(36, 37, 39, 0.6);
 }
 
-.sidebar .current {
+.sidebar .current,
+.sidebar a:hover {
        background-color: #fff;
 }
 
@@ -71,10 +72,6 @@ pre, .rustdoc.source .example-wrap {
        background-color: #f1f1f1;
 }
 
-.block a:hover {
-       background: #F5F5F5;
-}
-
 .line-numbers span { color: #c67e2d; }
 .line-numbers .line-highlighted {
        background-color: #FDFFD3 !important;
index 3c21a96cef02a4b812815bfd6db9f42de60e1e56..8e1919f75d671512149b1efdba9247121f2984ec 100644 (file)
@@ -54,7 +54,6 @@ function resourcePath(basename, extension) {
     return getVar("root-path") + basename + getVar("resource-suffix") + extension;
 }
 
-
 (function () {
     window.rootPath = getVar("root-path");
     window.currentCrate = getVar("current-crate");
@@ -232,7 +231,7 @@ function hideThemeButtonState() {
             document.title = searchState.titleBeforeSearch;
             // We also remove the query parameter from the URL.
             if (searchState.browserSupportsHistoryApi()) {
-                history.replaceState("", window.currentCrate + " - Rust",
+                history.replaceState(null, window.currentCrate + " - Rust",
                     getNakedUrl() + window.location.hash);
             }
         },
@@ -246,18 +245,6 @@ function hideThemeButtonState() {
                 });
             return params;
         },
-        putBackSearch: function(search_input) {
-            var search = searchState.outputElement();
-            if (search_input.value !== "" && hasClass(search, "hidden")) {
-                searchState.showResults(search);
-                if (searchState.browserSupportsHistoryApi()) {
-                    var extra = "?search=" + encodeURIComponent(search_input.value);
-                    history.replaceState(search_input.value, "",
-                        getNakedUrl() + extra + window.location.hash);
-                }
-                document.title = searchState.title;
-            }
-        },
         browserSupportsHistoryApi: function() {
             return window.history && typeof window.history.pushState === "function";
         },
@@ -282,14 +269,10 @@ function hideThemeButtonState() {
             }
 
             search_input.addEventListener("focus", function() {
-                searchState.putBackSearch(this);
-                search_input.origPlaceholder = searchState.input.placeholder;
+                search_input.origPlaceholder = search_input.placeholder;
                 search_input.placeholder = "Type your search here.";
                 loadSearch();
             });
-            search_input.addEventListener("blur", function() {
-                search_input.placeholder = searchState.input.origPlaceholder;
-            });
 
             if (search_input.value != '') {
                 loadSearch();
@@ -330,7 +313,7 @@ function hideThemeButtonState() {
             var hash = ev.newURL.slice(ev.newURL.indexOf("#") + 1);
             if (searchState.browserSupportsHistoryApi()) {
                 // `window.location.search`` contains all the query parameters, not just `search`.
-                history.replaceState(hash, "",
+                history.replaceState(null, "",
                     getNakedUrl() + window.location.search + "#" + hash);
             }
             elem = document.getElementById(hash);
@@ -576,7 +559,15 @@ function hideThemeButtonState() {
             others.appendChild(div);
         }
 
-        function block(shortty, longty) {
+        /**
+         * Append to the sidebar a "block" of links - a heading along with a list (`<ul>`) of items.
+         *
+         * @param {string} shortty - A short type name, like "primitive", "mod", or "macro"
+         * @param {string} id - The HTML id of the corresponding section on the module page.
+         * @param {string} longty - A long, capitalized, plural name, like "Primitive Types",
+         *                          "Modules", or "Macros".
+         */
+        function block(shortty, id, longty) {
             var filtered = items[shortty];
             if (!filtered) {
                 return;
@@ -585,7 +576,7 @@ function hideThemeButtonState() {
             var div = document.createElement("div");
             div.className = "block " + shortty;
             var h3 = document.createElement("h3");
-            h3.textContent = longty;
+            h3.innerHTML = `<a href="index.html#${id}">${longty}</a>`;
             div.appendChild(h3);
             var ul = document.createElement("ul");
 
@@ -624,20 +615,20 @@ function hideThemeButtonState() {
 
             var isModule = hasClass(document.body, "mod");
             if (!isModule) {
-                block("primitive", "Primitive Types");
-                block("mod", "Modules");
-                block("macro", "Macros");
-                block("struct", "Structs");
-                block("enum", "Enums");
-                block("union", "Unions");
-                block("constant", "Constants");
-                block("static", "Statics");
-                block("trait", "Traits");
-                block("fn", "Functions");
-                block("type", "Type Definitions");
-                block("foreigntype", "Foreign Types");
-                block("keyword", "Keywords");
-                block("traitalias", "Trait Aliases");
+                block("primitive", "primitives", "Primitive Types");
+                block("mod", "modules", "Modules");
+                block("macro", "macros", "Macros");
+                block("struct", "structs", "Structs");
+                block("enum", "enums", "Enums");
+                block("union", "unions", "Unions");
+                block("constant", "constants", "Constants");
+                block("static", "static", "Statics");
+                block("trait", "traits", "Traits");
+                block("fn", "functions", "Functions");
+                block("type", "types", "Type Definitions");
+                block("foreigntype", "foreign-types", "Foreign Types");
+                block("keyword", "keywords", "Keywords");
+                block("traitalias", "trait-aliases", "Trait Aliases");
             }
 
             // `crates{version}.js` should always be loaded before this script, so we can use
index 104464b3881147a476802deb439b6bcf6ac5e274..b0ce63a4ec1d5d7177feacb2d84198642d807ce5 100644 (file)
@@ -1,5 +1,5 @@
 /* global addClass, getNakedUrl, getSettingValue, hasOwnPropertyRustdoc, initSearch, onEach */
-/* global onEachLazy, removeClass, searchState, updateLocalStorage */
+/* global onEachLazy, removeClass, searchState, hasClass */
 
 (function() {
 // This mapping table should match the discriminants of
@@ -133,6 +133,39 @@ window.initSearch = function(rawSearchIndex) {
         searchState.input.value = params.search || "";
     }
 
+    /**
+     * Build an URL with search parameters.
+     *
+     * @param {string} search            - The current search being performed.
+     * @param {string|null} filterCrates - The current filtering crate (if any).
+     * @return {string}
+     */
+    function buildUrl(search, filterCrates) {
+        var extra = "?search=" + encodeURIComponent(search);
+
+        if (filterCrates !== null) {
+            extra += "&filter-crate=" + encodeURIComponent(filterCrates);
+        }
+        return getNakedUrl() + extra + window.location.hash;
+    }
+
+    /**
+     * Return the filtering crate or `null` if there is none.
+     *
+     * @return {string|null}
+     */
+    function getFilterCrates() {
+        var elem = document.getElementById("crate-search");
+
+        if (elem &&
+            elem.value !== "All crates" &&
+            hasOwnPropertyRustdoc(rawSearchIndex, elem.value))
+        {
+            return elem.value;
+        }
+        return null;
+    }
+
     /**
      * Executes the query and returns a list of results for each results tab.
      * @param  {Object}        query          - The user query
@@ -554,11 +587,8 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         function typePassesFilter(filter, type) {
-            // No filter
-            if (filter <= NO_TYPE_FILTER) return true;
-
-            // Exact match
-            if (filter === type) return true;
+            // No filter or Exact mach
+            if (filter <= NO_TYPE_FILTER || filter === type) return true;
 
             // Match related items
             var name = itemTypes[type];
@@ -595,7 +625,7 @@ window.initSearch = function(rawSearchIndex) {
             // aliases to be before the others in the displayed results.
             var aliases = [];
             var crateAliases = [];
-            if (filterCrates !== undefined) {
+            if (filterCrates !== null) {
                 if (ALIASES[filterCrates] && ALIASES[filterCrates][query.search]) {
                     var query_aliases = ALIASES[filterCrates][query.search];
                     var len = query_aliases.length;
@@ -694,7 +724,7 @@ window.initSearch = function(rawSearchIndex) {
         {
             val = extractGenerics(val.substr(1, val.length - 2));
             for (i = 0; i < nSearchWords; ++i) {
-                if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
+                if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
                     continue;
                 }
                 in_args = findArg(searchIndex[i], val, true, typeFilter);
@@ -725,7 +755,7 @@ window.initSearch = function(rawSearchIndex) {
             var output = extractGenerics(parts[1]);
 
             for (i = 0; i < nSearchWords; ++i) {
-                if (filterCrates !== undefined && searchIndex[i].crate !== filterCrates) {
+                if (filterCrates !== null && searchIndex[i].crate !== filterCrates) {
                     continue;
                 }
                 var type = searchIndex[i].type;
@@ -781,7 +811,7 @@ window.initSearch = function(rawSearchIndex) {
             var lev, j;
             for (j = 0; j < nSearchWords; ++j) {
                 ty = searchIndex[j];
-                if (!ty || (filterCrates !== undefined && ty.crate !== filterCrates)) {
+                if (!ty || (filterCrates !== null && ty.crate !== filterCrates)) {
                     continue;
                 }
                 var lev_add = 0;
@@ -1167,110 +1197,19 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     function execSearch(query, searchWords, filterCrates) {
-        function getSmallest(arrays, positions, notDuplicates) {
-            var start = null;
-
-            for (var it = 0, len = positions.length; it < len; ++it) {
-                if (arrays[it].length > positions[it] &&
-                    (start === null || start > arrays[it][positions[it]].lev) &&
-                    !notDuplicates[arrays[it][positions[it]].fullPath]) {
-                    start = arrays[it][positions[it]].lev;
-                }
-            }
-            return start;
-        }
-
-        function mergeArrays(arrays) {
-            var ret = [];
-            var positions = [];
-            var notDuplicates = {};
-
-            for (var x = 0, arrays_len = arrays.length; x < arrays_len; ++x) {
-                positions.push(0);
-            }
-            while (ret.length < MAX_RESULTS) {
-                var smallest = getSmallest(arrays, positions, notDuplicates);
-
-                if (smallest === null) {
-                    break;
-                }
-                for (x = 0; x < arrays_len && ret.length < MAX_RESULTS; ++x) {
-                    if (arrays[x].length > positions[x] &&
-                            arrays[x][positions[x]].lev === smallest &&
-                            !notDuplicates[arrays[x][positions[x]].fullPath]) {
-                        ret.push(arrays[x][positions[x]]);
-                        notDuplicates[arrays[x][positions[x]].fullPath] = true;
-                        positions[x] += 1;
-                    }
-                }
-            }
-            return ret;
-        }
-
-        // Split search query by ",", while respecting angle bracket nesting.
-        // Since "<" is an alias for the Ord family of traits, it also uses
-        // lookahead to distinguish "<"-as-less-than from "<"-as-angle-bracket.
-        //
-        // tokenizeQuery("A<B, C>, D") == ["A<B, C>", "D"]
-        // tokenizeQuery("A<B, C, D") == ["A<B", "C", "D"]
-        function tokenizeQuery(raw) {
-            var i, matched;
-            var l = raw.length;
-            var depth = 0;
-            var nextAngle = /(<|>)/g;
-            var ret = [];
-            var start = 0;
-            for (i = 0; i < l; ++i) {
-                switch (raw[i]) {
-                    case "<":
-                        nextAngle.lastIndex = i + 1;
-                        matched = nextAngle.exec(raw);
-                        if (matched && matched[1] === '>') {
-                            depth += 1;
-                        }
-                        break;
-                    case ">":
-                        if (depth > 0) {
-                            depth -= 1;
-                        }
-                        break;
-                    case ",":
-                        if (depth === 0) {
-                            ret.push(raw.substring(start, i));
-                            start = i + 1;
-                        }
-                        break;
-                }
-            }
-            if (start !== i) {
-                ret.push(raw.substring(start, i));
-            }
-            return ret;
-        }
-
-        var queries = tokenizeQuery(query.raw);
+        query = query.raw.trim();
         var results = {
             "in_args": [],
             "returned": [],
             "others": [],
         };
 
-        for (var i = 0, len = queries.length; i < len; ++i) {
-            query = queries[i].trim();
-            if (query.length !== 0) {
-                var tmp = execQuery(getQuery(query), searchWords, filterCrates);
+        if (query.length !== 0) {
+            var tmp = execQuery(getQuery(query), searchWords, filterCrates);
 
-                results.in_args.push(tmp.in_args);
-                results.returned.push(tmp.returned);
-                results.others.push(tmp.others);
-            }
-        }
-        if (queries.length > 1) {
-            return {
-                "in_args": mergeArrays(results.in_args),
-                "returned": mergeArrays(results.returned),
-                "others": mergeArrays(results.others),
-            };
+            results.in_args.push(tmp.in_args);
+            results.returned.push(tmp.returned);
+            results.others.push(tmp.others);
         }
         return {
             "in_args": results.in_args[0],
@@ -1279,17 +1218,6 @@ window.initSearch = function(rawSearchIndex) {
         };
     }
 
-    function getFilterCrates() {
-        var elem = document.getElementById("crate-search");
-
-        if (elem && elem.value !== "All crates" &&
-            hasOwnPropertyRustdoc(rawSearchIndex, elem.value))
-        {
-            return elem.value;
-        }
-        return undefined;
-    }
-
     /**
      * Perform a search based on the current state of the search input element
      * and display the results.
@@ -1309,27 +1237,34 @@ window.initSearch = function(rawSearchIndex) {
         }
         if (!forced && query.id === currentResults) {
             if (query.query.length > 0) {
-                searchState.putBackSearch(searchState.input);
+                putBackSearch();
             }
             return;
         }
 
+        var filterCrates = getFilterCrates();
+
+        // In case we have no information about the saved crate and there is a URL query parameter,
+        // we override it with the URL query parameter.
+        if (filterCrates === null && params["filter-crate"] !== undefined) {
+            filterCrates = params["filter-crate"];
+        }
+
         // Update document title to maintain a meaningful browser history
         searchState.title = "Results for " + query.query + " - Rust";
 
         // Because searching is incremental by character, only the most
         // recent search query is added to the browser history.
         if (searchState.browserSupportsHistoryApi()) {
-            var newURL = getNakedUrl() + "?search=" + encodeURIComponent(query.raw) +
-                window.location.hash;
+            var newURL = buildUrl(query.raw, filterCrates);
+
             if (!history.state && !params.search) {
-                history.pushState(query, "", newURL);
+                history.pushState(null, "", newURL);
             } else {
-                history.replaceState(query, "", newURL);
+                history.replaceState(null, "", newURL);
             }
         }
 
-        var filterCrates = getFilterCrates();
         showResults(execSearch(query, searchWords, filterCrates),
             params["go_to_first"], filterCrates);
     }
@@ -1495,12 +1430,28 @@ window.initSearch = function(rawSearchIndex) {
         search();
     }
 
+    function putBackSearch() {
+        var search_input = searchState.input;
+        if (!searchState.input) {
+            return;
+        }
+        var search = searchState.outputElement();
+        if (search_input.value !== "" && hasClass(search, "hidden")) {
+            searchState.showResults(search);
+            if (searchState.browserSupportsHistoryApi()) {
+                history.replaceState(null, "",
+                    buildUrl(search_input.value, getFilterCrates()));
+            }
+            document.title = searchState.title;
+        }
+    }
+
     function registerSearchEvents() {
         var searchAfter500ms = function() {
             searchState.clearInputTimeout();
             if (searchState.input.value.length === 0) {
                 if (searchState.browserSupportsHistoryApi()) {
-                    history.replaceState("", window.currentCrate + " - Rust",
+                    history.replaceState(null, window.currentCrate + " - Rust",
                         getNakedUrl() + window.location.hash);
                 }
                 searchState.hideResults();
@@ -1567,6 +1518,14 @@ window.initSearch = function(rawSearchIndex) {
             }
         });
 
+        searchState.input.addEventListener("focus", function() {
+            putBackSearch();
+        });
+
+        searchState.input.addEventListener("blur", function() {
+            searchState.input.placeholder = searchState.input.origPlaceholder;
+        });
+
         // Push and pop states are used to add search results to the browser
         // history.
         if (searchState.browserSupportsHistoryApi()) {
@@ -1619,7 +1578,16 @@ window.initSearch = function(rawSearchIndex) {
     }
 
     function updateCrate(ev) {
-        updateLocalStorage("rustdoc-saved-filter-crate", ev.target.value);
+        if (ev.target.value === "All crates") {
+            // If we don't remove it from the URL, it'll be picked up again by the search.
+            var params = searchState.getQueryStringParams();
+            var query = searchState.input.value.trim();
+            if (!history.state && !params.search) {
+                history.pushState(null, "", buildUrl(query, null));
+            } else {
+                history.replaceState(null, "", buildUrl(query, null));
+            }
+        }
         // In case you "cut" the entry from the search input, then change the crate filter
         // before paste back the previous search, you get the old search results without
         // the filter. To prevent this, we need to remove the previous results.
@@ -1629,10 +1597,15 @@ window.initSearch = function(rawSearchIndex) {
 
     searchWords = buildIndex(rawSearchIndex);
     registerSearchEvents();
-    // If there's a search term in the URL, execute the search now.
-    if (searchState.getQueryStringParams().search) {
-        search();
+
+    function runSearchIfNeeded() {
+        // If there's a search term in the URL, execute the search now.
+        if (searchState.getQueryStringParams().search) {
+            search();
+        }
     }
+
+    runSearchIfNeeded();
 };
 
 if (window.searchIndex !== undefined) {
index 47a8fcdfd5ecf29c5f7f6223a8691debc0b7928a..139fa5c9a11a62e4db3586a604a1dd849c7a729c 100644 (file)
@@ -4,7 +4,7 @@
 
 (function () {
     function changeSetting(settingName, value) {
-        updateLocalStorage("rustdoc-" + settingName, value);
+        updateLocalStorage(settingName, value);
 
         switch (settingName) {
             case "theme":
index 498f60e9f25ae4fd601dd22087421667209c8493..90490acccfdb5714a79994d19f8582e5febe2476 100644 (file)
@@ -82,11 +82,11 @@ function toggleSidebar() {
     if (child.innerText === ">") {
         sidebar.classList.add("expanded");
         child.innerText = "<";
-        updateLocalStorage("rustdoc-source-sidebar-show", "true");
+        updateLocalStorage("source-sidebar-show", "true");
     } else {
         sidebar.classList.remove("expanded");
         child.innerText = ">";
-        updateLocalStorage("rustdoc-source-sidebar-show", "false");
+        updateLocalStorage("source-sidebar-show", "false");
     }
 }
 
@@ -97,7 +97,7 @@ function createSidebarToggle() {
 
     var inner = document.createElement("div");
 
-    if (getCurrentValue("rustdoc-source-sidebar-show") === "true") {
+    if (getCurrentValue("source-sidebar-show") === "true") {
         inner.innerText = "<";
     } else {
         inner.innerText = ">";
@@ -120,7 +120,7 @@ function createSourceSidebar() {
 
     var sidebar = document.createElement("div");
     sidebar.id = "source-sidebar";
-    if (getCurrentValue("rustdoc-source-sidebar-show") !== "true") {
+    if (getCurrentValue("source-sidebar-show") !== "true") {
         container.classList.remove("expanded");
     } else {
         container.classList.add("expanded");
index 06bb34eb11573c70165dcd4f8a8a8584e7154377..ccf3d0a581a171e3fd4dc5e59fd981db5e1a3b25 100644 (file)
@@ -15,7 +15,7 @@ var settingsDataset = (function () {
 })();
 
 function getSettingValue(settingName) {
-    var current = getCurrentValue('rustdoc-' + settingName);
+    var current = getCurrentValue(settingName);
     if (current !== null) {
         return current;
     }
@@ -106,7 +106,7 @@ function hasOwnPropertyRustdoc(obj, property) {
 
 function updateLocalStorage(name, value) {
     try {
-        window.localStorage.setItem(name, value);
+        window.localStorage.setItem("rustdoc-" + name, value);
     } catch(e) {
         // localStorage is not accessible, do nothing
     }
@@ -114,7 +114,7 @@ function updateLocalStorage(name, value) {
 
 function getCurrentValue(name) {
     try {
-        return window.localStorage.getItem(name);
+        return window.localStorage.getItem("rustdoc-" + name);
     } catch(e) {
         return null;
     }
@@ -127,7 +127,7 @@ function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
     // If this new value comes from a system setting or from the previously
     // saved theme, no need to save it.
     if (saveTheme) {
-        updateLocalStorage("rustdoc-theme", newTheme);
+        updateLocalStorage("theme", newTheme);
     }
 
     if (styleElem.href === newHref) {
@@ -158,7 +158,7 @@ function useSystemTheme(value) {
         value = true;
     }
 
-    updateLocalStorage("rustdoc-use-system-theme", value);
+    updateLocalStorage("use-system-theme", value);
 
     // update the toggle if we're on the settings page
     var toggle = document.getElementById("use-system-theme");
@@ -231,7 +231,7 @@ if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
     if (getSettingValue("use-system-theme") === null
         && getSettingValue("preferred-dark-theme") === null
         && darkThemes.indexOf(localStoredTheme) >= 0) {
-        updateLocalStorage("rustdoc-preferred-dark-theme", localStoredTheme);
+        updateLocalStorage("preferred-dark-theme", localStoredTheme);
     }
 
     // call the function to initialize the theme at least once!
index a7c3c0bb606102532413f59fe416c3c59d0cf9c3..170f166db500e0d090873b227c7cc1280bc05ce0 100644 (file)
@@ -5,6 +5,7 @@
 #![feature(rustc_private)]
 #![feature(array_methods)]
 #![feature(assert_matches)]
+#![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(box_syntax)]
@@ -687,10 +688,9 @@ fn main_args(at_args: &[String]) -> MainResult {
         Ok(opts) => opts,
         Err(code) => return if code == 0 { Ok(()) } else { Err(ErrorReported) },
     };
-    rustc_interface::util::setup_callbacks_and_run_in_thread_pool_with_globals(
+    rustc_interface::util::run_in_thread_pool_with_globals(
         options.edition,
         1, // this runs single-threaded, even in a parallel compiler
-        &None,
         move || main_options(options),
     )
 }
index 86662ebaaca215505d5baaddb3de1bd8b7a45306..33a1530d588efc031e8af5254abdaffe75d0f7ba 100644 (file)
@@ -2,10 +2,8 @@
 //!
 //! [RFC 1946]: https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md
 
-use rustc_ast as ast;
 use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet};
 use rustc_errors::{Applicability, DiagnosticBuilder};
-use rustc_expand::base::SyntaxExtensionKind;
 use rustc_hir::def::{
     DefKind,
     Namespace::{self, *},
@@ -14,7 +12,6 @@
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_ID};
 use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug, ty};
-use rustc_resolve::ParentScope;
 use rustc_session::lint::Lint;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{sym, Ident, Symbol};
@@ -486,23 +483,9 @@ fn resolve_macro(
         path_str: &'a str,
         module_id: DefId,
     ) -> Result<Res, ResolutionFailure<'a>> {
-        let path = ast::Path::from_ident(Ident::from_str(path_str));
         self.cx.enter_resolver(|resolver| {
-            // FIXME(jynelson): does this really need 3 separate lookups?
-            if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
-                &path,
-                None,
-                &ParentScope::module(resolver.graph_root(), resolver),
-                false,
-                false,
-            ) {
-                if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind {
-                    return Ok(res.try_into().unwrap());
-                }
-            }
-            if let Some(&res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
-                return Ok(res.try_into().unwrap());
-            }
+            // NOTE: this needs 2 separate lookups because `resolve_str_path_error` doesn't take
+            // lexical scope into account (it ignores all macros not defined at the mod-level)
             debug!("resolving {} as a macro in the module {:?}", path_str, module_id);
             if let Ok((_, res)) =
                 resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id)
@@ -512,6 +495,9 @@ fn resolve_macro(
                     return Ok(res);
                 }
             }
+            if let Some(&res) = resolver.all_macros().get(&Symbol::intern(path_str)) {
+                return Ok(res.try_into().unwrap());
+            }
             Err(ResolutionFailure::NotResolved {
                 module_id,
                 partial_res: None,
@@ -1240,9 +1226,7 @@ fn resolve_link(
         let base_node =
             if item.is_mod() && inner_docs { self.mod_ids.last().copied() } else { parent_node };
 
-        let mut module_id = if let Some(id) = base_node {
-            id
-        } else {
+        let Some(mut module_id) = base_node else {
             // This is a bug.
             debug!("attempting to resolve item without parent module: {}", path_str);
             resolution_failure(
@@ -1991,9 +1975,7 @@ fn split(path: &str) -> Option<(&str, &str)> {
                     // If so, report it and say the first which failed; if not, say the first path segment didn't resolve.
                     let mut name = path_str;
                     'outer: loop {
-                        let (start, end) = if let Some(x) = split(name) {
-                            x
-                        } else {
+                        let Some((start, end)) = split(name) else {
                             // avoid bug that marked [Quux::Z] as missing Z, not Quux
                             if partial_res.is_none() {
                                 *unresolved = name.into();
index edd4e9da66d99043010da3582f9a6163278b457d..5c11ab1d3beb929a4304daafc0ae191d3e5af906 100644 (file)
@@ -116,6 +116,9 @@ fn add_foreign_traits_in_scope(&mut self) {
             let all_traits = Vec::from_iter(self.resolver.cstore().traits_in_crate_untracked(cnum));
             let all_trait_impls =
                 Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum));
+            let all_inherent_impls =
+                Vec::from_iter(self.resolver.cstore().inherent_impls_in_crate_untracked(cnum));
+            let all_lang_items = Vec::from_iter(self.resolver.cstore().lang_items_untracked(cnum));
 
             // Querying traits in scope is expensive so we try to prune the impl and traits lists
             // using privacy, private traits and impls from other crates are never documented in
@@ -134,6 +137,14 @@ fn add_foreign_traits_in_scope(&mut self) {
                     self.add_traits_in_parent_scope(impl_def_id);
                 }
             }
+            for (ty_def_id, impl_def_id) in all_inherent_impls {
+                if self.resolver.cstore().visibility_untracked(ty_def_id) == Visibility::Public {
+                    self.add_traits_in_parent_scope(impl_def_id);
+                }
+            }
+            for def_id in all_lang_items {
+                self.add_traits_in_parent_scope(def_id);
+            }
 
             self.all_traits.extend(all_traits);
             self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(_, def_id, _)| def_id));
index f7a9a0899e390281e1f9faf705bec3da84c5fe8f..9caadef3dec7c92c371a3600fed3c9fc4eeaaadd 100644 (file)
@@ -38,7 +38,7 @@ fn drop_tag(
     tags: &mut Vec<(String, Range<usize>)>,
     tag_name: String,
     range: Range<usize>,
-    f: &impl Fn(&str, &Range<usize>),
+    f: &impl Fn(&str, &Range<usize>, bool),
 ) {
     let tag_name_low = tag_name.to_lowercase();
     if let Some(pos) = tags.iter().rposition(|(t, _)| t.to_lowercase() == tag_name_low) {
@@ -59,14 +59,42 @@ fn drop_tag(
             // `tags` is used as a queue, meaning that everything after `pos` is included inside it.
             // So `<h2><h3></h2>` will look like `["h2", "h3"]`. So when closing `h2`, we will still
             // have `h3`, meaning the tag wasn't closed as it should have.
-            f(&format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span);
+            f(&format!("unclosed HTML tag `{}`", last_tag_name), &last_tag_span, true);
         }
         // Remove the `tag_name` that was originally closed
         tags.pop();
     } else {
         // It can happen for example in this case: `<h2></script></h2>` (the `h2` tag isn't required
         // but it helps for the visualization).
-        f(&format!("unopened HTML tag `{}`", tag_name), &range);
+        f(&format!("unopened HTML tag `{}`", tag_name), &range, false);
+    }
+}
+
+fn extract_path_backwards(text: &str, end_pos: usize) -> Option<usize> {
+    use rustc_lexer::{is_id_continue, is_id_start};
+    let mut current_pos = end_pos;
+    loop {
+        if current_pos >= 2 && text[..current_pos].ends_with("::") {
+            current_pos -= 2;
+        }
+        let new_pos = text[..current_pos]
+            .char_indices()
+            .rev()
+            .take_while(|(_, c)| is_id_start(*c) || is_id_continue(*c))
+            .reduce(|_accum, item| item)
+            .and_then(|(new_pos, c)| is_id_start(c).then_some(new_pos));
+        if let Some(new_pos) = new_pos {
+            if current_pos != new_pos {
+                current_pos = new_pos;
+                continue;
+            }
+        }
+        break;
+    }
+    if current_pos == end_pos {
+        return None;
+    } else {
+        return Some(current_pos);
     }
 }
 
@@ -76,7 +104,7 @@ fn extract_html_tag(
     range: &Range<usize>,
     start_pos: usize,
     iter: &mut Peekable<CharIndices<'_>>,
-    f: &impl Fn(&str, &Range<usize>),
+    f: &impl Fn(&str, &Range<usize>, bool),
 ) {
     let mut tag_name = String::new();
     let mut is_closing = false;
@@ -140,7 +168,7 @@ fn extract_tags(
     text: &str,
     range: Range<usize>,
     is_in_comment: &mut Option<Range<usize>>,
-    f: &impl Fn(&str, &Range<usize>),
+    f: &impl Fn(&str, &Range<usize>, bool),
 ) {
     let mut iter = text.char_indices().peekable();
 
@@ -178,14 +206,42 @@ fn visit_item(&mut self, item: &Item) {
         };
         let dox = item.attrs.collapsed_doc_value().unwrap_or_default();
         if !dox.is_empty() {
-            let report_diag = |msg: &str, range: &Range<usize>| {
+            let report_diag = |msg: &str, range: &Range<usize>, is_open_tag: bool| {
                 let sp = match super::source_span_for_markdown_range(tcx, &dox, range, &item.attrs)
                 {
                     Some(sp) => sp,
                     None => item.attr_span(tcx),
                 };
                 tcx.struct_span_lint_hir(crate::lint::INVALID_HTML_TAGS, hir_id, sp, |lint| {
-                    lint.build(msg).emit()
+                    use rustc_lint_defs::Applicability;
+                    let mut diag = lint.build(msg);
+                    // If a tag looks like `<this>`, it might actually be a generic.
+                    // We don't try to detect stuff `<like, this>` because that's not valid HTML,
+                    // and we don't try to detect stuff `<like this>` because that's not valid Rust.
+                    if let Some(Some(generics_start)) = (is_open_tag
+                        && dox[..range.end].ends_with(">"))
+                    .then(|| extract_path_backwards(&dox, range.start))
+                    {
+                        let generics_sp = match super::source_span_for_markdown_range(
+                            tcx,
+                            &dox,
+                            &(generics_start..range.end),
+                            &item.attrs,
+                        ) {
+                            Some(sp) => sp,
+                            None => item.attr_span(tcx),
+                        };
+                        // multipart form is chosen here because ``Vec<i32>`` would be confusing.
+                        diag.multipart_suggestion(
+                            "try marking as source code",
+                            vec![
+                                (generics_sp.shrink_to_lo(), String::from("`")),
+                                (generics_sp.shrink_to_hi(), String::from("`")),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    diag.emit()
                 });
             };
 
@@ -210,11 +266,11 @@ fn visit_item(&mut self, item: &Item) {
                 let t = t.to_lowercase();
                 !ALLOWED_UNCLOSED.contains(&t.as_str())
             }) {
-                report_diag(&format!("unclosed HTML tag `{}`", tag), range);
+                report_diag(&format!("unclosed HTML tag `{}`", tag), range, true);
             }
 
             if let Some(range) = is_in_comment {
-                report_diag("Unclosed HTML comment", &range);
+                report_diag("Unclosed HTML comment", &range, false);
             }
         }
 
index 899c9e4c62956cb3ec4b385501de85ee730c76a4..f9e91c299eabb32bb398519ad3bdf385f11dd0cb 100644 (file)
@@ -152,9 +152,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
             }
             hir::ExprKind::MethodCall(_, _, span) => {
                 let types = tcx.typeck(ex.hir_id.owner);
-                let def_id = if let Some(def_id) = types.type_dependent_def_id(ex.hir_id) {
-                    def_id
-                } else {
+                let Some(def_id) = types.type_dependent_def_id(ex.hir_id) else {
                     trace!("type_dependent_def_id({}) = None", ex.hir_id);
                     return;
                 };
@@ -196,7 +194,8 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
                 return;
             }
 
-            let file = tcx.sess.source_map().lookup_char_pos(span.lo()).file;
+            let source_map = tcx.sess.source_map();
+            let file = source_map.lookup_char_pos(span.lo()).file;
             let file_path = match file.name.clone() {
                 FileName::Real(real_filename) => real_filename.into_local_path(),
                 _ => None,
@@ -217,6 +216,8 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
                 let fn_entries = self.calls.entry(fn_key).or_default();
 
                 trace!("Including expr: {:?}", span);
+                let enclosing_item_span =
+                    source_map.span_extend_to_prev_char(enclosing_item_span, '\n', false);
                 let location = CallLocation::new(span, enclosing_item_span, &file);
                 fn_entries.entry(abs_path).or_insert_with(mk_call_data).locations.push(location);
             }
@@ -247,8 +248,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         let target_crates = options
             .target_crates
             .into_iter()
-            .map(|target| all_crates.iter().filter(move |(_, name)| name.as_str() == target))
-            .flatten()
+            .flat_map(|target| all_crates.iter().filter(move |(_, name)| name.as_str() == target))
             .map(|(crate_num, _)| **crate_num)
             .collect::<Vec<_>>();
 
index 2cbb3324a5e0499051584b0e1281f6e86061f26b..e8b3a0929db61c3022a9c6e5160f07d006b9256c 100644 (file)
@@ -188,9 +188,7 @@ fn maybe_inline_local(
         debug!("maybe_inline_local res: {:?}", res);
 
         let tcx = self.cx.tcx;
-        let res_did = if let Some(did) = res.opt_def_id() {
-            did
-        } else {
+        let Some(res_did) = res.opt_def_id() else {
             return false;
         };
 
index b6b46f596a7d2523ee1acd1c00e699615849da60..e29ac13bc97e26f886c3bfe72f9135e994c3cd0a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b6b46f596a7d2523ee1acd1c00e699615849da60
+Subproject commit e29ac13bc97e26f886c3bfe72f9135e994c3cd0a
diff --git a/src/test/codegen/cf-protection.rs b/src/test/codegen/cf-protection.rs
new file mode 100644 (file)
index 0000000..ccbc863
--- /dev/null
@@ -0,0 +1,38 @@
+// Test that the correct module flags are emitted with different control-flow protection flags.
+
+// revisions: undefined none branch return full
+// needs-llvm-components: x86
+// [undefined] compile-flags:
+// [none] compile-flags: -Z cf-protection=none
+// [branch] compile-flags: -Z cf-protection=branch
+// [return] compile-flags: -Z cf-protection=return
+// [full] compile-flags: -Z cf-protection=full
+// compile-flags: --target x86_64-unknown-linux-gnu
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized { }
+
+// A basic test function.
+pub fn test() {
+}
+
+// undefined-NOT: !"cf-protection-branch"
+// undefined-NOT: !"cf-protection-return"
+
+// none-NOT: !"cf-protection-branch"
+// none-NOT: !"cf-protection-return"
+
+// branch-NOT: !"cf-protection-return"
+// branch: !"cf-protection-branch", i32 1
+// branch-NOT: !"cf-protection-return"
+
+// return-NOT: !"cf-protection-branch"
+// return: !"cf-protection-return", i32 1
+// return-NOT: !"cf-protection-branch"
+
+// full: !"cf-protection-branch", i32 1
+// full: !"cf-protection-return", i32 1
index 35fd275fd28975bd2ab9beb034a2c936da1ccbf9..b9cb4f93d07d8159e8a4016380a6a140a8793620 100644 (file)
@@ -9,19 +9,41 @@
 // compile-flags: -Cdebuginfo=2 -Copt-level=0 -Csymbol-mangling-version=v0
 // ignore-tidy-linelength
 
+// NONMSVC: ![[USIZE:[0-9]+]] = !DIBasicType(name: "usize"
+// MSVC: ![[USIZE:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "usize"
+// NONMSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()"
+// MSVC: ![[PTR:[0-9]+]] = !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$<tuple$<> >"
+
 // NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTrait>::{vtable}"
 // MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTrait>::vtable$"
-// NONMSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "*const ()",
-// MSVC: !DIDerivedType(tag: DW_TAG_pointer_type, name: "ptr_const$<tuple$<> >",
-// CHECK: !DISubrange(count: 5
+
+// NONMSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "<debug_vtable::Foo as debug_vtable::SomeTrait>::{vtable_type}", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]],
+// MSVC: ![[VTABLE_TY0:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$<debug_vtable::Foo, debug_vtable::SomeTrait>::vtable_type$", {{.*}} size: {{320|160}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}} vtableHolder: ![[FOO_TYPE:[0-9]+]],
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method4", scope: ![[VTABLE_TY0]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{256|128}})
+// CHECK: ![[FOO_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Foo",
 
 // NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as debug_vtable::SomeTraitWithGenerics<u64, i8>>::{vtable}"
 // MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, debug_vtable::SomeTraitWithGenerics<u64,i8> >::vtable$"
-// CHECK: !DISubrange(count: 4
+
+// NONMSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "<debug_vtable::Foo as debug_vtable::SomeTraitWithGenerics<u64, i8>>::{vtable_type}", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
+// MSVC: ![[VTABLE_TY1:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$<debug_vtable::Foo, debug_vtable::SomeTraitWithGenerics<u64,i8> >::vtable_type$", {{.*}}, size: {{256|128}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__method3", scope: ![[VTABLE_TY1]], {{.*}} baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}}, offset: {{192|96}})
 
 // NONMSVC: !DIGlobalVariable(name: "<debug_vtable::Foo as _>::{vtable}"
 // MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::Foo, _>::vtable$"
-// CHECK: !DISubrange(count: 3
+
+// NONMSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "<debug_vtable::Foo as _>::{vtable_type}", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
+// MSVC: ![[VTABLE_TY2:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "impl$<debug_vtable::Foo, _>::vtable_type$", {{.*}}, size: {{192|96}}, align: {{64|32}}, flags: DIFlagArtificial, {{.*}}, vtableHolder: ![[FOO_TYPE]],
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "drop_in_place", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[PTR]], size: {{64|32}}, align: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "size", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{64|32}})
+// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "align", scope: ![[VTABLE_TY2]], {{.*}}, baseType: ![[USIZE]], size: {{64|32}}, align: {{64|32}}, offset: {{128|64}})
 
 // NONMSVC: !DIGlobalVariable(name: "<debug_vtable::bar::{closure_env#0} as core::ops::function::FnOnce<(core::option::Option<&dyn core::ops::function::Fn<(), Output=()>>)>>::{vtable}"
 // MSVC: !DIGlobalVariable(name: "impl$<debug_vtable::bar::closure_env$0, core::ops::function::FnOnce<tuple$<enum$<core::option::Option<ref$<dyn$<core::ops::function::Fn<tuple$<>,assoc$<Output,tuple$<> > > > > >, {{.*}}, {{.*}}, Some> > > >::vtable$"
@@ -34,6 +56,9 @@
 
 #![crate_type = "lib"]
 
+// Force emission for debuginfo for usize and *const() early..
+pub static mut XYZ: Option<(usize, *const ())> = None;
+
 pub struct Foo;
 
 pub trait SomeTrait {
index 6e5ac951261305447d75a5877dd0e384cb16b3bc..ad59f740b567f7ad58974ba473ebd19d7f678f22 100644 (file)
 
 // compile-flags: -Cdebuginfo=2 --edition 2021 -Copt-level=0 -Csymbol-mangling-version=v0
 
-
-// CHECK: [[non_generic_closure_NAMESPACE:!.*]] = !DINamespace(name: "non_generic_closure"
-// CHECK: [[function_containing_closure_NAMESPACE:!.*]] = !DINamespace(name: "function_containing_closure"
-// CHECK: [[generic_async_function_NAMESPACE:!.*]] = !DINamespace(name: "generic_async_function"
-// CHECK: [[generic_async_block_NAMESPACE:!.*]] = !DINamespace(name: "generic_async_block"
-
 // non_generic_closure()
-// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: [[non_generic_closure_NAMESPACE]]
-// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: [[non_generic_closure_NAMESPACE]]
+// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]],
+// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0", scope: ![[non_generic_closure_NAMESPACE:[0-9]+]],
+// CHECK: ![[non_generic_closure_NAMESPACE]] = !DINamespace(name: "non_generic_closure"
+
+// CHECK: ![[function_containing_closure_NAMESPACE:[0-9]+]] = !DINamespace(name: "function_containing_closure"
+// CHECK: ![[generic_async_function_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_function"
+// CHECK: ![[generic_async_block_NAMESPACE:[0-9]+]] = !DINamespace(name: "generic_async_block"
 
 // function_containing_closure<u32>()
-// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<u32>", scope: [[function_containing_closure_NAMESPACE]]
-// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<u32>", scope: [[function_containing_closure_NAMESPACE]]
+// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<u32>", scope: ![[function_containing_closure_NAMESPACE]]
+// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<u32>", scope: ![[function_containing_closure_NAMESPACE]]
 
 // generic_async_function<Foo>()
-// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: [[generic_async_function_NAMESPACE]]
+// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[generic_async_function_NAMESPACE]]
 
 // generic_async_function<u32>()
-// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<u32>", scope: [[generic_async_function_NAMESPACE]]
+// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}<u32>", scope: ![[generic_async_function_NAMESPACE]]
 
 // generic_async_block<Foo>()
-// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: [[generic_async_block_NAMESPACE]]
+// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[generic_async_block_NAMESPACE]]
 
 // generic_async_block<u32>()
-// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<u32>", scope: [[generic_async_block_NAMESPACE]]
+// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{async_block_env#0}<u32>", scope: ![[generic_async_block_NAMESPACE]]
 
 // function_containing_closure<Foo>()
-// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: [[function_containing_closure_NAMESPACE]]
-// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<debuginfo_generic_closure_env_names::Foo>", scope: [[function_containing_closure_NAMESPACE]]
+// NONMSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "{closure_env#0}<debuginfo_generic_closure_env_names::Foo>", scope: ![[function_containing_closure_NAMESPACE]]
+// MSVC: !DICompositeType(tag: DW_TAG_structure_type, name: "closure_env$0<debuginfo_generic_closure_env_names::Foo>", scope: ![[function_containing_closure_NAMESPACE]]
 
 
 #![crate_type = "lib"]
 pub struct Foo;
 
 pub fn non_generic_closure(x: Foo) -> Box<dyn FnOnce() -> Foo> {
-    // This static only exists to trigger generating the namespace debuginfo for
-    // `function_containing_closure` at a predictable, early point, which makes
-    // writing the FileCheck tests above simpler.
-    static _X: u8 = 0;
     return Box::new(move || x);
 }
 
 fn function_containing_closure<T: 'static>(x: T) -> impl FnOnce() -> T {
-    static _X: u8 = 0; // Same as above
+    // This static only exists to trigger generating the namespace debuginfo for
+    // `function_containing_closure` at a predictable, early point, which makes
+    // writing the FileCheck tests above simpler.
+    static _X: u8 = 0;
 
     return move || x;
 }
index adbeae454494ac8b95624878cff2ac34294b97f8..ec7a67915928646f87ebe1bbae7159b7850fc762 100644 (file)
@@ -2,52 +2,17 @@
 // as "inreg" like the C/C++ compilers for the platforms.
 // x86 only.
 
-// ignore-aarch64
-// ignore-aarch64_be
-// ignore-arm
-// ignore-armeb
-// ignore-avr
-// ignore-bpfel
-// ignore-bpfeb
-// ignore-hexagon
-// ignore-mips
-// ignore-mips64
-// ignore-msp430
-// ignore-powerpc64
-// ignore-powerpc64le
-// ignore-powerpc
-// ignore-r600
-// ignore-riscv64
-// ignore-amdgcn
-// ignore-sparc
-// ignore-sparc64
-// ignore-sparcv9
-// ignore-sparcel
-// ignore-s390x
-// ignore-tce
-// ignore-thumb
-// ignore-thumbeb
-// ignore-x86_64
-// ignore-xcore
-// ignore-nvptx
-// ignore-nvptx64
-// ignore-le32
-// ignore-le64
-// ignore-amdil
-// ignore-amdil64
-// ignore-hsail
-// ignore-hsail64
-// ignore-spir
-// ignore-spir64
-// ignore-kalimba
-// ignore-shave
-// ignore-wasm32
-// ignore-wasm64
-// ignore-emscripten
-
-// compile-flags: -C no-prepopulate-passes
+// compile-flags: --target i686-unknown-linux-gnu -C no-prepopulate-passes
+// needs-llvm-components: x86
 
 #![crate_type = "lib"]
+#![no_core]
+#![feature(no_core, lang_items)]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
 
 pub mod tests {
     // CHECK: @f1(i32 inreg %_1, i32 inreg %_2, i32 %_3)
@@ -70,7 +35,7 @@ pub extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {}
     #[no_mangle]
     pub extern "fastcall" fn f5(_: i64, _: i32) {}
 
-    // CHECK: @f6(i1 inreg zeroext %_1, i32 inreg %_2, i32 %_3)
+    // CHECK: @f6(i1 inreg noundef zeroext %_1, i32 inreg %_2, i32 %_3)
     #[no_mangle]
     pub extern "fastcall" fn f6(_: bool, _: i32, _: i32) {}
 }
index 3e10e227e55fef2604a0e707557ebc3c50fe1010..17b54d86cb09f057696093415c7086c5dc2a84e7 100644 (file)
@@ -3,6 +3,8 @@
 #![crate_type = "lib"]
 #![feature(rustc_attrs)]
 
+use std::mem::MaybeUninit;
+
 pub struct S {
   _field: [i32; 8],
 }
@@ -11,68 +13,79 @@ pub struct UnsafeInner {
   _field: std::cell::UnsafeCell<i16>,
 }
 
-// CHECK: zeroext i1 @boolean(i1 zeroext %x)
+// CHECK: noundef zeroext i1 @boolean(i1 noundef zeroext %x)
 #[no_mangle]
 pub fn boolean(x: bool) -> bool {
   x
 }
 
-// CHECK: @readonly_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1)
+// CHECK: i8 @maybeuninit_boolean(i8 %x)
+#[no_mangle]
+pub fn maybeuninit_boolean(x: MaybeUninit<bool>) -> MaybeUninit<bool> {
+  x
+}
+
+// CHECK: @readonly_borrow(i32* noalias noundef readonly align 4 dereferenceable(4) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn readonly_borrow(_: &i32) {
 }
 
-// CHECK: @static_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1)
+// CHECK: @static_borrow(i32* noalias noundef readonly align 4 dereferenceable(4) %_1)
 // static borrow may be captured
 #[no_mangle]
 pub fn static_borrow(_: &'static i32) {
 }
 
-// CHECK: @named_borrow(i32* noalias readonly align 4 dereferenceable(4) %_1)
+// CHECK: @named_borrow(i32* noalias noundef readonly align 4 dereferenceable(4) %_1)
 // borrow with named lifetime may be captured
 #[no_mangle]
 pub fn named_borrow<'r>(_: &'r i32) {
 }
 
-// CHECK: @unsafe_borrow(i16* align 2 dereferenceable(2) %_1)
+// CHECK: @unsafe_borrow(i16* noundef align 2 dereferenceable(2) %_1)
 // unsafe interior means this isn't actually readonly and there may be aliases ...
 #[no_mangle]
 pub fn unsafe_borrow(_: &UnsafeInner) {
 }
 
-// CHECK: @mutable_unsafe_borrow(i16* noalias align 2 dereferenceable(2) %_1)
+// CHECK: @mutable_unsafe_borrow(i16* noalias noundef align 2 dereferenceable(2) %_1)
 // ... unless this is a mutable borrow, those never alias
 #[no_mangle]
 pub fn mutable_unsafe_borrow(_: &mut UnsafeInner) {
 }
 
-// CHECK: @mutable_borrow(i32* noalias align 4 dereferenceable(4) %_1)
+// CHECK: @mutable_borrow(i32* noalias noundef align 4 dereferenceable(4) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn mutable_borrow(_: &mut i32) {
 }
 
-// CHECK: @indirect_struct(%S* noalias nocapture dereferenceable(32) %_1)
+// CHECK: @indirect_struct(%S* noalias nocapture noundef dereferenceable(32) %_1)
 #[no_mangle]
 pub fn indirect_struct(_: S) {
 }
 
-// CHECK: @borrowed_struct(%S* noalias readonly align 4 dereferenceable(32) %_1)
+// CHECK: @borrowed_struct(%S* noalias noundef readonly align 4 dereferenceable(32) %_1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn borrowed_struct(_: &S) {
 }
 
+// CHECK: @raw_struct(%S* %_1)
+#[no_mangle]
+pub fn raw_struct(_: *const S) {
+}
+
 // `Box` can get deallocated during execution of the function, so it should
 // not get `dereferenceable`.
-// CHECK: noalias nonnull align 4 i32* @_box(i32* noalias nonnull align 4 %x)
+// CHECK: noalias noundef nonnull align 4 i32* @_box(i32* noalias noundef nonnull align 4 %x)
 #[no_mangle]
 pub fn _box(x: Box<i32>) -> Box<i32> {
   x
 }
 
-// CHECK: @struct_return(%S* noalias nocapture sret(%S) dereferenceable(32){{( %0)?}})
+// CHECK: @struct_return(%S* noalias nocapture noundef sret(%S) dereferenceable(32){{( %0)?}})
 #[no_mangle]
 pub fn struct_return() -> S {
   S {
@@ -86,48 +99,58 @@ pub fn struct_return() -> S {
 pub fn helper(_: usize) {
 }
 
-// CHECK: @slice([0 x i8]* noalias nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1)
+// CHECK: @slice([0 x i8]* noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn slice(_: &[u8]) {
 }
 
-// CHECK: @mutable_slice([0 x i8]* noalias nonnull align 1 %_1.0, [[USIZE]] %_1.1)
+// CHECK: @mutable_slice([0 x i8]* noalias noundef nonnull align 1 %_1.0, [[USIZE]] %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn mutable_slice(_: &mut [u8]) {
 }
 
-// CHECK: @unsafe_slice([0 x i16]* nonnull align 2 %_1.0, [[USIZE]] %_1.1)
+// CHECK: @unsafe_slice([0 x i16]* noundef nonnull align 2 %_1.0, [[USIZE]] %_1.1)
 // unsafe interior means this isn't actually readonly and there may be aliases ...
 #[no_mangle]
 pub fn unsafe_slice(_: &[UnsafeInner]) {
 }
 
-// CHECK: @str([0 x i8]* noalias nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1)
+// CHECK: @raw_slice([0 x i8]* %_1.0, [[USIZE]] %_1.1)
+#[no_mangle]
+pub fn raw_slice(_: *const [u8]) {
+}
+
+// CHECK: @str([0 x i8]* noalias noundef nonnull readonly align 1 %_1.0, [[USIZE]] %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn str(_: &[u8]) {
 }
 
-// CHECK: @trait_borrow({}* nonnull align 1 %_1.0, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
+// CHECK: @trait_borrow({}* noundef nonnull align 1 %_1.0, [3 x [[USIZE]]]* noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
 // FIXME #25759 This should also have `nocapture`
 #[no_mangle]
 pub fn trait_borrow(_: &Drop) {
 }
 
-// CHECK: @trait_box({}* noalias nonnull align 1{{( %0)?}}, [3 x [[USIZE]]]* noalias readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}})
+// CHECK: @trait_raw({}* %_1.0, [3 x [[USIZE]]]* noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %_1.1)
+#[no_mangle]
+pub fn trait_raw(_: *const Drop) {
+}
+
+// CHECK: @trait_box({}* noalias noundef nonnull align 1{{( %0)?}}, [3 x [[USIZE]]]* noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}})
 #[no_mangle]
 pub fn trait_box(_: Box<Drop>) {
 }
 
-// CHECK: { i8*, i8* } @trait_option(i8* noalias align 1 %x.0, i8* %x.1)
+// CHECK: { i8*, i8* } @trait_option(i8* noalias noundef align 1 %x.0, i8* %x.1)
 #[no_mangle]
 pub fn trait_option(x: Option<Box<Drop>>) -> Option<Box<Drop>> {
   x
 }
 
-// CHECK: { [0 x i16]*, [[USIZE]] } @return_slice([0 x i16]* noalias nonnull readonly align 2 %x.0, [[USIZE]] %x.1)
+// CHECK: { [0 x i16]*, [[USIZE]] } @return_slice([0 x i16]* noalias noundef nonnull readonly align 2 %x.0, [[USIZE]] %x.1)
 #[no_mangle]
 pub fn return_slice(x: &[u16]) -> &[u16] {
   x
@@ -139,7 +162,7 @@ pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
   x
 }
 
-// CHECK: { i8, i8 } @enum_id_2(i1 zeroext %x.0, i8 %x.1)
+// CHECK: { i8, i8 } @enum_id_2(i1 noundef zeroext %x.0, i8 %x.1)
 #[no_mangle]
 pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
   x
index dfa7803d4f2f1419a9d2e38e1d44aacc94f3ff46..5d1fb80ec0051bb5c5ed435deea192fc5ab41029 100644 (file)
@@ -52,7 +52,7 @@ pub struct BigPacked2 {
 #[no_mangle]
 pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 {
 // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array
-// CHECK: call void %{{.*}}(%Array* noalias nocapture sret{{.*}} dereferenceable(32) [[ALLOCA]])
+// CHECK: call void %{{.*}}(%Array* noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
 // CHECK: call void @llvm.memcpy.{{.*}}(i8* align 1 %{{.*}}, i8* align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
     // check that calls whose destination is a field of a packed struct
     // go through an alloca rather than calling the function with an
@@ -64,7 +64,7 @@ pub fn call_pkd1(f: fn() -> Array) -> BigPacked1 {
 #[no_mangle]
 pub fn call_pkd2(f: fn() -> Array) -> BigPacked2 {
 // CHECK: [[ALLOCA:%[_a-z0-9]+]] = alloca %Array
-// CHECK: call void %{{.*}}(%Array* noalias nocapture sret{{.*}} dereferenceable(32) [[ALLOCA]])
+// CHECK: call void %{{.*}}(%Array* noalias nocapture noundef sret{{.*}} dereferenceable(32) [[ALLOCA]])
 // CHECK: call void @llvm.memcpy.{{.*}}(i8* align 2 %{{.*}}, i8* align 4 %{{.*}}, i{{[0-9]+}} 32, i1 false)
     // check that calls whose destination is a field of a packed struct
     // go through an alloca rather than calling the function with an
index 693f0d99c4fff04c6503386dc0768f7fc7cd29c4..c67406ea69338b1242040abe534e6057ce0edc6c 100644 (file)
@@ -1,15 +1,21 @@
-//
-// compile-flags: -C no-prepopulate-passes
-// only-riscv64
-// only-linux
+// compile-flags: --target riscv64gc-unknown-linux-gnu -C no-prepopulate-passes
+// needs-llvm-components: riscv
+
 #![crate_type = "lib"]
+#![no_core]
+#![feature(no_core, lang_items)]
 #![allow(improper_ctypes)]
 
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
 // CHECK: define void @f_void()
 #[no_mangle]
 pub extern "C" fn f_void() {}
 
-// CHECK: define zeroext i1 @f_scalar_0(i1 zeroext %a)
+// CHECK: define noundef zeroext i1 @f_scalar_0(i1 noundef zeroext %a)
 #[no_mangle]
 pub extern "C" fn f_scalar_0(a: bool) -> bool {
     a
@@ -70,8 +76,6 @@ pub struct Tiny {
 // CHECK: define void @f_agg_tiny(i64 %0)
 #[no_mangle]
 pub extern "C" fn f_agg_tiny(mut e: Tiny) {
-    e.a += e.b;
-    e.c += e.d;
 }
 
 // CHECK: define i64 @f_agg_tiny_ret()
@@ -89,14 +93,12 @@ pub struct Small {
 // CHECK: define void @f_agg_small([2 x i64] %0)
 #[no_mangle]
 pub extern "C" fn f_agg_small(mut x: Small) {
-    x.a += unsafe { *x.b };
-    x.b = &mut x.a;
 }
 
 // CHECK: define [2 x i64] @f_agg_small_ret()
 #[no_mangle]
 pub extern "C" fn f_agg_small_ret() -> Small {
-    Small { a: 1, b: core::ptr::null_mut() }
+    Small { a: 1, b: 0 as *mut _ }
 }
 
 #[repr(C)]
@@ -107,7 +109,6 @@ pub struct SmallAligned {
 // CHECK: define void @f_agg_small_aligned(i128 %0)
 #[no_mangle]
 pub extern "C" fn f_agg_small_aligned(mut x: SmallAligned) {
-    x.a += x.a;
 }
 
 #[repr(C)]
@@ -121,7 +122,6 @@ pub struct Large {
 // CHECK: define void @f_agg_large(%Large* {{.*}}%x)
 #[no_mangle]
 pub extern "C" fn f_agg_large(mut x: Large) {
-    x.a = x.b + x.c + x.d;
 }
 
 // CHECK: define void @f_agg_large_ret(%Large* {{.*}}sret{{.*}}, i32 signext %i, i8 signext %j)
@@ -172,7 +172,7 @@ pub extern "C" fn f_scalar_stack_2(
         4.0f64,
         5.0f64,
         Tiny { a: 1, b: 2, c: 3, d: 4 },
-        Small { a: 10, b: core::ptr::null_mut() },
+        Small { a: 10, b: 0 as *mut _ },
         SmallAligned { a: 11 },
         Large { a: 12, b: 13, c: 14, d: 15 },
     );
index 473272158d099914f373e27f2757652e8f35add9..264f28fdb5feea5e115473b341f18a52eec08de5 100644 (file)
@@ -2,25 +2,25 @@
 
 #![crate_type = "lib"]
 
-// CHECK: define{{.*}}{ i8, i8 } @pair_bool_bool(i1 zeroext %pair.0, i1 zeroext %pair.1)
+// CHECK: define{{.*}}{ i8, i8 } @pair_bool_bool(i1 noundef zeroext %pair.0, i1 noundef zeroext %pair.1)
 #[no_mangle]
 pub fn pair_bool_bool(pair: (bool, bool)) -> (bool, bool) {
     pair
 }
 
-// CHECK: define{{.*}}{ i8, i32 } @pair_bool_i32(i1 zeroext %pair.0, i32 %pair.1)
+// CHECK: define{{.*}}{ i8, i32 } @pair_bool_i32(i1 noundef zeroext %pair.0, i32 %pair.1)
 #[no_mangle]
 pub fn pair_bool_i32(pair: (bool, i32)) -> (bool, i32) {
     pair
 }
 
-// CHECK: define{{.*}}{ i32, i8 } @pair_i32_bool(i32 %pair.0, i1 zeroext %pair.1)
+// CHECK: define{{.*}}{ i32, i8 } @pair_i32_bool(i32 %pair.0, i1 noundef zeroext %pair.1)
 #[no_mangle]
 pub fn pair_i32_bool(pair: (i32, bool)) -> (i32, bool) {
     pair
 }
 
-// CHECK: define{{.*}}{ i8, i8 } @pair_and_or(i1 zeroext %_1.0, i1 zeroext %_1.1)
+// CHECK: define{{.*}}{ i8, i8 } @pair_and_or(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1)
 #[no_mangle]
 pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) {
     // Make sure it can operate directly on the unpacked args
@@ -30,7 +30,7 @@ pub fn pair_and_or((a, b): (bool, bool)) -> (bool, bool) {
     (a && b, a || b)
 }
 
-// CHECK: define{{.*}}void @pair_branches(i1 zeroext %_1.0, i1 zeroext %_1.1)
+// CHECK: define{{.*}}void @pair_branches(i1 noundef zeroext %_1.0, i1 noundef zeroext %_1.1)
 #[no_mangle]
 pub fn pair_branches((a, b): (bool, bool)) {
     // Make sure it can branch directly on the unpacked bool args
index e9584929f3a9eccfac69d12f45b59e16a6d5e8fd..a5aeb80de85c33d42f421b95477e458592850d35 100644 (file)
@@ -15,7 +15,7 @@ pub fn f32_to_bits(x: f32) -> u32 {
     unsafe { std::mem::transmute(x) }
 }
 
-// CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 zeroext %b)
+// CHECK-LABEL: define{{.*}}i8 @bool_to_byte(i1 noundef zeroext %b)
 // CHECK: %1 = zext i1 %b to i8
 // CHECK-NEXT: store i8 %1, i8* %0
 // CHECK-NEXT: %2 = load i8, i8* %0
@@ -25,7 +25,7 @@ pub fn bool_to_byte(b: bool) -> u8 {
     unsafe { std::mem::transmute(b) }
 }
 
-// CHECK-LABEL: define{{.*}}zeroext i1 @byte_to_bool(i8 %byte)
+// CHECK-LABEL: define{{.*}}noundef zeroext i1 @byte_to_bool(i8 %byte)
 // CHECK: %1 = trunc i8 %byte to i1
 // CHECK-NEXT: %2 = zext i1 %1 to i8
 // CHECK-NEXT: store i8 %2, i8* %0
index f282fd237054c48e881048e25b3db786c352b696..bb87d263bdf3d2f1e6b9daf97d701e309c009134 100644 (file)
@@ -75,7 +75,7 @@ pub union CUnionU128x2{a:(u128, u128)}
 pub fn test_CUnionU128x2(_: CUnionU128x2) { loop {} }
 
 pub union UnionBool { b:bool }
-// CHECK: define zeroext i1 @test_UnionBool(i8 %b)
+// CHECK: define noundef zeroext i1 @test_UnionBool(i8 %b)
 #[no_mangle]
 pub fn test_UnionBool(b: UnionBool) -> bool { unsafe { b.b }  }
 // CHECK: %0 = trunc i8 %b to i1
diff --git a/src/test/codegen/unwind-abis/aapcs-unwind-abi.rs b/src/test/codegen/unwind-abis/aapcs-unwind-abi.rs
new file mode 100644 (file)
index 0000000..1fe0480
--- /dev/null
@@ -0,0 +1,31 @@
+// needs-llvm-components: arm
+// compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// Test that `nounwind` atributes are correctly applied to exported `aapcs` and
+// `aapcs-unwind` extern functions. `aapcs-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "aapcs" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "aapcs-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/src/test/codegen/unwind-abis/cdecl-unwind-abi.rs b/src/test/codegen/unwind-abis/cdecl-unwind-abi.rs
new file mode 100644 (file)
index 0000000..52e0d2d
--- /dev/null
@@ -0,0 +1,29 @@
+// compile-flags: -C opt-level=0
+
+// Test that `nounwind` atributes are correctly applied to exported `cdecl` and
+// `cdecl-unwind` extern functions. `cdecl-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+#![crate_type = "lib"]
+#![feature(c_unwind)]
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "cdecl" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "cdecl-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/src/test/codegen/unwind-abis/fastcall-unwind-abi.rs b/src/test/codegen/unwind-abis/fastcall-unwind-abi.rs
new file mode 100644 (file)
index 0000000..ed23235
--- /dev/null
@@ -0,0 +1,31 @@
+// needs-llvm-components: x86
+// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// Test that `nounwind` atributes are correctly applied to exported `fastcall` and
+// `fastcall-unwind` extern functions. `fastcall-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "fastcall" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "fastcall-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/src/test/codegen/unwind-abis/sysv64-unwind-abi.rs b/src/test/codegen/unwind-abis/sysv64-unwind-abi.rs
new file mode 100644 (file)
index 0000000..a38736f
--- /dev/null
@@ -0,0 +1,31 @@
+// needs-llvm-components: x86
+// compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// Test that `nounwind` atributes are correctly applied to exported `sysv64` and
+// `sysv64-unwind` extern functions. `sysv64-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "sysv64" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "sysv64-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs b/src/test/codegen/unwind-abis/vectorcall-unwind-abi.rs
new file mode 100644 (file)
index 0000000..0fb9612
--- /dev/null
@@ -0,0 +1,31 @@
+// needs-llvm-components: x86
+// compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind, abi_vectorcall)]
+#[lang="sized"]
+trait Sized { }
+
+// Test that `nounwind` atributes are correctly applied to exported `vectorcall` and
+// `vectorcall-unwind` extern functions. `vectorcall-unwind` functions MUST NOT have this attribute.
+// We disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "vectorcall" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "vectorcall-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/src/test/codegen/unwind-abis/win64-unwind-abi.rs b/src/test/codegen/unwind-abis/win64-unwind-abi.rs
new file mode 100644 (file)
index 0000000..5d8482d
--- /dev/null
@@ -0,0 +1,31 @@
+// needs-llvm-components: x86
+// compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes
+#![no_core]
+#![feature(no_core, lang_items, c_unwind)]
+#[lang="sized"]
+trait Sized { }
+
+// Test that `nounwind` atributes are correctly applied to exported `win64` and
+// `win64-unwind` extern functions. `win64-unwind` functions MUST NOT have this attribute. We
+// disable optimizations above to prevent LLVM from inferring the attribute.
+
+// CHECK: @rust_item_that_cannot_unwind() unnamed_addr #0 {
+#[no_mangle]
+pub extern "win64" fn rust_item_that_cannot_unwind() {
+}
+
+// CHECK: @rust_item_that_can_unwind() unnamed_addr #1 {
+#[no_mangle]
+pub extern "win64-unwind" fn rust_item_that_can_unwind() {
+}
+
+// Now, make some assertions that the LLVM attributes for these functions are correct.  First, make
+// sure that the first item is correctly marked with the `nounwind` attribute:
+//
+// CHECK: attributes #0 = { {{.*}}nounwind{{.*}} }
+//
+// Next, let's assert that the second item, which CAN unwind, does not have this attribute.
+//
+// CHECK: attributes #1 = {
+// CHECK-NOT: nounwind
+// CHECK: }
diff --git a/src/test/codegen/used_with_arg.rs b/src/test/codegen/used_with_arg.rs
new file mode 100644 (file)
index 0000000..5bff50a
--- /dev/null
@@ -0,0 +1,10 @@
+#![crate_type = "lib"]
+#![feature(used_with_arg)]
+
+// CHECK: @llvm.used = appending global [1 x i8*]{{.*}}USED_LINKER
+#[used(linker)]
+static mut USED_LINKER: [usize; 1] = [0];
+
+// CHECK-NEXT: @llvm.compiler.used = appending global [1 x i8*]{{.*}}USED_COMPILER
+#[used(compiler)]
+static mut USED_COMPILER: [usize; 1] = [0];
index 75c93b73f857dad4a433cd68ff01cd8eba352392..2fb991b60ef3f7b25aadf73ff8495c345995f0c9 100644 (file)
@@ -358,9 +358,11 @@ pub trait AddDefaultTrait {
 
 #[cfg(any(cfail1,cfail4))]
 impl AddDefaultTrait for Foo {
-    // -------------------------------------------------------------------------------------------
+    // ----------------------------------------------------
     // -------------------------
-            fn method_name() { }
+    // ----------------------------------------------------
+    // -------------------------
+    fn         method_name() { }
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
@@ -369,9 +371,9 @@ fn method_name() { }
 #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl AddDefaultTrait for Foo {
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="associated_item", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item,optimized_mir", cfg="cfail5")]
+    #[rustc_clean(except="associated_item", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     default fn method_name() { }
 }
index 8e02dca4fb8b6541694c546117efd7479b41ed99..f8a8afa92e0e65f3a3e33b2f02e408d5a2a163d6 100644 (file)
@@ -9,12 +9,9 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
         _2 = const {alloc1: &&[(Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
-                                         // ty::Const
-                                         // + ty: &&[(std::option::Option<i32>, &[&str])]
-                                         // + val: Value(Scalar(alloc1))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation.rs:8:5: 8:8
-                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&str])], val: Value(Scalar(alloc1)) }
+                                         // + literal: Const { ty: &&[(Option<i32>, &[&str])], val: Value(Scalar(alloc1)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation.rs:8:8: 8:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation.rs:8:8: 8:9
index 88cdbda2fae36cbd28ccfa25c9cb86dc2914a5c4..1f1d857425e5b3b5c7812f75ef556a4a51a13834 100644 (file)
@@ -9,12 +9,9 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
         _2 = const {alloc1: &&[(Option<i32>, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
-                                         // ty::Const
-                                         // + ty: &&[(std::option::Option<i32>, &[&str])]
-                                         // + val: Value(Scalar(alloc1))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation.rs:8:5: 8:8
-                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&str])], val: Value(Scalar(alloc1)) }
+                                         // + literal: Const { ty: &&[(Option<i32>, &[&str])], val: Value(Scalar(alloc1)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation.rs:8:5: 8:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation.rs:8:8: 8:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation.rs:8:8: 8:9
index 059b721f5bb6332d0d8ac8e70e609ae0e68e9fa5..8b5ad40c9f92c9c475a201c57d873b526af96574 100644 (file)
@@ -9,12 +9,9 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
         _2 = const {alloc1: &&[(Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
-                                         // ty::Const
-                                         // + ty: &&[(std::option::Option<i32>, &[&u8])]
-                                         // + val: Value(Scalar(alloc1))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation2.rs:5:5: 5:8
-                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) }
+                                         // + literal: Const { ty: &&[(Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9
index d6a97917d6226c7f5aece75f866cbe85a12ca581..ef651f01c9b98df9f3b3c9091973dce8bdf0b81c 100644 (file)
@@ -9,12 +9,9 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
         _2 = const {alloc1: &&[(Option<i32>, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
-                                         // ty::Const
-                                         // + ty: &&[(std::option::Option<i32>, &[&u8])]
-                                         // + val: Value(Scalar(alloc1))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation2.rs:5:5: 5:8
-                                         // + literal: Const { ty: &&[(std::option::Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) }
+                                         // + literal: Const { ty: &&[(Option<i32>, &[&u8])], val: Value(Scalar(alloc1)) }
         _1 = (*_2);                      // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8
         StorageDead(_2);                 // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9
         StorageDead(_1);                 // scope 0 at $DIR/const_allocation2.rs:5:8: 5:9
index 32000340dcebfc35a4bd434ea0fe3a2c7cb393e6..991cf40d1b7ce6884a02dce09cb8ca16c7640a6c 100644 (file)
@@ -9,9 +9,6 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
         _2 = const {alloc1: &&Packed};   // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
-                                         // ty::Const
-                                         // + ty: &&Packed
-                                         // + val: Value(Scalar(alloc1))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation3.rs:5:5: 5:8
                                          // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc1)) }
index cac882333aeb94debb5ea1a446f5bb613d8b7643..fb481697aa8111f414a49a5f99c598bd42d5a9d9 100644 (file)
@@ -9,9 +9,6 @@ fn main() -> () {
         StorageLive(_1);                 // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
         StorageLive(_2);                 // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
         _2 = const {alloc1: &&Packed};   // scope 0 at $DIR/const_allocation3.rs:5:5: 5:8
-                                         // ty::Const
-                                         // + ty: &&Packed
-                                         // + val: Value(Scalar(alloc1))
                                          // mir::Constant
                                          // + span: $DIR/const_allocation3.rs:5:5: 5:8
                                          // + literal: Const { ty: &&Packed, val: Value(Scalar(alloc1)) }
index bec0fa9c0495722bfa36bae10fe39d58c034ff19..666b805e822c1a5286fb8190c32cc1b376284b1f 100644 (file)
@@ -8,9 +8,6 @@ promoted[0] in BAR: &[&i32; 1] = {
 
     bb0: {
         _3 = const {alloc1: &i32};       // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
-                                         // ty::Const
-                                         // + ty: &i32
-                                         // + val: Value(Scalar(alloc1))
                                          // mir::Constant
                                          // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34
                                          // + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) }
index b480b257825642f1ff0bb11829638e3f8af24efc..ad83e9c276e66d30ee4ac4a4f222a36f4b4e2f19 100644 (file)
@@ -18,9 +18,7 @@
 -         StorageLive(_5);                 // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
 -         _5 = const {alloc1: &i32};       // scope 0 at $DIR/const-promotion-extern-static.rs:9:33: 9:34
 +         _6 = const BAR::promoted[0];     // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
-                                           // ty::Const
--                                          // + ty: &i32
--                                          // + val: Value(Scalar(alloc1))
++                                          // ty::Const
 +                                          // + ty: &[&i32; 1]
 +                                          // + val: Unevaluated(BAR, [], Some(promoted[0]))
                                            // mir::Constant
index c01b31525b6a6ee0ffa906bf53f9f30cfb558f4d..785c8386e88b51b447b298e9732d6efd529f8812 100644 (file)
@@ -8,9 +8,6 @@ promoted[0] in FOO: &[&i32; 1] = {
 
     bb0: {
         _3 = const {alloc3: *const i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
-                                         // ty::Const
-                                         // + ty: *const i32
-                                         // + val: Value(Scalar(alloc3))
                                          // mir::Constant
                                          // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
                                          // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) }
index ed48f5dc9dcbca44b6b907c5a98053db1033983d..a9cf3ca976797da7321ea1f14095b3cd764fbd71 100644 (file)
@@ -20,9 +20,7 @@
 -         StorageLive(_5);                 // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
 -         _5 = const {alloc3: *const i32}; // scope 1 at $DIR/const-promotion-extern-static.rs:13:42: 13:43
 +         _6 = const FOO::promoted[0];     // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
-                                           // ty::Const
--                                          // + ty: *const i32
--                                          // + val: Value(Scalar(alloc3))
++                                          // ty::Const
 +                                          // + ty: &[&i32; 1]
 +                                          // + val: Unevaluated(FOO, [], Some(promoted[0]))
                                            // mir::Constant
diff --git a/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff b/src/test/mir-opt/const_prop/invalid_constant.main.ConstProp.diff
new file mode 100644 (file)
index 0000000..ee6c3b5
--- /dev/null
@@ -0,0 +1,55 @@
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+  
+  fn main() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/invalid_constant.rs:15:11: 15:11
+      let _1: std::option::Option<()>;     // in scope 0 at $DIR/invalid_constant.rs:16:5: 16:12
+      let mut _2: std::option::Option<std::option::Option<()>>; // in scope 0 at $DIR/invalid_constant.rs:16:7: 16:11
+      scope 1 (inlined f) {                // at $DIR/invalid_constant.rs:16:5: 16:12
+          debug x => _2;                   // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
+          let mut _3: isize;               // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
+          let _4: std::option::Option<()>; // in scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
+          scope 2 {
+              debug y => _4;               // in scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
+          }
+      }
+  
+      bb0: {
+          discriminant(_2) = 0;            // scope 0 at $DIR/invalid_constant.rs:16:7: 16:11
+-         _3 = discriminant(_2);           // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
+-         switchInt(move _3) -> [0_isize: bb3, otherwise: bb2]; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
++         _3 = const 0_isize;              // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
++         switchInt(const 0_isize) -> [0_isize: bb3, otherwise: bb2]; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
+      }
+  
+      bb1: {
+          nop;                             // scope 0 at $DIR/invalid_constant.rs:15:11: 17:2
+          return;                          // scope 0 at $DIR/invalid_constant.rs:17:2: 17:2
+      }
+  
+      bb2: {
+-         _4 = ((_2 as Some).0: std::option::Option<()>); // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
+-         _1 = _4;                         // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
++         _4 = const Scalar(0x02): Option::<()>; // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
++                                          // ty::Const
++                                          // + ty: std::option::Option<()>
++                                          // + val: Value(Scalar(0x02))
++                                          // mir::Constant
++                                          // + span: $DIR/invalid_constant.rs:16:5: 16:12
++                                          // + literal: Const { ty: std::option::Option<()>, val: Value(Scalar(0x02)) }
++         _1 = const Scalar(0x02): Option::<()>; // scope 2 at $DIR/invalid_constant.rs:16:5: 16:12
++                                          // ty::Const
++                                          // + ty: std::option::Option<()>
++                                          // + val: Value(Scalar(0x02))
++                                          // mir::Constant
++                                          // + span: $DIR/invalid_constant.rs:16:5: 16:12
++                                          // + literal: Const { ty: std::option::Option<()>, val: Value(Scalar(0x02)) }
+          goto -> bb1;                     // scope 0 at $DIR/invalid_constant.rs:10:20: 10:21
+      }
+  
+      bb3: {
+          discriminant(_1) = 0;            // scope 1 at $DIR/invalid_constant.rs:16:5: 16:12
+          goto -> bb1;                     // scope 0 at $DIR/invalid_constant.rs:9:17: 9:21
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop/invalid_constant.rs b/src/test/mir-opt/const_prop/invalid_constant.rs
new file mode 100644 (file)
index 0000000..1eb6f37
--- /dev/null
@@ -0,0 +1,17 @@
+// Verify that we can pretty print invalid constant introduced
+// by constant propagation. Regression test for issue #93688.
+//
+// compile-flags: -Copt-level=0 -Zinline-mir
+
+#[inline(always)]
+pub fn f(x: Option<Option<()>>) -> Option<()> {
+    match x {
+        None => None,
+        Some(y) => y,
+    }
+}
+
+// EMIT_MIR invalid_constant.main.ConstProp.diff
+fn main() {
+    f(None);
+}
index afc621784633e5cf7f8670c59d386d30ce985a52..1fd92ddd461905413f4b81d75dedf1bfba77ac51 100644 (file)
@@ -24,9 +24,6 @@
           StorageLive(_3);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
           StorageLive(_4);                 // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
           _4 = const {alloc1: *mut u32};   // scope 2 at $DIR/mutable_variable_no_prop.rs:9:13: 9:19
-                                           // ty::Const
-                                           // + ty: *mut u32
-                                           // + val: Value(Scalar(alloc1))
                                            // mir::Constant
                                            // + span: $DIR/mutable_variable_no_prop.rs:9:13: 9:19
                                            // + literal: Const { ty: *mut u32, val: Value(Scalar(alloc1)) }
index 13ef30d89a076e89ef73b07a0f594f6a9028285f..15b3e076642584104f43aee81f5a6bff35e856f8 100644 (file)
@@ -17,9 +17,6 @@
           StorageLive(_2);                 // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
           StorageLive(_3);                 // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
           _3 = const {alloc1: &u8};        // scope 0 at $DIR/read_immutable_static.rs:7:13: 7:16
-                                           // ty::Const
-                                           // + ty: &u8
-                                           // + val: Value(Scalar(alloc1))
                                            // mir::Constant
                                            // + span: $DIR/read_immutable_static.rs:7:13: 7:16
                                            // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) }
@@ -28,9 +25,6 @@
           StorageLive(_4);                 // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
           StorageLive(_5);                 // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
           _5 = const {alloc1: &u8};        // scope 0 at $DIR/read_immutable_static.rs:7:19: 7:22
-                                           // ty::Const
-                                           // + ty: &u8
-                                           // + val: Value(Scalar(alloc1))
                                            // mir::Constant
                                            // + span: $DIR/read_immutable_static.rs:7:19: 7:22
                                            // + literal: Const { ty: &u8, val: Value(Scalar(alloc1)) }
index b3c90c528377d6fe8787f758cf2d8902487d10f4..09403bb3a7926675c9134740abf8a073728b196f 100644 (file)
@@ -1,9 +1,9 @@
-// Test that `-Z instrument-coverage` with `-Z dump-mir-graphviz` generates a graphviz (.dot file)
+// Test that `-C instrument-coverage` with `-Z dump-mir-graphviz` generates a graphviz (.dot file)
 // rendering of the `BasicCoverageBlock` coverage control flow graph, with counters and
 // expressions.
 
 // needs-profiler-support
-// compile-flags: -Z instrument-coverage -Z dump-mir-graphviz
+// compile-flags: -C instrument-coverage -Z dump-mir-graphviz
 // EMIT_MIR coverage_graphviz.main.InstrumentCoverage.0.dot
 // EMIT_MIR coverage_graphviz.bar.InstrumentCoverage.0.dot
 fn main() {
index 18863edac97e49815f1f803ede41583adb99622b..a748f2c5ccc9b54346df5557be2e3fe9658349f7 100644 (file)
@@ -1,9 +1,9 @@
-// Test that `-Z instrument-coverage` injects Coverage statements. The Coverage Counter statements
+// Test that `-C instrument-coverage` injects Coverage statements. The Coverage Counter statements
 // are later converted into LLVM instrprof.increment intrinsics, during codegen.
 
 // needs-profiler-support
 // ignore-windows
-// compile-flags: -Z instrument-coverage --remap-path-prefix={{src-base}}=/the/src
+// compile-flags: -C instrument-coverage --remap-path-prefix={{src-base}}=/the/src
 
 // EMIT_MIR instrument_coverage.main.InstrumentCoverage.diff
 // EMIT_MIR instrument_coverage.bar.InstrumentCoverage.diff
index 57485993dced0a70b71326946cb984e2b924c998..1a454bab4d0d961949255630072705d054f48274 100644 (file)
@@ -21,7 +21,7 @@
       let mut _19: *const T;               // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68
       let mut _20: *const T;               // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84
       let mut _21: *const T;               // in scope 0 at $DIR/issue_76432.rs:9:70: 9:84
-      let mut _22: !;                      // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+      let mut _22: !;                      // in scope 0 at $SRC_DIR/core/src/panic.rs:LL:COL
       let mut _23: &[T; 3];                // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29
       scope 1 {
           debug v => _2;                   // in scope 1 at $DIR/issue_76432.rs:7:9: 7:10
       }
   
       bb1: {
-          StorageLive(_22);                // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          core::panicking::panic(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+          StorageLive(_22);                // scope 1 at $SRC_DIR/core/src/panic.rs:LL:COL
+          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/macros/mod.rs:LL:COL
+                                           // + span: $SRC_DIR/core/src/panic.rs:LL:COL
                                            // + literal: Const { ty: fn(&'static str) -> ! {core::panicking::panic}, val: Value(Scalar(<ZST>)) }
                                            // ty::Const
                                            // + ty: &str
                                            // + val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 })
                                            // mir::Constant
-                                           // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+                                           // + span: $SRC_DIR/core/src/panic.rs:LL:COL
                                            // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 }) }
       }
   
index 2404b321942890ed841d897e8df1913493b646bb..27c86ec22b84ef1f52c9428debee24246c7d4511 100644 (file)
@@ -119,9 +119,9 @@ fn syntax() {
     let _ = #[attr] foo![#! [attr]];
     let _ = #[attr] foo! {};
     let _ = #[attr] foo! { #! [attr] };
-    let _ = #[attr] Foo{bar: baz,};
-    let _ = #[attr] Foo{..foo};
-    let _ = #[attr] Foo{bar: baz, ..foo};
+    let _ = #[attr] Foo { bar: baz };
+    let _ = #[attr] Foo { ..foo };
+    let _ = #[attr] Foo { bar: baz, ..foo };
     let _ = #[attr] (0);
 
     {
index 87f525a6178e63ac6eb4c805a4d4cb5ef5440252..80f739f4f9e1aa196be31d9ed4339a137caef71b 100644 (file)
@@ -8,9 +8,10 @@ struct C {
 
 #[allow()]
 const C: C =
-    C{
+    C {
         #[cfg(debug_assertions)]
         field: 0,
 
         #[cfg(not(debug_assertions))]
-        field: 1,};
+        field: 1,
+    };
index 96bde96200af9a3312a1067a290b8330eec8108a..7ab22f1960c2d8fbc8daf2f8c5d253b97104135d 100644 (file)
@@ -90,9 +90,9 @@ struct Foo {
 fn _7() {
 
     #[rustc_dummy]
-    Foo{data: (),};
+    Foo { data: () };
 
-    let _ = #[rustc_dummy] Foo{data: (),};
+    let _ = #[rustc_dummy] Foo { data: () };
 }
 
 fn _8() {
@@ -209,7 +209,7 @@ fn _11() {
     let mut x = 0;
     let _ = #[rustc_dummy] x = 15;
     let _ = #[rustc_dummy] x += 15;
-    let s = Foo{data: (),};
+    let s = Foo { data: () };
     let _ = #[rustc_dummy] s.data;
     let _ = (#[rustc_dummy] s).data;
     let t = Bar(());
@@ -235,9 +235,9 @@ fn _11() {
     let _ = #[rustc_dummy] expr_mac!();
     let _ = #[rustc_dummy] expr_mac![];
     let _ = #[rustc_dummy] expr_mac! {};
-    let _ = #[rustc_dummy] Foo{data: (),};
-    let _ = #[rustc_dummy] Foo{..s};
-    let _ = #[rustc_dummy] Foo{data: (), ..s};
+    let _ = #[rustc_dummy] Foo { data: () };
+    let _ = #[rustc_dummy] Foo { ..s };
+    let _ = #[rustc_dummy] Foo { data: (), ..s };
     let _ = #[rustc_dummy] (0);
 }
 
diff --git a/src/test/pretty/use-tree.rs b/src/test/pretty/use-tree.rs
new file mode 100644 (file)
index 0000000..5da9523
--- /dev/null
@@ -0,0 +1,23 @@
+// pp-exact
+// edition:2021
+
+#![allow(unused_imports)]
+
+use ::std::fmt::{self, Debug, Display, Write as _};
+
+use core::option::Option::*;
+
+use core::{
+    cmp::{Eq, Ord, PartialEq, PartialOrd},
+    convert::{AsMut, AsRef, From, Into},
+    iter::{
+        DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator,
+        IntoIterator, Iterator,
+    },
+    marker::{
+        Copy as Copy, Send as Send, Sized as Sized, Sync as Sync, Unpin as U,
+    },
+    ops::{*, Drop, Fn, FnMut, FnOnce},
+};
+
+fn main() {}
index bc7951a04da86d7dcf338bd5d736935415719d8c..e9b28504a907a4c5fa02769f49ab0d15180b89e9 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(cfg_target_has_atomic, no_core, intrinsics, lang_items)]
+#![feature(no_core, intrinsics, lang_items)]
 #![crate_type="rlib"]
 #![no_core]
 
index bc4562bef3a96c728c654c7b8716eae239aac65d..f79e4c3f4798c29791e7fede5c3e2e25bec440f9 100644 (file)
@@ -1,4 +1,4 @@
 -include ../tools.mk
 
 all:
-       $(RUSTC) --edition=2018 --crate-type=rlib ../../../../library/core/src/lib.rs --cfg no_fp_fmt_parse
+       $(RUSTC) --edition=2021 --crate-type=rlib ../../../../library/core/src/lib.rs --cfg no_fp_fmt_parse
index 3c4df3533e147f512a481954d373fdd95e20214a..fbe0a5cb1bb8cac13f2c93e09aebf1e00c92f0cb 100644 (file)
@@ -57,7 +57,7 @@ all: test_llvm_ir
 test_llvm_ir:
        # Compile the test program with non-experimental coverage instrumentation, and generate LLVM IR
        $(RUSTC) $(BASEDIR)/testprog.rs \
-                       -Zinstrument-coverage \
+                       -Cinstrument-coverage \
                        --emit=llvm-ir
 
        cat "$(TMPDIR)"/testprog.ll | \
index 8e5f210468773cd91c97eea4ea6f14c302380e8f..84e67e53ea4c6512eef386723e4bdb4e9f49e4f7 100644 (file)
@@ -1,5 +1,5 @@
 # Check for metadata, variables, declarations, and function definitions injected
-# into LLVM IR when compiling with -Zinstrument-coverage.
+# into LLVM IR when compiling with -Cinstrument-coverage.
 
 WINDOWS:      $__llvm_profile_runtime_user = comdat any
 
@@ -15,14 +15,14 @@ CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|i
 CHECK-SAME:   section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
 
 CHECK:        @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
-CHECK-SAME:   @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called,
+CHECK-SAME:   @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called
 CHECK-SAME:   section "[[INSTR_PROF_DATA]]"{{.*}}, align 8
 
 CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global
 CHECK-SAME:   section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
 
 CHECK:        @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = {{private|internal}} global
-CHECK-SAME:   @__profc__R{{[a-zA-Z0-9_]+}}testprog4main,
+CHECK-SAME:   @__profc__R{{[a-zA-Z0-9_]+}}testprog4main
 CHECK-SAME:   section "[[INSTR_PROF_DATA]]"{{.*}}, align 8
 
 CHECK:        @__llvm_prf_nm = private constant
index 094d6b3ebf5f8f6a41c32b343ebba175c85afcf2..78723e78e772f52f496b5e0c7733f48161c2d7c5 100644 (file)
@@ -81,13 +81,13 @@ endif
        # Compile the test library with coverage instrumentation
        $(RUSTC) $(SOURCEDIR)/lib/$@.rs \
                        $$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/lib/$@.rs ) \
-                       --crate-type rlib -Zinstrument-coverage
+                       --crate-type rlib -Cinstrument-coverage
 
 %: $(SOURCEDIR)/%.rs
        # Compile the test program with coverage instrumentation
        $(RUSTC) $(SOURCEDIR)/$@.rs \
                        $$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/$@.rs ) \
-                       -L "$(TMPDIR)" -Zinstrument-coverage
+                       -L "$(TMPDIR)" -Cinstrument-coverage
 
        # Run it in order to generate some profiling data,
        # with `LLVM_PROFILE_FILE=<profdata_file>` environment variable set to
@@ -109,7 +109,7 @@ endif
        LLVM_PROFILE_FILE="$(TMPDIR)"/$@-%p-%m.profraw \
                        $(RUSTDOC) --crate-name workaround_for_79771 --test $(SOURCEDIR)/$@.rs \
                        $$( sed -n 's/^\/\/ compile-flags: \([^#]*\).*/\1/p' $(SOURCEDIR)/$@.rs ) \
-                       -L "$(TMPDIR)" -Zinstrument-coverage \
+                       -L "$(TMPDIR)" -Cinstrument-coverage \
                        -Z unstable-options --persist-doctests=$(TMPDIR)/rustdoc-$@
 
        # Postprocess the profiling data so it can be used by the llvm-cov tool
index 2831e9b532aba6ac0d8f06ac9f204b9b0c163d98..1aa4a22c33e1803f7d9b55e719f8ac37b7d9a8b6 100644 (file)
@@ -11,7 +11,7 @@
    10|      1|}
 
 ../coverage/lib/inline_always_with_dead_code.rs:
-    1|       |// compile-flags: -Zinstrument-coverage -Ccodegen-units=4 -Copt-level=0
+    1|       |// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 -Copt-level=0
     2|       |
     3|       |#![allow(dead_code)]
     4|       |
index 324b9138c4d9c10271c007767fbc080d9f061fb1..83a9204136f7c15d82a676c84c9c461e55e297db 100644 (file)
@@ -6,8 +6,8 @@
     6|       |    println!("called but not covered");
     7|       |}
     8|       |
-    9|       |#[no_coverage]
-   10|       |fn do_not_add_coverage_2() {
+    9|       |fn do_not_add_coverage_2() {
+   10|       |    #![no_coverage]
    11|       |    println!("called but not covered");
    12|       |}
    13|       |
    28|      0|    println!("not called but covered");
    29|      0|}
    30|       |
-   31|      1|fn main() {
-   32|      1|    do_not_add_coverage_1();
-   33|      1|    do_not_add_coverage_2();
-   34|      1|    add_coverage_1();
-   35|      1|    add_coverage_2();
-   36|      1|}
+   31|       |// FIXME: These test-cases illustrate confusing results of nested functions.
+   32|       |// See https://github.com/rust-lang/rust/issues/93319
+   33|       |mod nested_fns {
+   34|       |    #[no_coverage]
+   35|       |    pub fn outer_not_covered(is_true: bool) {
+   36|      1|        fn inner(is_true: bool) {
+   37|      1|            if is_true {
+   38|      1|                println!("called and covered");
+   39|      1|            } else {
+   40|      0|                println!("absolutely not covered");
+   41|      0|            }
+   42|      1|        }
+   43|       |        println!("called but not covered");
+   44|       |        inner(is_true);
+   45|       |    }
+   46|       |
+   47|      1|    pub fn outer(is_true: bool) {
+   48|      1|        println!("called and covered");
+   49|      1|        inner_not_covered(is_true);
+   50|      1|
+   51|      1|        #[no_coverage]
+   52|      1|        fn inner_not_covered(is_true: bool) {
+   53|      1|            if is_true {
+   54|      1|                println!("called but not covered");
+   55|      1|            } else {
+   56|      1|                println!("absolutely not covered");
+   57|      1|            }
+   58|      1|        }
+   59|      1|    }
+   60|       |
+   61|      1|    pub fn outer_both_covered(is_true: bool) {
+   62|      1|        println!("called and covered");
+   63|      1|        inner(is_true);
+   64|      1|
+   65|      1|        fn inner(is_true: bool) {
+   66|      1|            if is_true {
+   67|      1|                println!("called and covered");
+   68|      1|            } else {
+   69|      0|                println!("absolutely not covered");
+   70|      0|            }
+   71|      1|        }
+   72|      1|    }
+   73|       |}
+   74|       |
+   75|      1|fn main() {
+   76|      1|    let is_true = std::env::args().len() == 1;
+   77|      1|
+   78|      1|    do_not_add_coverage_1();
+   79|      1|    do_not_add_coverage_2();
+   80|      1|    add_coverage_1();
+   81|      1|    add_coverage_2();
+   82|      1|
+   83|      1|    nested_fns::outer_not_covered(is_true);
+   84|      1|    nested_fns::outer(is_true);
+   85|      1|    nested_fns::outer_both_covered(is_true);
+   86|      1|}
 
index c2d5143a61816f881992c53bf2c3fa2a412201dc..55a49548cb5e03f9a6d749be26a4fcbef8cbd558 100644 (file)
    78|       |// generic functions with:
    79|       |//
    80|       |// ```shell
-   81|       |// $ `rustc -Z instrument-coverage=except-unused-generics ...`
+   81|       |// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...`
    82|       |// ```
    83|       |//
    84|       |// Even though this function is used by `uses_crate.rs` (and
index b567916aea060a829470b1fea6fa8e9b39450eaf..2b21dee6ccff63e8c461e3e341cd54852df712fe 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Zinstrument-coverage -Ccodegen-units=4 -Copt-level=0
+// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 -Copt-level=0
 
 #![allow(dead_code)]
 
index eaa93115ae8d2a9959e1cd6954afe099e8793662..8b8b1f7f351fd7d9a1905562450313b2354efaaa 100644 (file)
@@ -78,7 +78,7 @@ fn use_this_lib_crate() {
 // generic functions with:
 //
 // ```shell
-// $ `rustc -Z instrument-coverage=except-unused-generics ...`
+// $ `rustc -Zunstable-options -C instrument-coverage=except-unused-generics ...`
 // ```
 //
 // Even though this function is used by `uses_crate.rs` (and
index 6f8586d9f5ca642ec63c25d8c2f99ad739e1c3c1..0bfbdda2cab037cd1d748d9cb7b063710db15c10 100644 (file)
@@ -6,8 +6,8 @@ fn do_not_add_coverage_1() {
     println!("called but not covered");
 }
 
-#[no_coverage]
 fn do_not_add_coverage_2() {
+    #![no_coverage]
     println!("called but not covered");
 }
 
@@ -28,9 +28,59 @@ fn add_coverage_not_called() {
     println!("not called but covered");
 }
 
+// FIXME: These test-cases illustrate confusing results of nested functions.
+// See https://github.com/rust-lang/rust/issues/93319
+mod nested_fns {
+    #[no_coverage]
+    pub fn outer_not_covered(is_true: bool) {
+        fn inner(is_true: bool) {
+            if is_true {
+                println!("called and covered");
+            } else {
+                println!("absolutely not covered");
+            }
+        }
+        println!("called but not covered");
+        inner(is_true);
+    }
+
+    pub fn outer(is_true: bool) {
+        println!("called and covered");
+        inner_not_covered(is_true);
+
+        #[no_coverage]
+        fn inner_not_covered(is_true: bool) {
+            if is_true {
+                println!("called but not covered");
+            } else {
+                println!("absolutely not covered");
+            }
+        }
+    }
+
+    pub fn outer_both_covered(is_true: bool) {
+        println!("called and covered");
+        inner(is_true);
+
+        fn inner(is_true: bool) {
+            if is_true {
+                println!("called and covered");
+            } else {
+                println!("absolutely not covered");
+            }
+        }
+    }
+}
+
 fn main() {
+    let is_true = std::env::args().len() == 1;
+
     do_not_add_coverage_1();
     do_not_add_coverage_2();
     add_coverage_1();
     add_coverage_2();
+
+    nested_fns::outer_not_covered(is_true);
+    nested_fns::outer(is_true);
+    nested_fns::outer_both_covered(is_true);
 }
index 4acabbb70ede20672e52f9e7bd8690a8c5e79c69..9172d08eff9362804654c70435d0b7dc274304e9 100644 (file)
@@ -55,7 +55,6 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
         output_dir: None,
         file_loader: None,
         diagnostic_output: DiagnosticOutput::Default,
-        stderr: None,
         lint_caps: Default::default(),
         parse_sess_created: None,
         register_lints: None,
diff --git a/src/test/run-make-fulldeps/libs-and-bins/Makefile b/src/test/run-make-fulldeps/libs-and-bins/Makefile
deleted file mode 100644 (file)
index cc3b257..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
--include ../tools.mk
-
-all:
-       $(RUSTC) foo.rs
-       $(call RUN,foo)
-       rm $(TMPDIR)/$(call DYLIB_GLOB,foo)
diff --git a/src/test/run-make-fulldeps/libs-and-bins/foo.rs b/src/test/run-make-fulldeps/libs-and-bins/foo.rs
deleted file mode 100644 (file)
index ae166b1..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#![crate_type = "dylib"]
-#![crate_type = "bin"]
-
-fn main() {}
index 099b65a23cad6979e2be32d80a5a678c6a6de0d9..e2c778aa8650964a540d747c0ace08018a7bda80 100644 (file)
@@ -7,4 +7,4 @@
 { "type": "test", "name": "c", "event": "ok" }
 { "type": "test", "event": "started", "name": "d" }
 { "type": "test", "name": "d", "event": "ignored" }
-{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
+{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
index fd676799a76649435e0b6aa030ac8c50f629c9e4..68eb00c297ea72a175bbd3c3b952572503d62478 100644 (file)
@@ -7,4 +7,4 @@
 { "type": "test", "name": "c", "event": "ok", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:15:5\n" }
 { "type": "test", "event": "started", "name": "d" }
 { "type": "test", "name": "d", "event": "ignored" }
-{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "allowed_fail": 0, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
+{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
index 783d826a53dabbd7d4d96197defae5b2ce8de264..69a286f0b74f83a3faf3e75502fe1c33822d3ba6 100644 (file)
@@ -1,6 +1,7 @@
 -include ../tools.mk
 
 all:
-       $(RUSTC) foo-bar.rs
+       $(RUSTC) foo-bar.rs --crate-type bin
        [ -f $(TMPDIR)/$(call BIN,foo-bar) ]
+       $(RUSTC) foo-bar.rs --crate-type lib
        [ -f $(TMPDIR)/libfoo_bar.rlib ]
index 3f1a70458e377134d727cc068985d205fa6427b5..f328e4d9d04c31d0d70d16d21a07d1613be9d577 100644 (file)
@@ -1,4 +1 @@
-#![crate_type = "lib"]
-#![crate_type = "bin"]
-
 fn main() {}
diff --git a/src/test/run-make/rustdoc-scrape-examples-whitespace/Makefile b/src/test/run-make/rustdoc-scrape-examples-whitespace/Makefile
new file mode 100644 (file)
index 0000000..dce8b83
--- /dev/null
@@ -0,0 +1,5 @@
+deps := ex
+
+-include ../rustdoc-scrape-examples-multiple/scrape.mk
+
+all: scrape
diff --git a/src/test/run-make/rustdoc-scrape-examples-whitespace/examples/ex.rs b/src/test/run-make/rustdoc-scrape-examples-whitespace/examples/ex.rs
new file mode 100644 (file)
index 0000000..44ff689
--- /dev/null
@@ -0,0 +1,8 @@
+struct Foo;
+impl Foo {
+  fn bar() { foobar::ok(); }
+}
+
+fn main() {
+  Foo::bar();
+}
diff --git a/src/test/run-make/rustdoc-scrape-examples-whitespace/src/lib.rs b/src/test/run-make/rustdoc-scrape-examples-whitespace/src/lib.rs
new file mode 100644 (file)
index 0000000..28c3471
--- /dev/null
@@ -0,0 +1,3 @@
+// @has foobar/fn.ok.html '//*[@class="docblock scraped-example-list"]//code' '  '
+
+pub fn ok() {}
index 26e4503a5d086dc7545c98f759c7fb76536f610a..ddfb23a4f86ba555a3cf20f84c2111e68a02356f 100644 (file)
@@ -31,46 +31,4 @@ assert-css: ("h2#implementations a.anchor", {"color": "rgb(0, 0, 0)"})
 move-cursor-to: "#impl"
 assert-css: ("#impl a.anchor", {"color": "rgb(0, 0, 0)"})
 
-// Now we check the positions: only the first heading of the top doc comment should
-// have a different position.
-move-cursor-to: ".top-doc .docblock .section-header:first-child"
-assert-css: (
-    ".top-doc .docblock .section-header:first-child > a::before",
-    {"left": "-10px", "padding-right": "10px"},
-)
-// We also check that the heading itself has a different indent.
-assert-css: (".top-doc .docblock .section-header:first-child", {"margin-left": "15px"})
-
-move-cursor-to: ".top-doc .docblock .section-header:not(:first-child)"
-assert-css: (
-    ".top-doc .docblock .section-header:not(:first-child) > a::before",
-    {"left": "-25px", "padding-right": "10px"},
-)
-assert-css: (".top-doc .docblock .section-header:not(:first-child)", {"margin-left": "0px"})
-
-// Now let's check some other docblock headings...
-// First the impl block docs.
-move-cursor-to: "#title-for-struct-impl-doc"
-assert-css: (
-    "#title-for-struct-impl-doc > a::before",
-    {"left": "-25px", "padding-right": "10px"},
-)
-assert-css: ("#title-for-struct-impl-doc", {"margin-left": "0px"})
-// Now a method docs.
-move-cursor-to: "#title-for-struct-impl-item-doc"
-assert-css: (
-    "#title-for-struct-impl-item-doc > a::before",
-    {"left": "-25px", "padding-right": "10px"},
-)
 assert-css: ("#title-for-struct-impl-item-doc", {"margin-left": "0px"})
-
-// Finally, we want to ensure that if the first element of the doc block isn't a heading,
-// if there is a heading afterwards, it won't have the indent.
-goto: file://|DOC_PATH|/test_docs/enum.WhoLetTheDogOut.html
-
-move-cursor-to: ".top-doc .docblock .section-header"
-assert-css: (
-    ".top-doc .docblock .section-header > a::before",
-    {"left": "-25px", "padding-right": "10px"},
-)
-assert-css: (".top-doc .docblock .section-header", {"margin-left": "0px"})
index 12677a5648a2d374db1aefa6736fc319bc022bad..02f79f1fcd7748524796cef14370341a26f4ee4c 100644 (file)
@@ -6,4 +6,4 @@ goto: file://|DOC_PATH|/test_docs/long_code_block/index.html
 show-text: true // We need to enable text draw to be able to have the "real" size
 // Little explanations for this test: if the text wasn't displayed on two lines, it would take
 // around 20px (which is the font size).
-assert-property: (".docblock p > code", {"offsetHeight": "42"})
+assert-property: (".docblock p > code", {"offsetHeight": "44"})
index 42bc1c100200528470d64421501565a08012e49d..a680635ef8ae411f068db93f530ee913be1a2903 100644 (file)
@@ -4,12 +4,8 @@ goto: file://|DOC_PATH|/test_docs/struct.Foo.html#method.borrow
 assert-attribute: ("#blanket-implementations-list > details:nth-child(2)", {"open": ""})
 // We first check that the impl block is open by default.
 assert-attribute: ("#implementations + details", {"open": ""})
-// We collapse it.
-click: "#implementations + details > summary"
-// We check that it was collapsed as expected.
-assert-attribute-false: ("#implementations + details", {"open": ""})
 // To ensure that we will click on the currently hidden method.
-assert-text: (".sidebar-links > a", "must_use")
-click: ".sidebar-links > a"
+assert-text: (".sidebar-elems section .block li > a", "must_use")
+click: ".sidebar-elems section .block li > a"
 // We check that the impl block was opened as expected so that we can see the method.
 assert-attribute: ("#implementations + details", {"open": ""})
index d58ca13a6291fbc855f3e3ae158a27d54485c5de..cf9caa2d5866a150ad2da9e3d88fe02a500c1682 100644 (file)
@@ -40,7 +40,8 @@ goto: file://|DOC_PATH|/test_docs/index.html
 assert-css: (".small-section-header a", {"color": "rgb(197, 197, 197)"}, ALL)
 
 goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
-assert-css: (".section-header a", {"color": "rgb(57, 175, 215)"}, ALL)
+// We select headings (h2, h3, h...).
+assert-css: (".docblock > :not(p) > a", {"color": "rgb(57, 175, 215)"}, ALL)
 
 // Dark theme
 local-storage: {
@@ -78,7 +79,8 @@ goto: file://|DOC_PATH|/test_docs/index.html
 assert-css: (".small-section-header a", {"color": "rgb(221, 221, 221)"}, ALL)
 
 goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
-assert-css: (".section-header a", {"color": "rgb(210, 153, 29)"}, ALL)
+// We select headings (h2, h3, h...).
+assert-css: (".docblock > :not(p) > a", {"color": "rgb(210, 153, 29)"}, ALL)
 
 // Light theme
 local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
@@ -111,4 +113,5 @@ goto: file://|DOC_PATH|/test_docs/index.html
 assert-css: (".small-section-header a", {"color": "rgb(0, 0, 0)"}, ALL)
 
 goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
-assert-css: (".section-header a", {"color": "rgb(56, 115, 173)"}, ALL)
+// We select headings (h2, h3, h...).
+assert-css: (".docblock > :not(p) > a", {"color": "rgb(56, 115, 173)"}, ALL)
index 48e0156f1b81b8ee7789e05138d4563efc9107a7..8f126d98fe44d4d4f846b1871057166f2923adea 100644 (file)
@@ -6,34 +6,33 @@
 // Most of these sizes are set in CSS in `em` units, so here's a conversion chart based on our
 // default 16px font size:
 // 24px    1.5em
-// 22.4px  1.4em
-// 20.8px  1.3em
-// 18.4px  1.15em
-// 17.6px  1.1em
-// 16px    1em
-// 15.2px  0.95em  
+// 22px  1.375rem
+// 20px  1.25rem
+// 18px  1.125em
+// 16px  1rem
+// 14px  0.875rem
 goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
 
-assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
-assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"})
 assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
-assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "17.6px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "18px"})
 assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
 
-assert-css: ("h2#fields", {"font-size": "22.4px"})
+assert-css: ("h2#fields", {"font-size": "22px"})
 assert-css: ("h2#fields", {"border-bottom-width": "1px"})
-assert-css: ("h3#title-for-field", {"font-size": "20.8px"})
+assert-css: ("h3#title-for-field", {"font-size": "20px"})
 assert-css: ("h3#title-for-field", {"border-bottom-width": "0px"})
 assert-css: ("h4#sub-heading-for-field", {"font-size": "16px"})
 assert-css: ("h4#sub-heading-for-field", {"border-bottom-width": "0px"})
 
-assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"font-size": "22px"})
 assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
 
-assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"font-size": "18px"})
 assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
 assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
 assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
@@ -42,27 +41,27 @@ assert-css: ("h4#title-for-struct-impl-doc", {"font-size": "16px"})
 assert-css: ("h4#title-for-struct-impl-doc", {"border-bottom-width": "0px"})
 assert-css: ("h5#sub-heading-for-struct-impl-doc", {"font-size": "16px"})
 assert-css: ("h5#sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
-assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"font-size": "14px"})
 assert-css: ("h6#sub-sub-heading-for-struct-impl-doc", {"border-bottom-width": "0px"})
 
 assert-css: ("h5#title-for-struct-impl-item-doc", {"font-size": "16px"})
 assert-css: ("h5#title-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
-assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"font-size": "14px"})
 assert-css: ("h6#sub-heading-for-struct-impl-item-doc", {"border-bottom-width": "0px"})
-assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "14px"})
 
 goto: file://|DOC_PATH|/test_docs/enum.HeavilyDocumentedEnum.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
 
-assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
-assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"})
 assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
-assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "17.6px"})
+assert-css: ("h4#top-doc-prose-sub-sub-heading", {"font-size": "18px"})
 assert-css: ("h4#top-doc-prose-sub-sub-heading", {"border-bottom-width": "1px"})
 
-assert-css: ("h2#variants", {"font-size": "22.4px"})
+assert-css: ("h2#variants", {"font-size": "22px"})
 assert-css: ("h2#variants", {"border-bottom-width": "1px"})
 
 assert-css: ("h4#none-prose-title", {"font-size": "16px"})
@@ -77,18 +76,18 @@ assert-css: ("h5#wrapped-prose-sub-heading", {"border-bottom-width": "0px"})
 
 assert-css: ("h5#wrapped0-prose-title", {"font-size": "16px"})
 assert-css: ("h5#wrapped0-prose-title", {"border-bottom-width": "0px"})
-assert-css: ("h6#wrapped0-prose-sub-heading", {"font-size": "15.2px"})
+assert-css: ("h6#wrapped0-prose-sub-heading", {"font-size": "14px"})
 assert-css: ("h6#wrapped0-prose-sub-heading", {"border-bottom-width": "0px"})
 
 assert-css: ("h5#structy-prose-title", {"font-size": "16px"})
 assert-css: ("h5#structy-prose-title", {"border-bottom-width": "0px"})
-assert-css: ("h6#structy-prose-sub-heading", {"font-size": "15.2px"})
+assert-css: ("h6#structy-prose-sub-heading", {"font-size": "14px"})
 assert-css: ("h6#structy-prose-sub-heading", {"border-bottom-width": "0px"})
 
-assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"font-size": "22px"})
 assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
 
-assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"font-size": "18px"})
 assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
 assert-css: ("#method\.do_nothing > h4.code-header", {"font-size": "16px"})
 assert-css: ("#method\.do_nothing > h4.code-header", {"border-bottom-width": "0px"})
@@ -97,14 +96,14 @@ assert-css: ("h4#title-for-enum-impl-doc", {"font-size": "16px"})
 assert-css: ("h4#title-for-enum-impl-doc", {"border-bottom-width": "0px"})
 assert-css: ("h5#sub-heading-for-enum-impl-doc", {"font-size": "16px"})
 assert-css: ("h5#sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
-assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"font-size": "14px"})
 assert-css: ("h6#sub-sub-heading-for-enum-impl-doc", {"border-bottom-width": "0px"})
 
 assert-css: ("h5#title-for-enum-impl-item-doc", {"font-size": "16px"})
 assert-css: ("h5#title-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
-assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"font-size": "14px"})
 assert-css: ("h6#sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
-assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "14px"})
 assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
 
 assert-text: (".sidebar .others h3", "Modules")
@@ -114,23 +113,23 @@ goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
 
-assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
-assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"})
 assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
 
-assert-css: ("h2#fields", {"font-size": "22.4px"})
+assert-css: ("h2#fields", {"font-size": "22px"})
 assert-css: ("h2#fields", {"border-bottom-width": "1px"})
 
-assert-css: ("h3#title-for-union-variant", {"font-size": "20.8px"})
+assert-css: ("h3#title-for-union-variant", {"font-size": "20px"})
 assert-css: ("h3#title-for-union-variant", {"border-bottom-width": "0px"})
 assert-css: ("h4#sub-heading-for-union-variant", {"font-size": "16px"})
 assert-css: ("h4#sub-heading-for-union-variant", {"border-bottom-width": "0px"})
 
-assert-css: ("h2#implementations", {"font-size": "22.4px"})
+assert-css: ("h2#implementations", {"font-size": "22px"})
 assert-css: ("h2#implementations", {"border-bottom-width": "1px"})
 
-assert-css: ("#impl > h3.code-header", {"font-size": "17.6px"})
+assert-css: ("#impl > h3.code-header", {"font-size": "18px"})
 assert-css: ("#impl > h3.code-header", {"border-bottom-width": "0px"})
 assert-css: ("h4#title-for-union-impl-doc", {"font-size": "16px"})
 assert-css: ("h4#title-for-union-impl-doc", {"border-bottom-width": "0px"})
@@ -139,16 +138,16 @@ assert-css: ("h5#sub-heading-for-union-impl-doc", {"border-bottom-width": "0px"}
 
 assert-css: ("h5#title-for-union-impl-item-doc", {"font-size": "16px"})
 assert-css: ("h5#title-for-union-impl-item-doc", {"border-bottom-width": "0px"})
-assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"font-size": "15.2px"})
+assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"font-size": "14px"})
 assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": "0px"})
 
 goto: file://|DOC_PATH|/test_docs/macro.heavily_documented_macro.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
 
-assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
+assert-css: ("h2#top-doc-prose-title", {"font-size": "22px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
-assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
+assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "20px"})
 assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
 
 goto: file://|DOC_PATH|/staged_api/struct.Foo.html
index c9042eb4813ab8a187dfb4969ddcb8bbb8d19a76..6460a917e92d008dc0885d6ca225d4d2d630f9db 100644 (file)
@@ -14,3 +14,7 @@ assert: ("#implementors-list .impl:nth-child(2) > a.anchor")
 assert-attribute: ("#implementors-list .impl:nth-child(2)", {"id": "impl-Whatever-1"})
 assert-attribute: ("#implementors-list .impl:nth-child(2) > a.anchor", {"href": "#impl-Whatever-1"})
 assert: "#implementors-list .impl:nth-child(2) > .code-header.in-band"
+
+goto: file://|DOC_PATH|/test_docs/struct.HasEmptyTraits.html
+compare-elements-position-near-false: ("#impl-EmptyTrait1", "#impl-EmptyTrait2", {"y": 30})
+compare-elements-position-near: ("#impl-EmptyTrait3 h3", "#impl-EmptyTrait3 .item-info", {"y": 30})
index acb30141ce577c9ff693714a14e7c2b4921adb4a..7a32d9029103a4067696b73da350f76957c41c76 100644 (file)
@@ -3,5 +3,6 @@ goto: file://|DOC_PATH|/lib2/struct.Foo.html
 // We set a fixed size so there is no chance of "random" resize.
 size: (1100, 800)
 // We check that ".item-info" is bigger than its content.
-assert-css: (".item-info", {"width": "757px"})
-assert-css: (".item-info .stab", {"width": "341px"})
+assert-css: (".item-info", {"width": "790px"})
+assert-css: (".item-info .stab", {"width": "340px"})
+assert-position: (".item-info .stab", {"x": 295})
index 7be46a613c4fb159323fb96e5831edfe2f5ee235..e70abcb83cf2beb76eacfd53d147aaa63d518abd 100644 (file)
@@ -11,7 +11,7 @@ assert-css: (".main-heading", {
   "flex-direction": "column"
 })
 
-assert-property: (".mobile-topbar h2.location", {"offsetHeight": 45})
+assert-property: (".mobile-topbar h2.location", {"offsetHeight": 36})
 
 // Note: We can't use assert-text here because the 'Since' is set by CSS and
 // is therefore not part of the DOM.
index 98ca40512ee3c319f0737699fcffa0eb6ef3490a..73d310fc5c9cc6464ef8d214c5667c5c1847c206 100644 (file)
@@ -11,8 +11,38 @@ wait-for: "#crate-search"
 click: "#crate-search"
 // We select "lib2" option then press enter to change the filter.
 press-key: "ArrowDown"
+press-key: "ArrowDown"
 press-key: "Enter"
 // Waiting for the search results to appear...
 wait-for: "#titles"
 // We check that there is no more "test_docs" appearing.
 assert-false: "#results .externcrate"
+// We also check that "lib2" is the filter crate.
+assert-property: ("#crate-search", {"value": "lib2"})
+
+// Now we check that leaving the search results and putting them back keeps the
+// crate filtering.
+press-key: "Escape"
+wait-for: 100
+assert-css: ("#main-content", {"display": "block"})
+focus: ".search-input"
+wait-for: 100
+assert-css: ("#main-content", {"display": "none"})
+// We check that there is no more "test_docs" appearing.
+assert-false: "#results .externcrate"
+assert-property: ("#crate-search", {"value": "lib2"})
+
+// Selecting back "All crates"
+click: "#crate-search"
+press-key: "ArrowUp"
+press-key: "ArrowUp"
+press-key: "Enter"
+// Waiting for the search results to appear...
+wait-for: "#titles"
+assert-property: ("#crate-search", {"value": "All crates"})
+
+// Checking that the URL parameter is taken into account for crate filtering.
+goto: file://|DOC_PATH|/test_docs/index.html?search=test&filter-crate=lib2
+wait-for: "#crate-search"
+assert-property: ("#crate-search", {"value": "lib2"})
+assert-false: "#results .externcrate"
index 60bcffe120beca8385c09f91fdd79427f077b9d2..79f18db8fc7cde424abeb23607bedd19a005a963 100644 (file)
@@ -33,10 +33,10 @@ assert-property: (".mobile-topbar", {"clientHeight": "45"})
 // Check that clicking an element from the sidebar scrolls to the right place
 // so the target is not obscured by the topbar.
 click: ".sidebar-menu-toggle"
-click: ".sidebar-links a"
+click: ".sidebar-elems section .block li > a"
 assert-position: ("#method\.must_use", {"y": 45})
 
 // Check that the bottom-most item on the sidebar menu can be scrolled fully into view.
 click: ".sidebar-menu-toggle"
 scroll-to: ".block.keyword li:nth-child(1)"
-assert-position: (".block.keyword li:nth-child(1)", {"y": 542.96875})
+compare-elements-position-near: (".block.keyword li:nth-child(1)", ".mobile-topbar", {"y": 543})
index 1c5eb9239ba8bba6468a73153205a0e4d10a8513..0cb8e7763851c661c529540d7682b1915186c180 100644 (file)
@@ -10,7 +10,7 @@ click: (10, 10)
 // We wait for the sidebar to be expanded (there is a 0.5s animation).
 wait-for: 600
 assert-css: ("nav.sidebar.expanded", {"width": "300px"})
-assert-css: ("nav.sidebar.expanded a", {"font-size": "14.4px"})
+assert-css: ("nav.sidebar.expanded a", {"font-size": "14px"})
 // We collapse the sidebar.
 click: (10, 10)
 // We wait for the sidebar to be collapsed (there is a 0.5s animation).
index ef3a92ad7a6ced12f467c7f3cec63962a91811a8..6b79b00d3f7862589a765b0da9fca70aa12dc33c 100644 (file)
@@ -13,15 +13,15 @@ assert-css: ("#all-types", {"color": "rgb(53, 109, 164)"})
 // We check that we have the crates list and that the "current" on is "test_docs".
 assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs")
 // And we're also supposed to have the list of items in the current module.
-assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Modules")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(2)", "Macros")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(3)", "Structs")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(4)", "Enums")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(5)", "Traits")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(6)", "Functions")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(7)", "Type Definitions")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(8)", "Unions")
-assert-text: (".sidebar-elems .items > ul > li:nth-child(9)", "Keywords")
+assert-text: (".sidebar-elems section ul > li:nth-child(1)", "Modules")
+assert-text: (".sidebar-elems section ul > li:nth-child(2)", "Macros")
+assert-text: (".sidebar-elems section ul > li:nth-child(3)", "Structs")
+assert-text: (".sidebar-elems section ul > li:nth-child(4)", "Enums")
+assert-text: (".sidebar-elems section ul > li:nth-child(5)", "Traits")
+assert-text: (".sidebar-elems section ul > li:nth-child(6)", "Functions")
+assert-text: (".sidebar-elems section ul > li:nth-child(7)", "Type Definitions")
+assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Unions")
+assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Keywords")
 assert-text: ("#structs + .item-table .item-left > a", "Foo")
 click: "#structs + .item-table .item-left > a"
 
@@ -30,7 +30,7 @@ assert-count: (".sidebar .location", 2)
 // We check that there is no crate listed outside of the top level.
 assert-false: ".sidebar-elems > .crate"
 
-click: ".sidebar-links a"
+click: ".sidebar-elems section .block li > a"
 assert-property-false: ("html", {"scrollTop": "0"})
 
 click: ".sidebar h2.location a"
@@ -47,11 +47,11 @@ assert-text: (".sidebar > .location", "Crate lib2")
 // We check that we have the crates list and that the "current" on is now "lib2".
 assert-text: (".sidebar-elems .crate > ul > li > a.current", "lib2")
 // We now go to the "foobar" function page.
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(3)", "Traits")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(4)", "Functions")
-assert-text: (".sidebar-elems > .items > ul > li:nth-child(5)", "Type Definitions")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(1)", "Modules")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(2)", "Structs")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(3)", "Traits")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(4)", "Functions")
+assert-text: (".sidebar-elems > section .block ul > li:nth-child(5)", "Type Definitions")
 assert-text: ("#functions + .item-table .item-left > a", "foobar")
 click: "#functions + .item-table .item-left > a"
 
@@ -72,9 +72,16 @@ goto: ./sub_module/sub_sub_module/index.html
 assert-text: (".sidebar > .location", "Module sub_sub_module")
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems .crate"
-assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Functions")
+assert-text: (".sidebar-elems > section ul > li:nth-child(1)", "Functions")
 assert-text: ("#functions + .item-table .item-left > a", "foo")
 
 // Links to trait implementations in the sidebar should not wrap even if they are long.
 goto: file://|DOC_PATH|/lib2/struct.HasALongTraitWithParams.html
-assert-property: (".sidebar-links a", {"offsetHeight": 29})
+assert-property: (".sidebar-elems section .block li > a", {"offsetHeight": 29})
+
+// Test that clicking on of the "In <module>" headings in the sidebar links to the
+// appropriate anchor in index.html.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+click: ".block.mod h3 a"
+// PAGE: index.html
+assert-css: ("#modules", {"background-color": "rgb(253, 255, 211)"})
index b0b2f122afdb90b7fe362b9f39d39ad3fbf069ce..0c01e25455486232a54522398f6bfad0afcee192 100644 (file)
@@ -4,9 +4,8 @@
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
 show-text: true
 // Check the impl headers.
-assert-css: (".impl.has-srclink .srclink", {"font-size": "17px"}, ALL)
-// The ".6" part is because the font-size is actually "1.1em".
-assert-css: (".impl.has-srclink .code-header.in-band", {"font-size": "17.6px"}, ALL)
+assert-css: (".impl.has-srclink .srclink", {"font-size": "16px"}, ALL)
+assert-css: (".impl.has-srclink .code-header.in-band", {"font-size": "18px"}, ALL)
 // Check the impl items.
 assert-css: (".impl-items .has-srclink .srclink", {"font-size": "16px"}, ALL)
 assert-css: (".impl-items .has-srclink .code-header", {"font-size": "16px"}, ALL)
index 5f527078e79a84185bed4544a54d238818682b0b..8be819b76e4134a700755f354145b182dec09362 100644 (file)
@@ -7,3 +7,7 @@ build = "build.rs"
 
 [lib]
 path = "lib.rs"
+
+[features]
+default = ["some-feature"]
+some-feature = []
index f75de949292a1b151a5ddd234f3e64d1ac25c7f6..2068d1d6f39af1e1867d4e4d2b951c483a7eb59f 100644 (file)
@@ -260,3 +260,14 @@ pub fn do_nothing() {}
 macro_rules! heavily_documented_macro {
     () => {};
 }
+
+pub trait EmptyTrait1 {}
+pub trait EmptyTrait2 {}
+pub trait EmptyTrait3 {}
+
+pub struct HasEmptyTraits{}
+
+impl EmptyTrait1 for HasEmptyTraits {}
+impl EmptyTrait2 for HasEmptyTraits {}
+#[doc(cfg(feature = "some-feature"))]
+impl EmptyTrait3 for HasEmptyTraits {}
index 38942baa0b5974c6926807455882bad64c21b2bc..d77d1dca483e0e0cbbb03cb169d98e08f9314bc0 100644 (file)
@@ -1,8 +1,8 @@
 // Checks that the elements in the sidebar are alphabetically sorted.
 goto: file://|DOC_PATH|/test_docs/trait.AnotherOne.html
-assert-text: (".sidebar-links a:nth-of-type(1)", "another")
-assert-text: (".sidebar-links a:nth-of-type(2)", "func1")
-assert-text: (".sidebar-links a:nth-of-type(3)", "func2")
-assert-text: (".sidebar-links a:nth-of-type(4)", "func3")
-assert-text: (".sidebar-links a:nth-of-type(5)", "hello")
-assert-text: (".sidebar-links a:nth-of-type(6)", "why_not")
+assert-text: (".sidebar-elems section .block li:nth-of-type(1) > a", "another")
+assert-text: (".sidebar-elems section .block li:nth-of-type(2) > a", "func1")
+assert-text: (".sidebar-elems section .block li:nth-of-type(3) > a", "func2")
+assert-text: (".sidebar-elems section .block li:nth-of-type(4) > a", "func3")
+assert-text: (".sidebar-elems section .block li:nth-of-type(5) > a", "hello")
+assert-text: (".sidebar-elems section .block li:nth-of-type(6) > a", "why_not")
index 229c6d6ba6b9682f454fb5af4baa1d7b3c903d54..22212a31728dca6dc06524be2c9cc60e216a10fc 100644 (file)
@@ -31,6 +31,7 @@ assert-property: (".item-decl pre", {"scrollWidth": "950"})
 // On mobile:
 size: (600, 600)
 goto: file://|DOC_PATH|/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html
-assert-property: (".mobile-topbar .location", {"scrollWidth": "986"})
-assert-property: (".mobile-topbar .location", {"clientWidth": "504"})
+// It shouldn't have an overflow in the topbar either.
+assert-property: (".mobile-topbar .location", {"scrollWidth": "492"})
+assert-property: (".mobile-topbar .location", {"clientWidth": "492"})
 assert-css: (".mobile-topbar .location", {"overflow-x": "hidden"})
diff --git a/src/test/rustdoc-js-std/multi-query.js b/src/test/rustdoc-js-std/multi-query.js
deleted file mode 100644 (file)
index 1c92d01..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-const QUERY = 'str,u8';
-
-const EXPECTED = {
-    'others': [
-        { 'path': 'std', 'name': 'str', 'href': '../std/primitive.str.html' },
-        { 'path': 'std', 'name': 'u8', 'href': '../std/primitive.u8.html'  },
-        { 'path': 'std', 'name': 'str', 'href': '../std/str/index.html' },
-        { 'path': 'std', 'name': 'u8', 'href': '../std/u8/index.html' },
-    ],
-};
index f656aa72986fdb52a601c1526a0cd68983cbc526..3915ee7dc5d23196249c8499452744471076cfbb 100644 (file)
@@ -8,5 +8,7 @@ const EXPECTED = {
         { 'path': 'std', 'name': 'eprint' },
         { 'path': 'std', 'name': 'println' },
         { 'path': 'std', 'name': 'eprintln' },
+        { 'path': 'std::pin', 'name': 'pin' },
+        { 'path': 'core::pin', 'name': 'pin' },
     ],
 };
diff --git a/src/test/rustdoc-json/type/dyn.rs b/src/test/rustdoc-json/type/dyn.rs
new file mode 100644 (file)
index 0000000..f53dc03
--- /dev/null
@@ -0,0 +1,21 @@
+// ignore-tidy-linelength
+
+// @count dyn.json "$.index[*][?(@.name=='dyn')].inner.items" 1
+// @set sync_int_gen = - "$.index[*][?(@.name=='SyncIntGen')].id"
+// @is - "$.index[*][?(@.name=='dyn')].inner.items[0]" $sync_int_gen
+
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].kind" \"typedef\"
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.generics" '{"params": [], "where_predicates": []}'
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.kind" \"resolved_path\"
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.name" \"Box\"
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.bindings" []
+// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args" 1
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"resolved_path\"
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.name" \"Fn\"
+// @count - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[*]" 3
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[0].trait_bound.trait.inner.name" \"Send\"
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[1].trait_bound.trait.inner.name" \"Sync\"
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.param_names[2]" "{\"outlives\": \"'static\"}"
+// @is    - "$.index[*][?(@.name=='SyncIntGen')].inner.type.inner.args.angle_bracketed.args[0].type.inner.args" '{"parenthesized": {"inputs": [],"output": {"inner": "i32","kind": "primitive"}}}'
+pub type SyncIntGen = Box<dyn Fn() -> i32 + Send + Sync + 'static>;
diff --git a/src/test/rustdoc-json/type/fn_lifetime.rs b/src/test/rustdoc-json/type/fn_lifetime.rs
new file mode 100644 (file)
index 0000000..e0d1e96
--- /dev/null
@@ -0,0 +1,28 @@
+// ignore-tidy-linelength
+
+// @is fn_lifetime.json "$.index[*][?(@.name=='GenericFn')].kind" \"typedef\"
+
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*]" 1
+// @is    - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].name" \"\'a\"
+// @has   - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime"
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.params[*].kind.lifetime.outlives[*]" 0
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.generics.where_predicates[*]" 0
+// @is    - "$.index[*][?(@.name=='GenericFn')].inner.type.kind" \"function_pointer\"
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.generic_params[*]" 0
+// @count - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*]" 1
+// @is    - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\"
+// @is    - "$.index[*][?(@.name=='GenericFn')].inner.type.inner.decl.output.inner.lifetime" \"\'a\"
+
+pub type GenericFn<'a> = fn(&'a i32) -> &'a i32;
+
+// @is fn_lifetime.json "$.index[*][?(@.name=='ForAll')].kind" \"typedef\"
+// @count - "$.index[*][?(@.name=='ForAll')].inner.generics.params[*]" 0
+// @count - "$.index[*][?(@.name=='ForAll')].inner.generics.where_predicates[*]" 0
+// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*]" 1
+// @is    - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].name" \"\'a\"
+// @has   - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime"
+// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.generic_params[*].kind.lifetime.outlives[*]" 0
+// @count - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*]" 1
+// @is    - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.inputs[*][1].inner.lifetime" \"\'a\"
+// @is    - "$.index[*][?(@.name=='ForAll')].inner.type.inner.decl.output.inner.lifetime" \"\'a\"
+pub type ForAll = for<'a> fn(&'a i32) -> &'a i32;
diff --git a/src/test/rustdoc-json/type/generic_default.rs b/src/test/rustdoc-json/type/generic_default.rs
new file mode 100644 (file)
index 0000000..b6bb6dc
--- /dev/null
@@ -0,0 +1,33 @@
+// ignore-tidy-linelength
+
+// @set result = generic_default.json "$.index[*][?(@.name=='Result')].id"
+pub enum Result<T, E> {
+    Ok(T),
+    Err(E),
+}
+
+// @set my_error = - "$.index[*][?(@.name=='MyError')].id"
+pub struct MyError {}
+
+// @is    - "$.index[*][?(@.name=='MyResult')].kind" \"typedef\"
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.where_predicates[*]" 0
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[*]" 2
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].name" \"T\"
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].name" \"E\"
+// @has   - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type"
+// @has   - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type"
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.bounds[*]" 0
+// @count - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.bounds[*]" 0
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.generics.params[0].kind.type.default" null
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.kind" \"resolved_path\"
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.id" $my_error
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.generics.params[1].kind.type.default.inner.name" \"MyError\"
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.type.kind" \"resolved_path\"
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.type.inner.id" $result
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.type.inner.name" \"Result\"
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.bindings" []
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.kind" \"generic\"
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.kind" \"generic\"
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[0].type.inner" \"T\"
+// @is    - "$.index[*][?(@.name=='MyResult')].inner.type.inner.args.angle_bracketed.args[1].type.inner" \"E\"
+pub type MyResult<T, E = MyError> = Result<T, E>;
diff --git a/src/test/rustdoc-ui/block-doc-comment.rs b/src/test/rustdoc-ui/block-doc-comment.rs
new file mode 100644 (file)
index 0000000..c60dfa3
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+// compile-flags:--test
+
+// This test ensures that no code block is detected in the doc comments.
+
+pub mod Wormhole {
+    /** # Returns
+     *
+     */
+    pub fn foofoo() {}
+    /**
+     * # Returns
+     *
+     */
+    pub fn barbar() {}
+}
diff --git a/src/test/rustdoc-ui/block-doc-comment.stdout b/src/test/rustdoc-ui/block-doc-comment.stdout
new file mode 100644 (file)
index 0000000..e5c27be
--- /dev/null
@@ -0,0 +1,5 @@
+
+running 0 tests
+
+test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+
index 023d620bea2225d13fa04217d591d26c2d424217..e955470148a16cba9c857c43d0877f5d9f99f539 100644 (file)
@@ -23,13 +23,6 @@ pub fn bar() {}
 /// ```
 pub fn foobar() {}
 
-/// barfoo
-///
-/// ```allow-fail,allowfail,allOw_fail
-/// boo
-/// ```
-pub fn barfoo() {}
-
 /// b
 ///
 /// ```test-harness,testharness,tesT_harness
index affd0372a1f5e6d49412d3d2ee70a52a934930f5..b1fa9edf0e4cb3cb6ed3c688e5a8ce3f50cb0c1e 100644 (file)
@@ -111,77 +111,41 @@ error: unknown attribute `nO_run`. Did you mean `no_run`?
    |
    = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
 
-error: unknown attribute `allow-fail`. Did you mean `allow_fail`?
+error: unknown attribute `test-harness`. Did you mean `test_harness`?
   --> $DIR/check-attr-test.rs:26:1
    |
-26 | / /// barfoo
+26 | / /// b
 27 | | ///
-28 | | /// ```allow-fail,allowfail,allOw_fail
+28 | | /// ```test-harness,testharness,tesT_harness
 29 | | /// boo
 30 | | /// ```
    | |_______^
    |
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
 
-error: unknown attribute `allowfail`. Did you mean `allow_fail`?
+error: unknown attribute `testharness`. Did you mean `test_harness`?
   --> $DIR/check-attr-test.rs:26:1
    |
-26 | / /// barfoo
+26 | / /// b
 27 | | ///
-28 | | /// ```allow-fail,allowfail,allOw_fail
+28 | | /// ```test-harness,testharness,tesT_harness
 29 | | /// boo
 30 | | /// ```
    | |_______^
    |
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
+   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
 
-error: unknown attribute `allOw_fail`. Did you mean `allow_fail`?
+error: unknown attribute `tesT_harness`. Did you mean `test_harness`?
   --> $DIR/check-attr-test.rs:26:1
    |
-26 | / /// barfoo
+26 | / /// b
 27 | | ///
-28 | | /// ```allow-fail,allowfail,allOw_fail
+28 | | /// ```test-harness,testharness,tesT_harness
 29 | | /// boo
 30 | | /// ```
-   | |_______^
-   |
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
-
-error: unknown attribute `test-harness`. Did you mean `test_harness`?
-  --> $DIR/check-attr-test.rs:33:1
-   |
-33 | / /// b
-34 | | ///
-35 | | /// ```test-harness,testharness,tesT_harness
-36 | | /// boo
-37 | | /// ```
-   | |_______^
-   |
-   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
-
-error: unknown attribute `testharness`. Did you mean `test_harness`?
-  --> $DIR/check-attr-test.rs:33:1
-   |
-33 | / /// b
-34 | | ///
-35 | | /// ```test-harness,testharness,tesT_harness
-36 | | /// boo
-37 | | /// ```
-   | |_______^
-   |
-   = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
-
-error: unknown attribute `tesT_harness`. Did you mean `test_harness`?
-  --> $DIR/check-attr-test.rs:33:1
-   |
-33 | / /// b
-34 | | ///
-35 | | /// ```test-harness,testharness,tesT_harness
-36 | | /// boo
-37 | | /// ```
    | |_______^
    |
    = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
 
-error: aborting due to 15 previous errors
+error: aborting due to 12 previous errors
 
index 763bc4c6cddb90028ab956064225984c7f40fcc6..0b3f7bedda5cf9b442a625b2a97e7bb90bd71141 100644 (file)
@@ -30,16 +30,6 @@ pub fn bar() {}
 /// ```
 pub fn foobar() {}
 
-/// barfoo
-//~^ ERROR
-//~^^ ERROR
-//~^^^ ERROR
-///
-/// ```allow-fail,allowfail,alLow_fail
-/// boo
-/// ```
-pub fn barfoo() {}
-
 /// b
 //~^ ERROR
 //~^^ ERROR
index 9312cfb76f35f4a52e35bffb7242571b30f80819..370b804c56c64a840e3cfd37d909b15342e13be3 100644 (file)
@@ -129,50 +129,8 @@ LL | | /// ```
    |
    = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
 
-error: unknown attribute `allow-fail`. Did you mean `allow_fail`?
-  --> $DIR/check-attr.rs:33:1
-   |
-LL | / /// barfoo
-LL | |
-LL | |
-LL | |
-...  |
-LL | | /// boo
-LL | | /// ```
-   | |_______^
-   |
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
-
-error: unknown attribute `allowfail`. Did you mean `allow_fail`?
-  --> $DIR/check-attr.rs:33:1
-   |
-LL | / /// barfoo
-LL | |
-LL | |
-LL | |
-...  |
-LL | | /// boo
-LL | | /// ```
-   | |_______^
-   |
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
-
-error: unknown attribute `alLow_fail`. Did you mean `allow_fail`?
-  --> $DIR/check-attr.rs:33:1
-   |
-LL | / /// barfoo
-LL | |
-LL | |
-LL | |
-...  |
-LL | | /// boo
-LL | | /// ```
-   | |_______^
-   |
-   = help: the code block will either not be tested if not marked as a rust one or will be run (which you might not want)
-
 error: unknown attribute `test-harness`. Did you mean `test_harness`?
-  --> $DIR/check-attr.rs:43:1
+  --> $DIR/check-attr.rs:33:1
    |
 LL | / /// b
 LL | |
@@ -186,7 +144,7 @@ LL | | /// ```
    = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
 
 error: unknown attribute `testharness`. Did you mean `test_harness`?
-  --> $DIR/check-attr.rs:43:1
+  --> $DIR/check-attr.rs:33:1
    |
 LL | / /// b
 LL | |
@@ -200,7 +158,7 @@ LL | | /// ```
    = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
 
 error: unknown attribute `teSt_harness`. Did you mean `test_harness`?
-  --> $DIR/check-attr.rs:43:1
+  --> $DIR/check-attr.rs:33:1
    |
 LL | / /// b
 LL | |
@@ -213,5 +171,5 @@ LL | | /// ```
    |
    = help: the code block will either not be tested if not marked as a rust one or the code will be wrapped inside a main function
 
-error: aborting due to 15 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/test/rustdoc-ui/intra-doc/macro-rules.rs b/src/test/rustdoc-ui/intra-doc/macro-rules.rs
new file mode 100644 (file)
index 0000000..a14e4bd
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+#![allow(rustdoc::private_intra_doc_links)]
+
+macro_rules! foo {
+    () => {};
+}
+
+/// [foo!]
+pub fn baz() {}
diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.rs
new file mode 100644 (file)
index 0000000..744b307
--- /dev/null
@@ -0,0 +1,38 @@
+#![deny(rustdoc::invalid_html_tags)]
+
+/// This Vec<32> thing!
+// Numbers aren't valid HTML tags, so no error.
+pub struct ConstGeneric;
+
+/// This Vec<i32, i32> thing!
+// HTML tags cannot contain commas, so no error.
+pub struct MultipleGenerics;
+
+/// This Vec<i32 class="test"> thing!
+//~^ERROR unclosed HTML tag `i32`
+// HTML attributes shouldn't be treated as Rust syntax, so no suggestions.
+pub struct TagWithAttributes;
+
+/// This Vec<i32></i32> thing!
+// There should be no error, and no suggestion, since the tags are balanced.
+pub struct DoNotWarnOnMatchingTags;
+
+/// This Vec</i32> thing!
+//~^ERROR unopened HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct EndTagsAreNotValidRustSyntax;
+
+/// This 123<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct NumbersAreNotPaths;
+
+/// This Vec:<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct InvalidTurbofish;
+
+/// This [link](https://rust-lang.org)<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+// This should produce an error, but no suggestion.
+pub struct BareTurbofish;
diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr b/src/test/rustdoc-ui/suggestions/html-as-generics-no-suggestions.stderr
new file mode 100644 (file)
index 0000000..832b8b2
--- /dev/null
@@ -0,0 +1,38 @@
+error: unclosed HTML tag `i32`
+  --> $DIR/html-as-generics-no-suggestions.rs:11:13
+   |
+LL | /// This Vec<i32 class="test"> thing!
+   |             ^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/html-as-generics-no-suggestions.rs:1:9
+   |
+LL | #![deny(rustdoc::invalid_html_tags)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: unopened HTML tag `i32`
+  --> $DIR/html-as-generics-no-suggestions.rs:20:13
+   |
+LL | /// This Vec</i32> thing!
+   |             ^^^^^^
+
+error: unclosed HTML tag `i32`
+  --> $DIR/html-as-generics-no-suggestions.rs:25:13
+   |
+LL | /// This 123<i32> thing!
+   |             ^^^^^
+
+error: unclosed HTML tag `i32`
+  --> $DIR/html-as-generics-no-suggestions.rs:30:14
+   |
+LL | /// This Vec:<i32> thing!
+   |              ^^^^^
+
+error: unclosed HTML tag `i32`
+  --> $DIR/html-as-generics-no-suggestions.rs:35:39
+   |
+LL | /// This [link](https://rust-lang.org)<i32> thing!
+   |                                       ^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.fixed b/src/test/rustdoc-ui/suggestions/html-as-generics.fixed
new file mode 100644 (file)
index 0000000..c0a0de2
--- /dev/null
@@ -0,0 +1,32 @@
+// run-rustfix
+#![deny(rustdoc::invalid_html_tags)]
+
+/// This `Vec<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Generic;
+
+/// This `vec::Vec<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct GenericPath;
+
+/// This `i32<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct PathsCanContainTrailingNumbers;
+
+/// This `Vec::<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Turbofish;
+
+/// This [link](https://rust-lang.org)`::<i32>` thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct BareTurbofish;
+
+/// This <span>`Vec::<i32>`</span> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Nested;
diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.rs b/src/test/rustdoc-ui/suggestions/html-as-generics.rs
new file mode 100644 (file)
index 0000000..0b6009b
--- /dev/null
@@ -0,0 +1,32 @@
+// run-rustfix
+#![deny(rustdoc::invalid_html_tags)]
+
+/// This Vec<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Generic;
+
+/// This vec::Vec<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct GenericPath;
+
+/// This i32<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct PathsCanContainTrailingNumbers;
+
+/// This Vec::<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Turbofish;
+
+/// This [link](https://rust-lang.org)::<i32> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct BareTurbofish;
+
+/// This <span>Vec::<i32></span> thing!
+//~^ERROR unclosed HTML tag `i32`
+//~|HELP try marking as source
+pub struct Nested;
diff --git a/src/test/rustdoc-ui/suggestions/html-as-generics.stderr b/src/test/rustdoc-ui/suggestions/html-as-generics.stderr
new file mode 100644 (file)
index 0000000..df54b71
--- /dev/null
@@ -0,0 +1,73 @@
+error: unclosed HTML tag `i32`
+  --> $DIR/html-as-generics.rs:4:13
+   |
+LL | /// This Vec<i32> thing!
+   |             ^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/html-as-generics.rs:2:9
+   |
+LL | #![deny(rustdoc::invalid_html_tags)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: try marking as source code
+   |
+LL | /// This `Vec<i32>` thing!
+   |          +        +
+
+error: unclosed HTML tag `i32`
+  --> $DIR/html-as-generics.rs:9:18
+   |
+LL | /// This vec::Vec<i32> thing!
+   |                  ^^^^^
+   |
+help: try marking as source code
+   |
+LL | /// This `vec::Vec<i32>` thing!
+   |          +             +
+
+error: unclosed HTML tag `i32`
+  --> $DIR/html-as-generics.rs:14:13
+   |
+LL | /// This i32<i32> thing!
+   |             ^^^^^
+   |
+help: try marking as source code
+   |
+LL | /// This `i32<i32>` thing!
+   |          +        +
+
+error: unclosed HTML tag `i32`
+  --> $DIR/html-as-generics.rs:19:15
+   |
+LL | /// This Vec::<i32> thing!
+   |               ^^^^^
+   |
+help: try marking as source code
+   |
+LL | /// This `Vec::<i32>` thing!
+   |          +          +
+
+error: unclosed HTML tag `i32`
+  --> $DIR/html-as-generics.rs:24:41
+   |
+LL | /// This [link](https://rust-lang.org)::<i32> thing!
+   |                                         ^^^^^
+   |
+help: try marking as source code
+   |
+LL | /// This [link](https://rust-lang.org)`::<i32>` thing!
+   |                                       +       +
+
+error: unclosed HTML tag `i32`
+  --> $DIR/html-as-generics.rs:29:21
+   |
+LL | /// This <span>Vec::<i32></span> thing!
+   |                     ^^^^^
+   |
+help: try marking as source code
+   |
+LL | /// This <span>`Vec::<i32>`</span> thing!
+   |                +          +
+
+error: aborting due to 6 previous errors
+
index 6ae5e20632e521b212bdec85b90e29337f13cb04..da50fb86cd581a57bf6694df89e97a591677d2ec 100644 (file)
@@ -10,7 +10,7 @@ pub trait Trait {
 
 // @has 'foo/struct.Bar.html'
 // @has - '//h3[@class="sidebar-title"]' 'Associated Constants'
-// @has - '//div[@class="sidebar-elems"]//div[@class="sidebar-links"]/a' 'FOO'
+// @has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Trait for Bar {
     const FOO: u32 = 1;
 
@@ -23,7 +23,7 @@ pub enum Foo {
 
 // @has 'foo/enum.Foo.html'
 // @has - '//h3[@class="sidebar-title"]' 'Associated Constants'
-// @has - '//div[@class="sidebar-elems"]//div[@class="sidebar-links"]/a' 'FOO'
+// @has - '//div[@class="sidebar-elems"]//a' 'FOO'
 impl Trait for Foo {
     const FOO: u32 = 1;
 
index 6d85171edf784f805bbe5a88f395307f9ccdca90..0277501de097f956517d1ae6c14d33d89ea0e30f 100644 (file)
@@ -77,12 +77,12 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T }
 
 impl Foo {
     // @has async_fn/struct.Foo.html
-    // @has - '//div[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
+    // @has - '//*[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>'
     pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {}
     // taken from `tokio` as an example of a method that was particularly bad before
-    // @has - '//div[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
+    // @has - '//*[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>"
     pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {}
-    // @has - '//div[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
+    // @has - '//*[@class="method has-srclink"]' "pub async fn mut_self(&mut self)"
     pub async fn mut_self(&mut self) {}
 }
 
index 01ea09a94614a71be37d2c9b463bdf2bc32cb43e..a047c76b637d4cdf6a2c69d58e104e6bcf8dea20 100644 (file)
@@ -1,6 +1,6 @@
 #![feature(auto_traits)]
 
-// @has auto_aliases/trait.Bar.html '//div[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
+// @has auto_aliases/trait.Bar.html '//*[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo'
 pub struct Foo;
 
 pub auto trait Bar {}
index b934d84a9f616e290036907b4ad620e19c41ddb7..4c686730b1152b1fd877601e9f39d83cc724106b 100644 (file)
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// @has foo/struct.S.html '//div[@id="impl-Into%3CU%3E"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T'
+// @has foo/struct.S.html '//*[@id="impl-Into%3CU%3E"]//h3[@class="code-header in-band"]' 'impl<T, U> Into<U> for T'
 pub struct S2 {}
 mod m {
     pub struct S {}
index b8e101038f8f11b4ba74c1f8f97c7aabd148807d..e3f5d074783044cfe8b615d3b25301346d0a3767 100644 (file)
@@ -49,19 +49,19 @@ pub const fn bar2() -> u32 { 42 }
 pub struct Foo;
 
 impl Foo {
-    // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/h4[@class="code-header"]' 'pub fn gated() -> u32'
+    // @has 'foo/struct.Foo.html' '//*[@id="method.gated"]/h4[@class="code-header"]' 'pub fn gated() -> u32'
     // @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature="foo", issue = "none")]
     pub const fn gated() -> u32 { 42 }
 
-    // @has 'foo/struct.Foo.html' '//div[@id="method.gated_unsafe"]/h4[@class="code-header"]' 'pub unsafe fn gated_unsafe() -> u32'
+    // @has 'foo/struct.Foo.html' '//*[@id="method.gated_unsafe"]/h4[@class="code-header"]' 'pub unsafe fn gated_unsafe() -> u32'
     // @has - '//span[@class="since"]' '1.0.0 (const: unstable)'
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature="foo", issue = "none")]
     pub const unsafe fn gated_unsafe() -> u32 { 42 }
 
-    // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/h4[@class="code-header"]' 'pub const fn stable_impl() -> u32'
+    // @has 'foo/struct.Foo.html' '//*[@id="method.stable_impl"]/h4[@class="code-header"]' 'pub const fn stable_impl() -> u32'
     // @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "rust1", since = "1.2.0")]
index 7e38eb8369a8a7bbded402663945ec8d0d65cd8a..e54f9a57ae4ee8abd1ed97139d7dbe5a340e75f0 100644 (file)
@@ -7,7 +7,7 @@ pub struct Simd<T, const WIDTH: usize> {
     inner: T,
 }
 
-// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//div/h3[@class="code-header in-band"]' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
+// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3[@class="code-header in-band"]' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>'
 impl Add for Simd<u8, 16> {
     type Output = Self;
 
index b20663c6d68a5736e252d9baba89e6fa611c6f50..4279de91f56c1420bab481156484d54cdd9fe939 100644 (file)
@@ -5,7 +5,7 @@ pub trait Array {
 }
 
 // @has foo/trait.Array.html
-// @has - '//div[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
-impl <T, const N: usize> Array for [T; N] {
+// @has - '//*[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]'
+impl<T, const N: usize> Array for [T; N] {
     type Item = T;
 }
index 92d2c4697e7edea020355356ed6f78308a48fb7f..fc3a2731089eb406381f6ff37add7f4555b02f87 100644 (file)
@@ -36,7 +36,7 @@ impl Trait<{1 + 2}> for u8 {}
 // @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)'
 pub struct Bar<T, const N: usize>([T; N]);
 
-// @has foo/struct.Foo.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
+// @has foo/struct.Foo.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Foo<M> where u8: Trait<M>'
 impl<const M: usize> Foo<M> where u8: Trait<M> {
     // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize'
     pub const FOO_ASSOC: usize = M + 13;
@@ -47,7 +47,7 @@ pub fn hey<const N: usize>(&self) -> Bar<u8, N> {
     }
 }
 
-// @has foo/struct.Bar.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>'
+// @has foo/struct.Bar.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<const M: usize> Bar<u8, M>'
 impl<const M: usize> Bar<u8, M> {
     // @has - '//*[@id="method.hey"]' \
     //      'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>'
index cda900773abfa5968d84545d550863567c41af55..a3ef084165a8a580213d830c74f6e4360d79576d 100644 (file)
@@ -1,7 +1,5 @@
 #![allow(incomplete_features)]
-
 #![feature(adt_const_params)]
-
 #![crate_name = "foo"]
 
 #[derive(PartialEq, Eq)]
@@ -11,20 +9,20 @@ pub enum Order {
 }
 
 // @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>'
-// @has foo/struct.VSet.html '//div[@id="impl-Send"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
-// @has foo/struct.VSet.html '//div[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//*[@id="impl-Send"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>'
+// @has foo/struct.VSet.html '//*[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>'
 pub struct VSet<T, const ORDER: Order> {
     inner: Vec<T>,
 }
 
-// @has foo/struct.VSet.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>'
+// @has foo/struct.VSet.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Sorted }>'
 impl<T> VSet<T, { Order::Sorted }> {
     pub fn new() -> Self {
         Self { inner: Vec::new() }
     }
 }
 
-// @has foo/struct.VSet.html '//div[@id="impl-1"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>'
+// @has foo/struct.VSet.html '//*[@id="impl-1"]/h3[@class="code-header in-band"]' 'impl<T> VSet<T, { Order::Unsorted }>'
 impl<T> VSet<T, { Order::Unsorted }> {
     pub fn new() -> Self {
         Self { inner: Vec::new() }
@@ -33,7 +31,7 @@ pub fn new() -> Self {
 
 pub struct Escape<const S: &'static str>;
 
-// @has foo/struct.Escape.html '//div[@id="impl"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
+// @has foo/struct.Escape.html '//*[@id="impl"]/h3[@class="code-header in-band"]' 'impl Escape<r#"<script>alert("Escape");</script>"#>'
 impl Escape<r#"<script>alert("Escape");</script>"#> {
     pub fn f() {}
 }
index 0e27fc90b69a6cc69d87ddfeca7413a37e86efb3..fdf8434224f839b0a00453f32ae77eb2b147b3bf 100644 (file)
@@ -9,7 +9,7 @@ pub fn foo(&mut self) {}
 }
 
 // @has foo/struct.Bar.html
-// @has - '//div[@class="sidebar-links"]/a[@href="#method.foo"]' 'foo'
+// @has - '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.foo"]' 'foo'
 pub struct Bar {
     foo: Foo,
 }
index 9ab338ca9b1d1bd42e7eb1ea4e4b207a350acc46..746df9c804ebb37a876355449063ff06a309dcbe 100644 (file)
@@ -8,9 +8,9 @@
 // @has '-' '//*[@id="deref-methods-Path"]' 'Methods from Deref<Target = Path>'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.exists"]' 'pub fn exists(&self)'
 // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-PathBuf"]' 'Methods from Deref<Target=PathBuf>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.as_path"]' 'as_path'
+// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.as_path"]' 'as_path'
 // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Path"]' 'Methods from Deref<Target=Path>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.exists"]' 'exists'
+// @has '-' '//*[@class="sidebar-elems"]//*[@class="block"]//a[@href="#method.exists"]' 'exists'
 
 #![crate_name = "foo"]
 
index c07e048b0651c41f9ab2ee2b0c055bfd4142fce5..d5f8473f2842d255754d90d44bb6a16cedaafc2f 100644 (file)
@@ -8,9 +8,9 @@
 // @has '-' '//*[@id="deref-methods-Baz"]' 'Methods from Deref<Target = Baz>'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.baz"]' 'pub fn baz(&self)'
 // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Bar"]' 'Methods from Deref<Target=Bar>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.bar"]' 'bar'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.bar"]' 'bar'
 // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-Baz"]' 'Methods from Deref<Target=Baz>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.baz"]' 'baz'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.baz"]' 'baz'
 
 #![crate_name = "foo"]
 
index ad7a96c5dad1fc7c6ce37cc1746c13b7387b85d7..28f977e315abf4aabe9b53f880767d09386dfdad 100644 (file)
@@ -7,10 +7,10 @@
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_c"]' 'pub fn foo_c(&self)'
 // @has '-' '//*[@class="impl-items"]//*[@id="method.foo_j"]' 'pub fn foo_j(&self)'
 // @has '-' '//*[@class="sidebar-title"]/a[@href="#deref-methods-FooJ"]' 'Methods from Deref<Target=FooJ>'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_a"]' 'foo_a'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_b"]' 'foo_b'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_c"]' 'foo_c'
-// @has '-' '//*[@class="sidebar-links"]/a[@href="#method.foo_j"]' 'foo_j'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_a"]' 'foo_a'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_b"]' 'foo_b'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_c"]' 'foo_c'
+// @has '-' '//*[@class="sidebar-elems"]//section//a[@href="#method.foo_j"]' 'foo_j'
 
 pub struct FooA;
 pub type FooB = FooA;
index 546af2c121adbc4dc60dbc07de1c6212545f9f44..b7bbf140cfd00309faba4d42d4c9b582010c6335 100644 (file)
@@ -8,5 +8,5 @@ fn foo() {}
 pub struct Bar;
 
 // @has foo/struct.Bar.html
-// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E"]' 'Foo<unsafe extern "C" fn()>'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo%3Cunsafe%20extern%20%22C%22%20fn()%3E"]' 'Foo<unsafe extern "C" fn()>'
 impl Foo<unsafe extern "C" fn()> for Bar {}
index 2eed1cc9d7450bf1eae5ade2f736f559f1e7412f..d18f404212fa1bc9b63045b15022c6ca11c50047 100644 (file)
@@ -1,19 +1,19 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Foo.html
-// @has - '//div[@id="synthetic-implementations-list"]/div[@id="impl-Send"]' 'impl Send for Foo'
+// @has - '//div[@id="synthetic-implementations-list"]/*[@id="impl-Send"]' 'impl Send for Foo'
 pub struct Foo;
 
 pub trait EmptyTrait {}
 
-// @has - '//div[@id="trait-implementations-list"]/div[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
+// @has - '//div[@id="trait-implementations-list"]/*[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo'
 impl EmptyTrait for Foo {}
 
 pub trait NotEmpty {
     fn foo(&self);
 }
 
-// @has - '//div[@id="trait-implementations-list"]/details/summary/div[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
+// @has - '//div[@id="trait-implementations-list"]/details/summary/*[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo'
 impl NotEmpty for Foo {
     fn foo(&self) {}
 }
index d32d3fc581f8aaca3d4edced4e69e49f270e8797..9f8b0277e76b0a7c8dd2329ae3a687332a3c6e38 100644 (file)
@@ -2,5 +2,5 @@
 
 // This test ensures that the [src] link is present on traits items.
 
-// @has foo/trait.Iterator.html '//div[@id="method.zip"]//a[@class="srclink"]' "source"
+// @has foo/trait.Iterator.html '//*[@id="method.zip"]//a[@class="srclink"]' "source"
 pub use std::iter::Iterator;
index efa2025b4b9c229d8d199426528597c34c016a88..93cf16346b6f7fcd50c3ba887c513128d6c58b38 100644 (file)
@@ -4,6 +4,6 @@
 extern crate rustdoc_extern_default_method as ext;
 
 // @count extern_default_method/struct.Struct.html '//*[@id="method.provided"]' 1
-// @has extern_default_method/struct.Struct.html '//div[@id="method.provided"]//a[@class="fnname"]/@href' #method.provided
-// @has extern_default_method/struct.Struct.html '//div[@id="method.provided"]//a[@class="anchor"]/@href' #method.provided
+// @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="fnname"]/@href' #method.provided
+// @has extern_default_method/struct.Struct.html '//*[@id="method.provided"]//a[@class="anchor"]/@href' #method.provided
 pub use ext::Struct;
index 906316d2ebcc00799a62bc3cd75e1c338fbea089..1268c9587f84724f3c0349ab6335567f4ac67347 100644 (file)
@@ -2,12 +2,12 @@
 
 use std::fmt;
 
-// @!has foo/struct.Bar.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+// @!has foo/struct.Bar.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
 pub struct Bar;
 
-// @has foo/struct.Foo.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+// @has foo/struct.Foo.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
 pub struct Foo;
-// @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString'
+// @has foo/struct.Foo.html '//*[@class="sidebar-elems"]//section//a[@href="#impl-ToString"]' 'ToString'
 
 impl fmt::Display for Foo {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs b/src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs
new file mode 100644 (file)
index 0000000..ee4138b
--- /dev/null
@@ -0,0 +1,11 @@
+#[derive(Clone)]
+pub struct PublicStruct;
+
+mod inner {
+    use super::PublicStruct;
+
+    impl PublicStruct {
+        /// [PublicStruct::clone]
+        pub fn method() {}
+    }
+}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/extern-lang-item-impl-dep.rs b/src/test/rustdoc/intra-doc/auxiliary/extern-lang-item-impl-dep.rs
new file mode 100644 (file)
index 0000000..87ae2f0
--- /dev/null
@@ -0,0 +1,29 @@
+// no-prefer-dynamic
+
+#![feature(lang_items)]
+
+#![crate_type = "rlib"]
+#![no_std]
+
+pub struct DerefsToF64(f64);
+
+impl core::ops::Deref for DerefsToF64 {
+    type Target = f64;
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+mod inner {
+    #[lang = "f64_runtime"]
+    impl f64 {
+        /// [f64::clone]
+        pub fn method() {}
+    }
+}
+
+#[lang = "eh_personality"]
+fn foo() {}
+
+#[panic_handler]
+fn bar(_: &core::panic::PanicInfo) -> ! { loop {} }
diff --git a/src/test/rustdoc/intra-doc/extern-inherent-impl.rs b/src/test/rustdoc/intra-doc/extern-inherent-impl.rs
new file mode 100644 (file)
index 0000000..2e41c22
--- /dev/null
@@ -0,0 +1,8 @@
+// Reexport of a structure with public inherent impls having doc links in their comments. The doc
+// link points to an associated item, so we check that traits in scope for that link are populated.
+
+// aux-build:extern-inherent-impl-dep.rs
+
+extern crate extern_inherent_impl_dep;
+
+pub use extern_inherent_impl_dep::PublicStruct;
diff --git a/src/test/rustdoc/intra-doc/extern-lang-item-impl.rs b/src/test/rustdoc/intra-doc/extern-lang-item-impl.rs
new file mode 100644 (file)
index 0000000..f64f886
--- /dev/null
@@ -0,0 +1,11 @@
+// Reexport of a structure that derefs to a type with lang item impls having doc links in their
+// comments. The doc link points to an associated item, so we check that traits in scope for that
+// link are populated.
+
+// aux-build:extern-lang-item-impl-dep.rs
+
+#![no_std]
+
+extern crate extern_lang_item_impl_dep;
+
+pub use extern_lang_item_impl_dep::DerefsToF64;
index 90a2b76eab67bcdaa32a780bc5f5d1b52fc81cc1..490d7e51e321d5663a4398c99ad35eaa3a4d3d4c 100644 (file)
@@ -5,12 +5,14 @@ pub trait MyTrait {
     fn my_string(&self) -> String;
 }
 
-// @has - "//div[@id='implementors-list']//div[@id='impl-MyTrait']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug"
-impl<T> MyTrait for T where T: fmt::Debug {
+// @has - "//div[@id='implementors-list']//*[@id='impl-MyTrait']//h3[@class='code-header in-band']" "impl<T> MyTrait for T where T: Debug"
+impl<T> MyTrait for T
+where
+    T: fmt::Debug,
+{
     fn my_string(&self) -> String {
         format!("{:?}", self)
     }
 }
 
-pub fn main() {
-}
+pub fn main() {}
index 1777744c0fcb608a12d124dad91a91b3efc0ebe9..1e4791e01253df01edcb4aa0c7fdaa5816c6d812 100644 (file)
@@ -1,7 +1,6 @@
 // Ensure constant and array length values are not taken from source
 // code, which wreaks havoc with macros.
 
-
 macro_rules! make {
     ($n:expr) => {
         pub struct S;
@@ -23,7 +22,7 @@ fn ignore(_: &X) {}
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
+        //        '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
         // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]'
         // @has - '//*[@id="associatedconstant.D"]' 'const D: i32'
         impl T<[i32; ($n * $n)]> for S {
@@ -31,7 +30,7 @@ fn ignore(_: &X) {}
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
+        //        '//*[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S'
         // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)'
         // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32'
         impl T<(i32,)> for S {
@@ -39,14 +38,14 @@ impl T<(i32,)> for S {
         }
 
         // @has issue_33302/struct.S.html \
-        //        '//div[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S'
+        //        '//*[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S'
         // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)'
         // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32'
         impl T<(i32, i32)> for S {
             const C: (i32, i32) = ($n, $n);
             const D: i32 = ($n / $n);
         }
-    }
+    };
 }
 
 make!(4);
index 0b1f2f2c93f19eda621672dc73d2bfbf0726481f..c68ffd52186482da0ffe81389f01305b5522ca09 100644 (file)
@@ -1,5 +1,4 @@
-pub trait MyIterator {
-}
+pub trait MyIterator {}
 
 pub struct MyStruct<T>(T);
 
@@ -13,9 +12,9 @@ macro_rules! array_impls {
 }
 
 // @has issue_53812/trait.MyIterator.html
-// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>'
-// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>'
-// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>'
-// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>'
-// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>'
+// @has - '//*[@id="implementors-list"]/*[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>'
 array_impls! { 10 3 2 1 0 }
index b14e266f7f98d78a1edc2c18e446a8d3ee357d7b..ef15946ec50459ea288ad38506dc365de751d2d5 100644 (file)
@@ -4,6 +4,6 @@
 
 use issue_86620_1::*;
 
-// @!has issue_86620/struct.S.html '//div[@id="method.vzip"]//a[@class="fnname"]/@href' #tymethod.vzip
-// @has issue_86620/struct.S.html '//div[@id="method.vzip"]//a[@class="anchor"]/@href' #method.vzip
+// @!has issue_86620/struct.S.html '//*[@id="method.vzip"]//a[@class="fnname"]/@href' #tymethod.vzip
+// @has issue_86620/struct.S.html '//*[@id="method.vzip"]//a[@class="anchor"]/@href' #method.vzip
 pub struct S;
index 9f24e817fd3ebcc298d3f874afdbe54080279c2d..50f4af3aaafef91a61c64eb786846e1486544bad 100644 (file)
@@ -1,8 +1,8 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="sidebar-links"]/a' 'super_long_name'
-// @has - '//*[@class="sidebar-links"]/a' 'Disp'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'super_long_name'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Disp'
 pub struct Foo(usize);
 
 impl Foo {
index d63ab346045eec60f1c8d7849037ac33de9fbd98..b995fff1f9aa70633373f937aa762100917c57f0 100644 (file)
@@ -5,5 +5,5 @@
 
 // @has foo/struct.Foo.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#trait-implementations"]' 'Trait Implementations'
-// @has - '//*[@class="sidebar-links"]/a' '!Sync'
+// @has - '//*[@class="sidebar-elems"]//section//a' '!Sync'
 impl !Sync for Foo {}
index f9737240c70a294ed34ed06717e5649343b4b111..28adff84c7032c91aca8ad25ec776d7b024272f9 100644 (file)
@@ -1,8 +1,7 @@
 #![feature(rustdoc_internals)]
-
 #![crate_name = "foo"]
 
-// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
+// @has foo/primitive.i32.html '//*[@id="impl-ToString"]//h3[@class="code-header in-band"]' 'impl<T> ToString for T'
 
 #[doc(primitive = "i32")]
 /// Some useless docs, wouhou!
index 65a7debc2538dd8e1804d0a302956a0e60fe5c2c..619f40eff8984fc6ee45fdf1f58fa233b23e60c2 100644 (file)
@@ -9,13 +9,13 @@ impl B { pub fn foo_b(&self) {} }
 pub struct C {}
 impl C { pub fn foo_c(&self) {} }
 
-// @has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_b'
+// @has recursive_deref_sidebar/struct.A.html '//*[@class="sidebar-elems"]//section' 'foo_b'
 impl Deref for A {
     type Target = B;
     fn deref(&self) -> &B { todo!() }
 }
 
-// @has recursive_deref_sidebar/struct.A.html '//div[@class="sidebar-links"]' 'foo_c'
+// @has recursive_deref_sidebar/struct.A.html '//*[@class="sidebar-elems"]//section' 'foo_c'
 impl Deref for B {
     type Target = C;
     fn deref(&self) -> &C { todo!() }
index ee670e88b5cb4c69c6923cb5c5c09b3c691cc2a5..375cad9da7f88010070b87b326750d55e63c5dc7 100644 (file)
@@ -2,13 +2,13 @@
 
 // @has foo/trait.Foo.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#required-methods"]' 'Required Methods'
-// @has - '//*[@class="sidebar-links"]/a' 'bar'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'bar'
 // @has - '//*[@class="sidebar-title"]/a[@href="#provided-methods"]' 'Provided Methods'
-// @has - '//*[@class="sidebar-links"]/a' 'foo'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'foo'
 // @has - '//*[@class="sidebar-title"]/a[@href="#associated-const"]' 'Associated Constants'
-// @has - '//*[@class="sidebar-links"]/a' 'BAR'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'BAR'
 // @has - '//*[@class="sidebar-title"]/a[@href="#associated-types"]' 'Associated Types'
-// @has - '//*[@class="sidebar-links"]/a' 'Output'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Output'
 pub trait Foo {
     const BAR: u32 = 0;
     type Output: ?Sized;
@@ -19,9 +19,9 @@ fn foo() {}
 
 // @has foo/struct.Bar.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields'
-// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f"]' 'f'
-// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.u"]' 'u'
-// @!has - '//*[@class="sidebar-links"]/a' 'waza'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f"]' 'f'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.u"]' 'u'
+// @!has - '//*[@class="sidebar-elems"]//section//a' 'waza'
 pub struct Bar {
     pub f: u32,
     pub u: u32,
@@ -30,8 +30,8 @@ pub struct Bar {
 
 // @has foo/enum.En.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#variants"]' 'Variants'
-// @has - '//*[@class="sidebar-links"]/a' 'Foo'
-// @has - '//*[@class="sidebar-links"]/a' 'Bar'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Foo'
+// @has - '//*[@class="sidebar-elems"]//section//a' 'Bar'
 pub enum En {
     Foo,
     Bar,
@@ -39,9 +39,9 @@ pub enum En {
 
 // @has foo/union.MyUnion.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#fields"]' 'Fields'
-// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f1"]' 'f1'
-// @has - '//*[@class="sidebar-links"]/a[@href="#structfield.f2"]' 'f2'
-// @!has - '//*[@class="sidebar-links"]/a' 'waza'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f1"]' 'f1'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#structfield.f2"]' 'f2'
+// @!has - '//*[@class="sidebar-elems"]//section//a' 'waza'
 pub union MyUnion {
     pub f1: u32,
     pub f2: f32,
index 76b77b9bcbb6bf3347ff9d293e57b5b16052a2c0..7858f35a2616e57c3d61802956c3900683ba08c3 100644 (file)
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// @has foo/struct.SomeStruct.html '//*[@class="sidebar-links"]/a[@href="#method.some_fn-1"]' \
+// @has foo/struct.SomeStruct.html '//*[@class="sidebar-elems"]//section//li/a[@href="#method.some_fn-1"]' \
 //          "some_fn"
 pub struct SomeStruct<T> { _inner: T }
 
index d1083c487642d7ad668299fe02f53528820affc9..15515039659991b29fffeeb81e80ef975c974597 100644 (file)
@@ -5,10 +5,10 @@
 // @has foo/trait.Foo.html
 // @has - '//*[@class="sidebar-title"]/a[@href="#foreign-impls"]' 'Implementations on Foreign Types'
 // @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types'
-// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-u32"]' 'u32'
-// @has - '//div[@id="impl-Foo-for-u32"]//h3[@class="code-header in-band"]' 'impl Foo for u32'
-// @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
-// @has - '//div[@id="impl-Foo-for-%26%27a%20str"]//h3[@class="code-header in-band"]' "impl<'a> Foo for &'a str"
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-u32"]' 'u32'
+// @has - '//*[@id="impl-Foo-for-u32"]//h3[@class="code-header in-band"]' 'impl Foo for u32'
+// @has - '//*[@class="sidebar-elems"]//section//a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str"
+// @has - '//*[@id="impl-Foo-for-%26%27a%20str"]//h3[@class="code-header in-band"]' "impl<'a> Foo for &'a str"
 pub trait Foo {}
 
 impl Foo for u32 {}
index ac4a4ad394c1bb23f4768be96a8f7112689f5603..252a81260369ab8898c197d3d3228f005b7eabdf 100644 (file)
@@ -1,17 +1,17 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Bar.html
-// @!has - '//div[@id="impl-Sized"]'
+// @!has - '//*[@id="impl-Sized"]'
 pub struct Bar {
     a: u16,
 }
 
 // @has foo/struct.Foo.html
-// @!has - '//div[@id="impl-Sized"]'
+// @!has - '//*[@id="impl-Sized"]'
 pub struct Foo<T: ?Sized>(T);
 
 // @has foo/struct.Unsized.html
-// @has - '//div[@id="impl-Sized"]//h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
+// @has - '//*[@id="impl-Sized"]//h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
 pub struct Unsized {
     data: [u8],
 }
index 8d23ca918012b8e2293604f4f888d858afdf9761..14580373b3b051284d3eb844c9c26a989508f98c 100644 (file)
@@ -6,7 +6,7 @@
 // @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
 #[stable(feature = "bar", since = "1.0")]
 pub trait Bar {
-    // @has - '//div[@id="tymethod.foo"]/*[@class="rightside"]' '3.0 · source'
+    // @has - '//*[@id="tymethod.foo"]/*[@class="rightside"]' '3.0 · source'
     #[stable(feature = "foobar", since = "3.0")]
     fn foo();
 }
@@ -19,7 +19,7 @@ pub trait Bar {
 pub struct Foo;
 
 impl Foo {
-    // @has - '//div[@id="method.foofoo"]/*[@class="rightside"]' '3.0 · source'
+    // @has - '//*[@id="method.foofoo"]/*[@class="rightside"]' '3.0 · source'
     #[stable(feature = "foobar", since = "3.0")]
     pub fn foofoo() {}
 }
index 864cb0c400b64dc86dca67de432e9e9dad62eb09..5245789212d8c9e777f6984e7e999eea18415c81 100644 (file)
@@ -3,7 +3,7 @@
 use std::iter::Iterator;
 
 // @has foo/struct.Odd.html
-// @has - '//div[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
+// @has - '//*[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd'
 pub struct Odd {
     current: usize,
 }
index 46b8778217d27fd5d8f4380865e05822495ce436..0f461a1185b6e1c4868e21cacc5f2cc126c6007e 100644 (file)
@@ -1,12 +1,12 @@
 #![crate_name = "foo"]
 
 // @has foo/struct.Unsized.html
-// @has - '//div[@id="impl-Sized"]/h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
-// @!has - '//div[@id="impl-Sized"]//a[@class="srclink"]' 'source'
-// @has - '//div[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized'
-// @!has - '//div[@id="impl-Sync"]//a[@class="srclink"]' 'source'
-// @has - '//div[@id="impl-Any"]/h3[@class="code-header in-band"]' 'impl<T> Any for T'
-// @has - '//div[@id="impl-Any"]//a[@class="srclink"]' 'source'
+// @has - '//*[@id="impl-Sized"]/h3[@class="code-header in-band"]' 'impl !Sized for Unsized'
+// @!has - '//*[@id="impl-Sized"]//a[@class="srclink"]' 'source'
+// @has - '//*[@id="impl-Sync"]/h3[@class="code-header in-band"]' 'impl Sync for Unsized'
+// @!has - '//*[@id="impl-Sync"]//a[@class="srclink"]' 'source'
+// @has - '//*[@id="impl-Any"]/h3[@class="code-header in-band"]' 'impl<T> Any for T'
+// @has - '//*[@id="impl-Any"]//a[@class="srclink"]' 'source'
 pub struct Unsized {
     data: [u8],
 }
index ed2297b4fac5daf07f482667879b495fe947ec38..ea28d84f1ffdfe63fd0b41bad05a8c29205c822e 100644 (file)
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// The goal of this test is to answer that it won't be generated as a list because
+// The goal of this test is to ensure that it won't be generated as a list because
 // block doc comments can have their lines starting with a star.
 
 // @has foo/fn.foo.html
index db9adb4838e3e1e1889e6b69f3f6e7104f89f5f5..b5a97c610daeac7ca9efe9575efbdf6add7faf16 100644 (file)
@@ -7,52 +7,52 @@ fn defaulted_override(&self) {}
 }
 
 impl MyTrait for String {
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="associatedtype"]/@href' #associatedtype.Assoc
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-1"]//a[@class="associatedtype"]/@href' #associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1
     type Assoc = ();
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1
     const VALUE: u32 = 5;
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
     fn trait_function(&self) {}
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1
     fn defaulted_override(&self) {}
 }
 
 impl MyTrait for Vec<u8> {
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="associatedtype"]/@href' #associatedtype.Assoc
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-2"]//a[@class="associatedtype"]/@href' #associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2
     type Assoc = ();
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2
     const VALUE: u32 = 5;
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1
     fn trait_function(&self) {}
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2
     fn defaulted_override(&self) {}
 }
 
 impl MyTrait for MyStruct {
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="associatedtype"]/@href' trait.MyTrait.html#associatedtype.Assoc
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedtype.Assoc"]//a[@class="associatedtype"]/@href' trait.MyTrait.html#associatedtype.Assoc
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc
     type Assoc = bool;
-    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//*[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE
     const VALUE: u32 = 20;
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function
     fn trait_function(&self) {}
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override
     fn defaulted_override(&self) {}
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
-    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted
+    // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//*[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted
 }
 
 pub struct MyStruct;
index dec7fe3f6a5d9620cbb0da78e845cc3d974c7bba..a0c657d9a054d09bede9897ac1ab835fb275a474 100644 (file)
@@ -8,7 +8,7 @@
 // @has foo/all.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
 // @has foo/all.html '//a[@href="traitalias.Foo.html"]' 'Foo'
 
-// @has foo/index.html '//h2[@id="trait-aliases"]' 'Trait aliases'
+// @has foo/index.html '//h2[@id="trait-aliases"]' 'Trait Aliases'
 // @has foo/index.html '//a[@class="traitalias"]' 'CopyAlias'
 // @has foo/index.html '//a[@class="traitalias"]' 'Alias2'
 // @has foo/index.html '//a[@class="traitalias"]' 'Foo'
index bffe5030a84fd9674fe0cd97d8d744ec8853555e..ae866deba1ef039e488b75b5863f4d8a8e4d5b8e 100644 (file)
@@ -16,8 +16,8 @@ pub fn foo() {}
 pub struct Bar;
 
 impl Bar {
-    // @has - '//div[@id="method.bar"]/*[@class="rightside"]' '2.0'
-    // @!has - '//div[@id="method.bar"]/*[@class="rightside"]' '2.0 ·'
+    // @has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0'
+    // @!has - '//*[@id="method.bar"]/*[@class="rightside"]' '2.0 ·'
     #[stable(feature = "foobar", since = "2.0")]
     pub fn bar() {}
 }
index d0d89cbf126b480d0e65ff461270f5f04c5dbe59..3150a8ea05f41f321dde58bbe2dded183deead48 100644 (file)
@@ -1,15 +1,19 @@
 #![crate_name = "foo"]
 
 pub trait SomeTrait<Rhs = Self>
-where Rhs: ?Sized
-{}
+where
+    Rhs: ?Sized,
+{
+}
 
 // @has 'foo/trait.SomeTrait.html'
-// @has - "//div[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
-impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where
+// @has - "//*[@id='impl-SomeTrait%3C(A%2C%20B%2C%20C%2C%20D%2C%20E)%3E-for-(A%2C%20B%2C%20C%2C%20D%2C%20E)']/h3" "impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E) where A: PartialOrd<A> + PartialEq<A>, B: PartialOrd<B> + PartialEq<B>, C: PartialOrd<C> + PartialEq<C>, D: PartialOrd<D> + PartialEq<D>, E: PartialOrd<E> + PartialEq<E> + ?Sized, "
+impl<A, B, C, D, E> SomeTrait<(A, B, C, D, E)> for (A, B, C, D, E)
+where
     A: PartialOrd<A> + PartialEq<A>,
     B: PartialOrd<B> + PartialEq<B>,
     C: PartialOrd<C> + PartialEq<C>,
     D: PartialOrd<D> + PartialEq<D>,
-    E: PartialOrd<E> + PartialEq<E> + ?Sized
-{}
+    E: PartialOrd<E> + PartialEq<E> + ?Sized,
+{
+}
diff --git a/src/test/ui/aligned_enum_cast.rs b/src/test/ui/aligned_enum_cast.rs
new file mode 100644 (file)
index 0000000..4b5776a
--- /dev/null
@@ -0,0 +1,15 @@
+// run-pass
+// allows aligned custom discriminant enums to cast into other types
+// See the issue #92464 for more info
+#[allow(dead_code)]
+#[repr(align(8))]
+enum Aligned {
+    Zero = 0,
+    One = 1,
+}
+
+fn main() {
+    let aligned = Aligned::Zero;
+    let fo = aligned as u8;
+    println!("foo {}",fo);
+}
index e7a9ce94af4d9f52fc0c4c61e19f7097b2709c5d..c0f6118a9f1639354c2cd6e70bf951821b0ae8cd 100644 (file)
@@ -1,40 +1,40 @@
 error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
-  --> $DIR/not-an-allocator.rs:2:1
+  --> $DIR/not-an-allocator.rs:2:11
    |
 LL | #[global_allocator]
    | ------------------- in this procedural macro expansion
 LL | static A: usize = 0;
-   | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+   |           ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
    |
    = note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
-  --> $DIR/not-an-allocator.rs:2:1
+  --> $DIR/not-an-allocator.rs:2:11
    |
 LL | #[global_allocator]
    | ------------------- in this procedural macro expansion
 LL | static A: usize = 0;
-   | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+   |           ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
    |
    = note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
-  --> $DIR/not-an-allocator.rs:2:1
+  --> $DIR/not-an-allocator.rs:2:11
    |
 LL | #[global_allocator]
    | ------------------- in this procedural macro expansion
 LL | static A: usize = 0;
-   | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+   |           ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
    |
    = note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied
-  --> $DIR/not-an-allocator.rs:2:1
+  --> $DIR/not-an-allocator.rs:2:11
    |
 LL | #[global_allocator]
    | ------------------- in this procedural macro expansion
 LL | static A: usize = 0;
-   | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
+   |           ^^^^^ the trait `GlobalAlloc` is not implemented for `usize`
    |
    = note: this error originates in the attribute macro `global_allocator` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index d80ab921fb83ef97284acb76e15b8746cca94eec..3f705ba5b64c2995eeddfc8d1c10da25f94f9b78 100644 (file)
@@ -382,7 +382,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:39:37
    |
 LL |     let mut foo = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const foo`
+   |     ----------- help: consider using `const` instead of `let`: `const foo`
 ...
 LL |         asm!("{}", options(), const foo);
    |                                     ^^^ non-constant value
@@ -391,7 +391,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:48:44
    |
 LL |     let mut foo = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const foo`
+   |     ----------- help: consider using `const` instead of `let`: `const foo`
 ...
 LL |         asm!("{}", clobber_abi("C"), const foo);
    |                                            ^^^ non-constant value
@@ -400,7 +400,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:55:31
    |
 LL |     let mut foo = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const foo`
+   |     ----------- help: consider using `const` instead of `let`: `const foo`
 ...
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                               ^^^ non-constant value
@@ -409,7 +409,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:55:46
    |
 LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
+   |     ----------- help: consider using `const` instead of `let`: `const bar`
 ...
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                                              ^^^ non-constant value
@@ -418,7 +418,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:62:45
    |
 LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
+   |     ----------- help: consider using `const` instead of `let`: `const bar`
 ...
 LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                                             ^^^ non-constant value
@@ -427,7 +427,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:65:45
    |
 LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
+   |     ----------- help: consider using `const` instead of `let`: `const bar`
 ...
 LL |         asm!("{a}", in("x0") foo, a = const bar);
    |                                             ^^^ non-constant value
@@ -436,7 +436,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:68:41
    |
 LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
+   |     ----------- help: consider using `const` instead of `let`: `const bar`
 ...
 LL |         asm!("{1}", in("x0") foo, const bar);
    |                                         ^^^ non-constant value
index 3b1d922a7f7578248575b6c5e0f14e2ce8916765..11c4e01f4186d8a8371cfb88b36df2382f230bd2 100644 (file)
@@ -23,10 +23,10 @@ LL |         asm!("{1}", in(reg) foo);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
 
 error: there is no argument named `a`
-  --> $DIR/bad-template.rs:36:15
+  --> $DIR/bad-template.rs:36:16
    |
 LL |         asm!("{a}");
-   |               ^^^
+   |                ^
 
 error: invalid reference to argument at index 0
   --> $DIR/bad-template.rs:38:15
@@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
 
 error: there is no argument named `a`
-  --> $DIR/bad-template.rs:63:14
+  --> $DIR/bad-template.rs:63:15
    |
 LL | global_asm!("{a}");
-   |              ^^^
+   |               ^
 
 error: invalid reference to argument at index 0
   --> $DIR/bad-template.rs:65:14
index 3b1d922a7f7578248575b6c5e0f14e2ce8916765..11c4e01f4186d8a8371cfb88b36df2382f230bd2 100644 (file)
@@ -23,10 +23,10 @@ LL |         asm!("{1}", in(reg) foo);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
 
 error: there is no argument named `a`
-  --> $DIR/bad-template.rs:36:15
+  --> $DIR/bad-template.rs:36:16
    |
 LL |         asm!("{a}");
-   |               ^^^
+   |                ^
 
 error: invalid reference to argument at index 0
   --> $DIR/bad-template.rs:38:15
@@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
 
 error: there is no argument named `a`
-  --> $DIR/bad-template.rs:63:14
+  --> $DIR/bad-template.rs:63:15
    |
 LL | global_asm!("{a}");
-   |              ^^^
+   |               ^
 
 error: invalid reference to argument at index 0
   --> $DIR/bad-template.rs:65:14
index 3b69186f1e18b2fd7476a6fe92b5fa39a180365a..c198e0a69dde18049c4e42121cf37e28e22a771d 100644 (file)
@@ -23,10 +23,10 @@ LL |         asm!("{1}", in(reg) foo);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
 
 error: there is no argument named `a`
-  --> $DIR/bad-template.rs:36:15
+  --> $DIR/bad-template.rs:36:16
    |
 LL |         asm!("{a}");
-   |               ^^^
+   |                ^
 
 error: invalid reference to argument at index 0
   --> $DIR/bad-template.rs:38:15
@@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
 
 error: there is no argument named `a`
-  --> $DIR/bad-template.rs:63:14
+  --> $DIR/bad-template.rs:63:15
    |
 LL | global_asm!("{a}");
-   |              ^^^
+   |               ^
 
 error: invalid reference to argument at index 0
   --> $DIR/bad-template.rs:65:14
index 3b69186f1e18b2fd7476a6fe92b5fa39a180365a..c198e0a69dde18049c4e42121cf37e28e22a771d 100644 (file)
@@ -23,10 +23,10 @@ LL |         asm!("{1}", in(reg) foo);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
 
 error: there is no argument named `a`
-  --> $DIR/bad-template.rs:36:15
+  --> $DIR/bad-template.rs:36:16
    |
 LL |         asm!("{a}");
-   |               ^^^
+   |                ^
 
 error: invalid reference to argument at index 0
   --> $DIR/bad-template.rs:38:15
@@ -123,10 +123,10 @@ LL | global_asm!("{1}", const FOO);
    = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
 
 error: there is no argument named `a`
-  --> $DIR/bad-template.rs:63:14
+  --> $DIR/bad-template.rs:63:15
    |
 LL | global_asm!("{a}");
-   |              ^^^
+   |               ^
 
 error: invalid reference to argument at index 0
   --> $DIR/bad-template.rs:65:14
diff --git a/src/test/ui/asm/reg-conflict.rs b/src/test/ui/asm/reg-conflict.rs
new file mode 100644 (file)
index 0000000..983788a
--- /dev/null
@@ -0,0 +1,20 @@
+// compile-flags: --target armv7-unknown-linux-gnueabihf
+// needs-llvm-components: arm
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+#[lang = "sized"]
+trait Sized {}
+
+fn main() {
+    unsafe {
+        asm!("", out("d0") _, out("d1") _);
+        asm!("", out("d0") _, out("s1") _);
+        //~^ ERROR register `s1` conflicts with register `d0`
+    }
+}
diff --git a/src/test/ui/asm/reg-conflict.stderr b/src/test/ui/asm/reg-conflict.stderr
new file mode 100644 (file)
index 0000000..2395566
--- /dev/null
@@ -0,0 +1,10 @@
+error: register `s1` conflicts with register `d0`
+  --> $DIR/reg-conflict.rs:17:31
+   |
+LL |         asm!("", out("d0") _, out("s1") _);
+   |                  -----------  ^^^^^^^^^^^ register `s1`
+   |                  |
+   |                  register `d0`
+
+error: aborting due to previous error
+
index 2d0a7a94d56765d8d1b4cea1c7ed370b142d99aa..194cd66a66e96325ae9e63e4201d96fe616f56ec 100644 (file)
@@ -394,7 +394,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:39:37
    |
 LL |     let mut foo = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const foo`
+   |     ----------- help: consider using `const` instead of `let`: `const foo`
 ...
 LL |         asm!("{}", options(), const foo);
    |                                     ^^^ non-constant value
@@ -403,7 +403,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:50:44
    |
 LL |     let mut foo = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const foo`
+   |     ----------- help: consider using `const` instead of `let`: `const foo`
 ...
 LL |         asm!("{}", clobber_abi("C"), const foo);
    |                                            ^^^ non-constant value
@@ -412,7 +412,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:57:31
    |
 LL |     let mut foo = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const foo`
+   |     ----------- help: consider using `const` instead of `let`: `const foo`
 ...
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                               ^^^ non-constant value
@@ -421,7 +421,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:57:46
    |
 LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
+   |     ----------- help: consider using `const` instead of `let`: `const bar`
 ...
 LL |         asm!("{a}", a = const foo, a = const bar);
    |                                              ^^^ non-constant value
@@ -430,7 +430,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:64:46
    |
 LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
+   |     ----------- help: consider using `const` instead of `let`: `const bar`
 ...
 LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                                              ^^^ non-constant value
@@ -439,7 +439,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:67:46
    |
 LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
+   |     ----------- help: consider using `const` instead of `let`: `const bar`
 ...
 LL |         asm!("{a}", in("eax") foo, a = const bar);
    |                                              ^^^ non-constant value
@@ -448,7 +448,7 @@ error[E0435]: attempt to use a non-constant value in a constant
   --> $DIR/parse-error.rs:70:42
    |
 LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
+   |     ----------- help: consider using `const` instead of `let`: `const bar`
 ...
 LL |         asm!("{1}", in("eax") foo, const bar);
    |                                          ^^^ non-constant value
diff --git a/src/test/ui/associated-consts/issue-93835.rs b/src/test/ui/associated-consts/issue-93835.rs
new file mode 100644 (file)
index 0000000..5c7b065
--- /dev/null
@@ -0,0 +1,10 @@
+fn e() {
+    p:a<p:p<e=6>>
+    //~^ ERROR comparison operators
+    //~| ERROR cannot find value
+    //~| ERROR associated const equality
+    //~| ERROR associated const equality
+    //~| ERROR associated type bounds
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-consts/issue-93835.stderr b/src/test/ui/associated-consts/issue-93835.stderr
new file mode 100644 (file)
index 0000000..12df0e4
--- /dev/null
@@ -0,0 +1,66 @@
+error: comparison operators cannot be chained
+  --> $DIR/issue-93835.rs:2:8
+   |
+LL | fn e() {
+   |        - while parsing this struct
+LL |     p:a<p:p<e=6>>
+   |        ^        ^
+   |
+   = help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+   = help: or use `(...)` if you meant to specify fn arguments
+
+error[E0425]: cannot find value `p` in this scope
+  --> $DIR/issue-93835.rs:2:5
+   |
+LL |     p:a<p:p<e=6>>
+   |     ^ not found in this scope
+   |
+help: you might have meant to write a `struct` literal
+   |
+LL ~ fn e() { SomeStruct {
+LL |     p:a<p:p<e=6>>
+LL |
+LL |
+LL |
+LL |
+ ...
+help: maybe you meant to write a path separator here
+   |
+LL |     p::a<p:p<e=6>>
+   |      ~~
+help: maybe you meant to write an assignment here
+   |
+LL |     let p:a<p:p<e=6>>
+   |     ~~~~~
+
+error[E0658]: associated const equality is incomplete
+  --> $DIR/issue-93835.rs:2:13
+   |
+LL |     p:a<p:p<e=6>>
+   |             ^^^
+   |
+   = 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-93835.rs:2:13
+   |
+LL |     p:a<p:p<e=6>>
+   |             ^^^
+   |
+   = 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 type bounds are unstable
+  --> $DIR/issue-93835.rs:2:9
+   |
+LL |     p:a<p:p<e=6>>
+   |         ^^^^^^^^
+   |
+   = note: see issue #52662 <https://github.com/rust-lang/rust/issues/52662> for more information
+   = help: add `#![feature(associated_type_bounds)]` to the crate attributes to enable
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0425, E0658.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/src/test/ui/associated-consts/shadowed-const.rs b/src/test/ui/associated-consts/shadowed-const.rs
new file mode 100644 (file)
index 0000000..cfdb391
--- /dev/null
@@ -0,0 +1,23 @@
+// Checking that none of these ICE, which was introduced in
+// https://github.com/rust-lang/rust/issues/93553
+trait Foo {
+    type Bar;
+}
+
+trait Baz: Foo {
+    const Bar: Self::Bar;
+}
+
+trait Baz2: Foo {
+    const Bar: u32;
+
+    fn foo() -> Self::Bar;
+}
+
+trait Baz3 {
+  const BAR: usize;
+  const QUX: Self::BAR;
+  //~^ ERROR found associated const
+}
+
+fn main() {}
diff --git a/src/test/ui/associated-consts/shadowed-const.stderr b/src/test/ui/associated-consts/shadowed-const.stderr
new file mode 100644 (file)
index 0000000..fe21d2a
--- /dev/null
@@ -0,0 +1,8 @@
+error: found associated const `BAR` when type was expected
+  --> $DIR/shadowed-const.rs:19:14
+   |
+LL |   const QUX: Self::BAR;
+   |              ^^^^^^^^^
+
+error: aborting due to previous error
+
index 0c4907fd002943126756ce039cdc2623cdc19d78..d180de9be3bf310896f4f65b601240a691ebb9da 100644 (file)
@@ -1,6 +1,5 @@
 // NOTE: rustc cannot currently handle bounds of the form `for<'a> <Foo as Bar<'a>>::Assoc: Baz`.
 // This should hopefully be fixed with Chalk.
-// ignore-compare-mode-chalk
 
 #![feature(associated_type_bounds)]
 
index 4ecae471ec2da3909602ebca1931fec9685c623a..c23e54594ee301f679c2cd46c48929dbc4f55693 100644 (file)
@@ -1,5 +1,5 @@
 error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
-  --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:36
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:36
    |
 LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
    |                                    ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be sent between threads safely
@@ -11,7 +11,7 @@ LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Send {
    |             ++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0277]: `<<Self as Case1>::C as Iterator>::Item` is not an iterator
-  --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:43
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:43
    |
 LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
    |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `<<Self as Case1>::C as Iterator>::Item` is not an iterator
@@ -23,7 +23,7 @@ LL | trait Case1 where <<Self as Case1>::C as Iterator>::Item: Iterator {
    |             ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error[E0277]: `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
-  --> $DIR/bad-bounds-on-assoc-in-trait.rs:27:93
+  --> $DIR/bad-bounds-on-assoc-in-trait.rs:26:93
    |
 LL |     type C: Clone + Iterator<Item: Send + Iterator<Item: for<'a> Lam<&'a u8, App: Debug>> + Sync>;
    |                                                                                             ^^^^ `<<Self as Case1>::C as Iterator>::Item` cannot be shared between threads safely
index a9aa2747e52af9b3bc0dece674e18e7ed1afeca2..b0703a4ee22b3b35fc792be2e98cd53a4a46c004 100644 (file)
@@ -1,5 +1,4 @@
 // build-pass (FIXME(62277): could be check-pass?)
-// ignore-compare-mode-chalk
 
 #![feature(associated_type_bounds)]
 
index f1aab2a6da071696f7319932b23439bc1245a76f..97c5acf1f72ca42129efce0205612dc331f7719d 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-compare-mode-chalk
 
 #![feature(associated_type_bounds)]
 #![feature(untagged_unions)]
index b3bb58f78142af7f159280f0f9e3bdb29e37dc92..f56631b12aa67436734ea72997f1c33436f46d33 100644 (file)
@@ -15,6 +15,8 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied
 LL |     f1(2u32, 4u32);
    |     ^^ the trait `Foo` is not implemented for `u32`
    |
+   = help: the following implementations were found:
+             <i32 as Foo>
 note: required by a bound in `f1`
   --> $DIR/associated-types-path-2.rs:13:14
    |
@@ -26,6 +28,9 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied
    |
 LL |     f1(2u32, 4u32);
    |              ^^^^ the trait `Foo` is not implemented for `u32`
+   |
+   = help: the following implementations were found:
+             <i32 as Foo>
 
 error[E0277]: the trait bound `u32: Foo` is not satisfied
   --> $DIR/associated-types-path-2.rs:35:8
@@ -35,6 +40,8 @@ LL |     f1(2u32, 4i32);
    |     |
    |     required by a bound introduced by this call
    |
+   = help: the following implementations were found:
+             <i32 as Foo>
 note: required by a bound in `f1`
   --> $DIR/associated-types-path-2.rs:13:14
    |
@@ -46,6 +53,9 @@ error[E0277]: the trait bound `u32: Foo` is not satisfied
    |
 LL |     f1(2u32, 4i32);
    |              ^^^^ the trait `Foo` is not implemented for `u32`
+   |
+   = help: the following implementations were found:
+             <i32 as Foo>
 
 error[E0308]: mismatched types
   --> $DIR/associated-types-path-2.rs:41:18
index 220ee6af2fc9fed8a71e2347125492d384c9000a..c9b302b96919fef3c818c780a4e6a9cc9ff2396d 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // Test references to the trait `Stream` in the bounds for associated
 // types defined on `Stream`. Issue #20551.
-// ignore-compare-mode-chalk
-
 
 trait Stream {
     type Car;
index 4eed5c9a0083c18f6098d51d362a294066d44709..ec28ca240be2b5b9a4bc30e3790d88450323e0fb 100644 (file)
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `X`
   --> $DIR/hr-associated-type-bound-1.rs:3:33
    |
index 354f5ae459729ec1746a6999090cb37d1d94c6ef..6d19186bde49a51c692a593d11b9cab5da3f298c 100644 (file)
@@ -4,8 +4,6 @@ error[E0277]: the trait bound `for<'b> <T as X<'b>>::U: Clone` is not satisfied
 LL | fn f<'a, T: X<'a> + ?Sized>(x: &<T as X<'a>>::U) {
    |             ^^^^^ the trait `for<'b> Clone` is not implemented for `<T as X<'b>>::U`
    |
-   = help: the following implementations were found:
-             <&T as Clone>
 note: required by a bound in `X`
   --> $DIR/hr-associated-type-bound-object.rs:3:33
    |
index 99f95c200511ac4c017f5e7ef904ae53309f4d1d..e48ef8d17d1dee70af4f5adb426020fc61c97cac 100644 (file)
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     type V = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `Y`
   --> $DIR/hr-associated-type-bound-param-1.rs:4:36
    |
index 5193400882d1255f83eea4be2e4ca33229c4456e..f74c5a8590d1d5989766217919f176d4e05b5e9d 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-compare-mode-chalk
 trait Z<'a, T: ?Sized>
 where
     T: Z<'a, u16>,
index 730229b5208da70e32b7687be78a0c11639f5d5e..2fb3af38c0d9b391dcef3b3aac6bc005b4a732e9 100644 (file)
@@ -1,11 +1,13 @@
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-2.rs:4:8
+  --> $DIR/hr-associated-type-bound-param-2.rs:3:8
    |
 LL |     T: Z<'a, u16>,
    |        ^^^^^^^^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `Z`
-  --> $DIR/hr-associated-type-bound-param-2.rs:7:35
+  --> $DIR/hr-associated-type-bound-param-2.rs:6:35
    |
 LL | trait Z<'a, T: ?Sized>
    |       - required by a bound in this
@@ -14,13 +16,15 @@ LL |     for<'b> <T as Z<'b, u16>>::W: Clone,
    |                                   ^^^^^ required by this bound in `Z`
 
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-2.rs:4:8
+  --> $DIR/hr-associated-type-bound-param-2.rs:3:8
    |
 LL |     T: Z<'a, u16>,
    |        ^^^^^^^^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `Z`
-  --> $DIR/hr-associated-type-bound-param-2.rs:7:35
+  --> $DIR/hr-associated-type-bound-param-2.rs:6:35
    |
 LL | trait Z<'a, T: ?Sized>
    |       - required by a bound in this
@@ -29,13 +33,15 @@ LL |     for<'b> <T as Z<'b, u16>>::W: Clone,
    |                                   ^^^^^ required by this bound in `Z`
 
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-2.rs:16:14
+  --> $DIR/hr-associated-type-bound-param-2.rs:15:14
    |
 LL |     type W = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `Z`
-  --> $DIR/hr-associated-type-bound-param-2.rs:7:35
+  --> $DIR/hr-associated-type-bound-param-2.rs:6:35
    |
 LL | trait Z<'a, T: ?Sized>
    |       - required by a bound in this
index 9935445c306586c88a33a6ae53f6ac923839f0c4..775f45ca82965020718cc52863323b1fe57793c8 100644 (file)
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `X`
   --> $DIR/hr-associated-type-bound-param-3.rs:4:33
    |
index c26324ee6255455da3fe2d642c09ab79e26f5492..4e9b64ba832adb19be7e4ce2c532751b2a56fed7 100644 (file)
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `X`
   --> $DIR/hr-associated-type-bound-param-4.rs:4:36
    |
index 920aa835280701e159dfc2866ed41ecf11ae2c76..d7f3151a502ee667dba173f83e5b583e243522a2 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-compare-mode-chalk
 trait Cycle: Sized {
     type Next: Cycle<Next = Self>;
 }
index 63cd89316b38cf6a94bbfbd19106ba8d2cbbeb0c..d00abf30d3b053d0fd487fb53e6d58b90a048661 100644 (file)
@@ -1,11 +1,13 @@
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-5.rs:27:14
+  --> $DIR/hr-associated-type-bound-param-5.rs:26:14
    |
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `X`
-  --> $DIR/hr-associated-type-bound-param-5.rs:18:45
+  --> $DIR/hr-associated-type-bound-param-5.rs:17:45
    |
 LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
    |       - required by a bound in this
@@ -14,13 +16,15 @@ LL |     for<'b> <T::Next as X<'b, T::Next>>::U: Clone,
    |                                             ^^^^^ required by this bound in `X`
 
 error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/hr-associated-type-bound-param-5.rs:32:14
+  --> $DIR/hr-associated-type-bound-param-5.rs:31:14
    |
 LL |     type U = str;
    |              ^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `X`
-  --> $DIR/hr-associated-type-bound-param-5.rs:18:45
+  --> $DIR/hr-associated-type-bound-param-5.rs:17:45
    |
 LL | trait X<'a, T: Cycle + for<'b> X<'b, T>>
    |       - required by a bound in this
index 4fcb41485d0e2bdbb6711125d0e55df719cf74c1..47ee3e7ad70e83a8267515af1f933d6a7095653b 100644 (file)
@@ -1,6 +1,5 @@
 // Tests that HRTBs are correctly accepted -- https://github.com/rust-lang/rust/issues/50301
 // check-pass
-// ignore-compare-mode-chalk
 trait Trait
 where
     for<'a> &'a Self::IntoIter: IntoIterator<Item = u32>,
diff --git a/src/test/ui/associated-types/issue-91069.rs b/src/test/ui/associated-types/issue-91069.rs
new file mode 100644 (file)
index 0000000..109c2ee
--- /dev/null
@@ -0,0 +1,24 @@
+// check-pass
+
+pub trait Associate {
+    type Associated;
+}
+
+pub struct Wrap<'a> {
+    pub field: &'a i32,
+}
+
+pub trait Create<T> {
+    fn create() -> Self;
+}
+
+pub fn oh_no<'a, T>()
+where
+    Wrap<'a>: Associate,
+    <Wrap<'a> as Associate>::Associated: Create<T>,
+{
+    <Wrap<'a> as Associate>::Associated::create();
+}
+
+
+pub fn main() {}
index 974a1d961a05e07c737a2873b8b147786d3a145c..66cd94d7a1b3730f224fdd13c3c44ca10ebb44ba 100644 (file)
@@ -25,7 +25,7 @@ fn foo<'z>() where &'z (): Sized {
     let x: () = <i8 as Foo<'static, 'static,  u32>>::bar::<'static, char>;
     //[verbose]~^ ERROR mismatched types
     //[verbose]~| expected unit type `()`
-    //[verbose]~| found fn item `fn() {<i8 as Foo<ReStatic, ReStatic, u32>>::bar::<ReStatic, char>}`
+    //[verbose]~| found fn item `fn() {<i8 as Foo<ReStatic, ReStatic>>::bar::<ReStatic, char>}`
     //[normal]~^^^^ ERROR mismatched types
     //[normal]~| expected unit type `()`
     //[normal]~| found fn item `fn() {<i8 as Foo<'static, 'static>>::bar::<'static, char>}`
index cf480223da2b3a5496529e1f24fbde565e7b6e02..b831f3b7a76d23aef2deaf317863be67d68ee0c8 100644 (file)
@@ -20,7 +20,7 @@ error[E0308]: mismatched types
   --> $DIR/substs-ppaux.rs:25:17
    |
 LL |     fn bar<'a, T>() where T: 'a {}
-   |     --------------------------- fn() {<i8 as Foo<ReStatic, ReStatic, u32>>::bar::<ReStatic, char>} defined here
+   |     --------------------------- fn() {<i8 as Foo<ReStatic, ReStatic>>::bar::<ReStatic, char>} defined here
 ...
 LL |     let x: () = <i8 as Foo<'static, 'static,  u32>>::bar::<'static, char>;
    |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found fn item
@@ -28,7 +28,7 @@ LL |     let x: () = <i8 as Foo<'static, 'static,  u32>>::bar::<'static, char>;
    |            expected due to this
    |
    = note: expected unit type `()`
-                found fn item `fn() {<i8 as Foo<ReStatic, ReStatic, u32>>::bar::<ReStatic, char>}`
+                found fn item `fn() {<i8 as Foo<ReStatic, ReStatic>>::bar::<ReStatic, char>}`
 help: use parentheses to call this function
    |
 LL |     let x: () = <i8 as Foo<'static, 'static,  u32>>::bar::<'static, char>();
index 05ec013d0afd88666d21158eb5b2add9417f9829..c627fe17afbbed51635608c6cad0b2e38cdf1793 100644 (file)
@@ -1,6 +1,7 @@
 // Regression test for #93197
 // check-pass
 // edition:2021
+// compile-flags: -Zdrop-tracking
 
 #![feature(try_blocks)]
 
diff --git a/src/test/ui/async-await/issue-93648.rs b/src/test/ui/async-await/issue-93648.rs
new file mode 100644 (file)
index 0000000..4ce3ac1
--- /dev/null
@@ -0,0 +1,12 @@
+// edition:2021
+// build-pass
+// compile-flags: -Zdrop-tracking
+
+fn main() {
+    let _ = async {
+        let mut s = (String::new(),);
+        s.0.push_str("abc");
+        std::mem::drop(s);
+        async {}.await;
+    };
+}
diff --git a/src/test/ui/attributes/main-removed-1.rs b/src/test/ui/attributes/main-removed-1.rs
new file mode 100644 (file)
index 0000000..0e88746
--- /dev/null
@@ -0,0 +1,2 @@
+#[main]  //~ ERROR cannot find attribute `main` in this scope
+fn main() {}
diff --git a/src/test/ui/attributes/main-removed-1.stderr b/src/test/ui/attributes/main-removed-1.stderr
new file mode 100644 (file)
index 0000000..2422c5c
--- /dev/null
@@ -0,0 +1,10 @@
+error: cannot find attribute `main` in this scope
+  --> $DIR/main-removed-1.rs:1:3
+   |
+LL | #[main]
+   |   ^^^^
+   |
+   = note: `main` is in scope, but it is a function, not an attribute
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/attributes/main-removed-2/auxiliary/tokyo.rs b/src/test/ui/attributes/main-removed-2/auxiliary/tokyo.rs
new file mode 100644 (file)
index 0000000..196b5be
--- /dev/null
@@ -0,0 +1,12 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn main(_: TokenStream, input: TokenStream) -> TokenStream {
+    "fn main() { println!(\"Hello Tokyo!\"); }".parse().unwrap()
+}
diff --git a/src/test/ui/attributes/main-removed-2/main.rs b/src/test/ui/attributes/main-removed-2/main.rs
new file mode 100644 (file)
index 0000000..e8fecf8
--- /dev/null
@@ -0,0 +1,11 @@
+// run-pass
+// aux-build:tokyo.rs
+// compile-flags:--extern tokyo
+// edition:2021
+
+use tokyo::main;
+
+#[main]
+fn main() {
+    panic!("the #[main] macro should replace this with non-panicking code")
+}
diff --git a/src/test/ui/attributes/used_with_arg.rs b/src/test/ui/attributes/used_with_arg.rs
new file mode 100644 (file)
index 0000000..ad80ff5
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(used_with_arg)]
+
+#[used(linker)]
+static mut USED_LINKER: [usize; 1] = [0];
+
+#[used(compiler)]
+static mut USED_COMPILER: [usize; 1] = [0];
+
+#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together
+#[used(linker)]
+static mut USED_COMPILER_LINKER2: [usize; 1] = [0];
+
+#[used(compiler)] //~ ERROR `used(compiler)` and `used(linker)` can't be used together
+#[used(linker)]
+#[used(compiler)]
+#[used(linker)]
+static mut USED_COMPILER_LINKER3: [usize; 1] = [0];
+
+fn main() {}
diff --git a/src/test/ui/attributes/used_with_arg.stderr b/src/test/ui/attributes/used_with_arg.stderr
new file mode 100644 (file)
index 0000000..440e5c4
--- /dev/null
@@ -0,0 +1,18 @@
+error: `used(compiler)` and `used(linker)` can't be used together
+  --> $DIR/used_with_arg.rs:9:1
+   |
+LL | #[used(compiler)]
+   | ^^^^^^^^^^^^^^^^^
+LL | #[used(linker)]
+   | ^^^^^^^^^^^^^^^
+
+error: `used(compiler)` and `used(linker)` can't be used together
+  --> $DIR/used_with_arg.rs:13:1
+   |
+LL | #[used(compiler)]
+   | ^^^^^^^^^^^^^^^^^
+LL | #[used(linker)]
+   | ^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/attributes/used_with_multi_args.rs b/src/test/ui/attributes/used_with_multi_args.rs
new file mode 100644 (file)
index 0000000..2e17fcf
--- /dev/null
@@ -0,0 +1,6 @@
+#![feature(used_with_arg)]
+
+#[used(compiler, linker)] //~ expected `used`, `used(compiler)` or `used(linker)`
+static mut USED_COMPILER_LINKER: [usize; 1] = [0];
+
+fn main() {}
diff --git a/src/test/ui/attributes/used_with_multi_args.stderr b/src/test/ui/attributes/used_with_multi_args.stderr
new file mode 100644 (file)
index 0000000..c93aafc
--- /dev/null
@@ -0,0 +1,8 @@
+error: expected `used`, `used(compiler)` or `used(linker)`
+  --> $DIR/used_with_multi_args.rs:3:1
+   |
+LL | #[used(compiler, linker)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 8ce70b1ac0677c53494c4bc7a86d75f82c85d6ab..5755778fef2661cb28a295da1fe7cc42d8098cb7 100644 (file)
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `u32: Signed` is not satisfied
 LL |     is_defaulted::<&'static u32>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`
    |
+   = help: the following implementations were found:
+             <i32 as Signed>
 note: required because of the requirements on the impl of `Defaulted` for `&'static u32`
   --> $DIR/typeck-default-trait-impl-precedence.rs:10:19
    |
index 10f243bab158684547064ad0a445e95f4ce22806..1875ea06a06d5adf1f83b98c059b94a4a8d46f43 100644 (file)
@@ -272,9 +272,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A`
    |
 LL | struct A;
    | ^^^^^^^^^ must implement `PartialOrd<_>`
-help: consider annotating `A` with `#[derive(PartialOrd)]`
+help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]`
    |
-LL | #[derive(PartialOrd)]
+LL | #[derive(PartialEq, PartialOrd)]
    |
 
 error[E0369]: binary operation `<=` cannot be applied to type `A`
@@ -290,9 +290,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A`
    |
 LL | struct A;
    | ^^^^^^^^^ must implement `PartialOrd<_>`
-help: consider annotating `A` with `#[derive(PartialOrd)]`
+help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]`
    |
-LL | #[derive(PartialOrd)]
+LL | #[derive(PartialEq, PartialOrd)]
    |
 
 error[E0369]: binary operation `>` cannot be applied to type `A`
@@ -308,9 +308,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A`
    |
 LL | struct A;
    | ^^^^^^^^^ must implement `PartialOrd<_>`
-help: consider annotating `A` with `#[derive(PartialOrd)]`
+help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]`
    |
-LL | #[derive(PartialOrd)]
+LL | #[derive(PartialEq, PartialOrd)]
    |
 
 error[E0369]: binary operation `>=` cannot be applied to type `A`
@@ -326,9 +326,9 @@ note: an implementation of `PartialOrd<_>` might be missing for `A`
    |
 LL | struct A;
    | ^^^^^^^^^ must implement `PartialOrd<_>`
-help: consider annotating `A` with `#[derive(PartialOrd)]`
+help: consider annotating `A` with `#[derive(PartialEq, PartialOrd)]`
    |
-LL | #[derive(PartialOrd)]
+LL | #[derive(PartialEq, PartialOrd)]
    |
 
 error: aborting due to 15 previous errors
index 9e70a847457c0e91ab9106fb19602ffff24665ff..33d55be5812e78822b18d7e8472195b5b789c9fc 100644 (file)
@@ -2,7 +2,7 @@
 struct Value;
 
 static settings_dir: String = format!("");
-//~^ ERROR calls in statics are limited to constant functions
+//~^ ERROR cannot call non-const fn
 //~| ERROR is not yet stable as a const
 
 fn from_string(_: String) -> Value {
index 14e1667038965b772576cbc3106e1b071bcc5d9a..f3436fbec66a605327139855744a48cc66f327dc 100644 (file)
@@ -7,12 +7,13 @@ LL | static settings_dir: String = format!("");
    = help: add `#![feature(const_fmt_arguments_new)]` to the crate attributes to enable
    = note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `format` in statics
   --> $DIR/issue-64453.rs:4:31
    |
 LL | static settings_dir: String = format!("");
    |                               ^^^^^^^^^^^
    |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0507]: cannot move out of static item `settings_dir`
diff --git a/src/test/ui/box/issue-78459-ice.rs b/src/test/ui/box/issue-78459-ice.rs
new file mode 100644 (file)
index 0000000..89f75fe
--- /dev/null
@@ -0,0 +1,6 @@
+// check-pass
+#![feature(allocator_api)]
+
+fn main() {
+    Box::new_in((), &std::alloc::Global);
+}
diff --git a/src/test/ui/chalkify/assert.rs b/src/test/ui/chalkify/assert.rs
new file mode 100644 (file)
index 0000000..f4ebf91
--- /dev/null
@@ -0,0 +1,6 @@
+// run-pass
+// compile-flags: -Z chalk
+
+fn main() {
+    assert_eq!(1, 1);
+}
index f8b792ae5363ca2400ad3fa68cf0d170c1f5a4ec..7b0b3f85b39158d27ffcf442e33772ab3eec2db2 100644 (file)
@@ -4,6 +4,9 @@ error[E0277]: the trait bound `f32: Foo` is not satisfied
 LL |     gimme::<f32>();
    |             ^^^ the trait `Foo` is not implemented for `f32`
    |
+   = help: the following implementations were found:
+             <i32 as Foo>
+             <u32 as Foo>
 note: required by a bound in `gimme`
   --> $DIR/chalk_initial_program.rs:9:13
    |
index 95e320726aab0a6bd2ec27a50c5ee878a1b0a9df..2bc9f077f0285dc817d2b83e59684db0b51cb2c4 100644 (file)
@@ -17,6 +17,8 @@ error[E0277]: the trait bound `f32: Foo` is not satisfied
 LL | impl Baz<f32> for f32 { }
    |      ^^^^^^^^ the trait `Foo` is not implemented for `f32`
    |
+   = help: the following implementations were found:
+             <i32 as Foo>
 note: required by a bound in `Baz`
   --> $DIR/impl_wf.rs:18:31
    |
index 80ec03d6221e8e88b41b9993f75565e0433693f2..30cec80b036c629ea13bc92b043e718949de0f6a 100644 (file)
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `f32: Foo` is not satisfied
 LL |     type Item = f32;
    |                 ^^^ the trait `Foo` is not implemented for `f32`
    |
+   = help: the following implementations were found:
+             <i32 as Foo>
 note: required by a bound in `Bar::Item`
   --> $DIR/impl_wf_2.rs:8:16
    |
index cf36aef8afaf3d0c9963229d64099c941e820af4..0f0df29019e7bbc1dbea32322013e0b696abb71e 100644 (file)
@@ -2,6 +2,5 @@
 // compile-flags: -Z chalk
 
 fn main() {
-    // FIXME(chalk): Require `RegionOutlives`/`TypeOutlives`/`Subtype` support
-    //println!("hello");
+    println!("hello");
 }
index 13d9e6a6578856fd89c5a359bcf2f4434280ce0c..d56abc42bf540c048951ac55830e97e3c50bf309 100644 (file)
@@ -5,8 +5,7 @@
 
 fn main() {
     let d: &dyn Display = &mut 3;
-    // FIXME(chalk) should be able to call d.to_string() as well, but doing so
-    // requires Chalk to be able to prove trait object well-formed goals.
+    d.to_string();
     (&d).to_string();
     let f: &dyn Fn(i32) -> _ = &|x| x + x;
     f(2);
index 57902efa2015cb8de239e3d780c9806fd31ae613..6abd8b28760d8261b2c21965a56bf57cb7eadc7f 100644 (file)
@@ -5,7 +5,6 @@ LL |     let s = S {
    |             ^ the trait `Foo` is not implemented for `{float}`
    |
    = help: the following implementations were found:
-             <Option<T> as Foo>
              <i32 as Foo>
 note: required by a bound in `S`
   --> $DIR/type_wf.rs:6:13
index 3d1b5a08227569652484309536d72ce709932b4b..eb4ecd8baca965e97ecc4d5fc75c291f7021a2b3 100644 (file)
@@ -87,7 +87,7 @@ fn drop(&mut self) {}
 static mut STATIC14: SafeStruct = SafeStruct {
     field1: SafeEnum::Variant1,
     field2: SafeEnum::Variant4("str".to_string())
-//~^ ERROR calls in statics are limited to constant functions
+//~^ ERROR cannot call non-const fn
 };
 
 static STATIC15: &'static [Box<MyOwned>] = &[
index eb640c88e026f1c487225f5a90aeff19d88350b9..b28cf0d6bd0f582808a27f90823e8595d040ee16 100644 (file)
@@ -15,11 +15,13 @@ error[E0010]: allocations are not allowed in statics
 LL | static STATIC11: Box<MyOwned> = box MyOwned;
    |                                 ^^^^^^^^^^^ allocation not allowed in statics
 
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/check-static-values-constraints.rs:89:32
+error[E0015]: cannot call non-const fn `<str as ToString>::to_string` in statics
+  --> $DIR/check-static-values-constraints.rs:89:38
    |
 LL |     field2: SafeEnum::Variant4("str".to_string())
-   |                                ^^^^^^^^^^^^^^^^^
+   |                                      ^^^^^^^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error[E0010]: allocations are not allowed in statics
   --> $DIR/check-static-values-constraints.rs:94:5
index 357dd25389ecbbed2969ac430dd4b2990f30ef13..e5aef04b6894eaf1b3a9805eb95e812535754894 100644 (file)
@@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `路濫狼á́́`
 LL | extern "路濫狼á́́" fn foo() {}
    |        ^^^^^^^^^ invalid ABI
    |
-   = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
+   = help: valid ABIs: Rust, C, C-unwind, cdecl, cdecl-unwind, stdcall, stdcall-unwind, fastcall, fastcall-unwind, vectorcall, vectorcall-unwind, thiscall, thiscall-unwind, aapcs, aapcs-unwind, win64, win64-unwind, sysv64, sysv64-unwind, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
 
 error: aborting due to previous error
 
index 43806cb995c0309aff489147db0e6b5d3cc2e265..19ff9ae62fdc644002133c17e90d1d146572765e 100644 (file)
@@ -1,5 +1,6 @@
 #![crate_type = "lib"]
 #![feature(negative_impls)]
+#![feature(with_negative_coherence)]
 
 pub trait Error {}
 impl !Error for &str {}
diff --git a/src/test/ui/coherence/coherence-negative-outlives-lifetimes.rs b/src/test/ui/coherence/coherence-negative-outlives-lifetimes.rs
new file mode 100644 (file)
index 0000000..159788b
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(negative_impls)]
+
+// FIXME: this should compile
+
+trait MyPredicate<'a> {}
+impl<'a, T> !MyPredicate<'a> for &T where T: 'a {}
+trait MyTrait<'a> {}
+impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {}
+impl<'a, T> MyTrait<'a> for &'a T {}
+//~^ ERROR: conflicting implementations of trait `MyTrait<'_>` for type `&_`
+
+fn main() {}
diff --git a/src/test/ui/coherence/coherence-negative-outlives-lifetimes.stderr b/src/test/ui/coherence/coherence-negative-outlives-lifetimes.stderr
new file mode 100644 (file)
index 0000000..263bd19
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0119]: conflicting implementations of trait `MyTrait<'_>` for type `&_`
+  --> $DIR/coherence-negative-outlives-lifetimes.rs:9:1
+   |
+LL | impl<'a, T: MyPredicate<'a>> MyTrait<'a> for T {}
+   | ---------------------------------------------- first implementation here
+LL | impl<'a, T> MyTrait<'a> for &'a T {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0119`.
index e024eae9819abcda58765cabedbea3e957a9d360..a0dd881d1aaad7455fa266dd44f0a47149949c66 100644 (file)
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(negative_impls)]
+#![feature(with_negative_coherence)]
 
 use std::ops::DerefMut;
 
index ab65163bea4424945fac4ed2d2faf108e3687214..8059d23ffd215f9b4df5a09900fb003ed893bf40 100644 (file)
@@ -3,7 +3,7 @@
 //
 // Check that if we promise to not impl what would overlap it doesn't actually overlap
 
-#![feature(negative_impls)]
+#![feature(with_negative_coherence)]
 
 extern crate error_lib as lib;
 use lib::Error;
diff --git a/src/test/ui/coherence/coherence-overlap-with-regions.rs b/src/test/ui/coherence/coherence-overlap-with-regions.rs
new file mode 100644 (file)
index 0000000..32f01f4
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+#![feature(with_negative_coherence)]
+
+#[rustc_strict_coherence]
+trait Foo {}
+impl<T> !Foo for &T where T: 'static {}
+
+#[rustc_strict_coherence]
+trait Bar {}
+impl<T: Foo> Bar for T {}
+impl<T> Bar for &T where T: 'static {}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const-generic-default-wont-borrowck.rs b/src/test/ui/const-generics/const-generic-default-wont-borrowck.rs
new file mode 100644 (file)
index 0000000..bb5a2f1
--- /dev/null
@@ -0,0 +1,6 @@
+struct X<const N: usize = {
+    let s: &'static str; s.len()
+    //~^ ERROR borrow of possibly-uninitialized variable
+}>;
+
+fn main() {}
diff --git a/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr b/src/test/ui/const-generics/const-generic-default-wont-borrowck.stderr
new file mode 100644 (file)
index 0000000..6c25019
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0381]: borrow of possibly-uninitialized variable: `s`
+  --> $DIR/const-generic-default-wont-borrowck.rs:2:26
+   |
+LL |     let s: &'static str; s.len()
+   |                          ^^^^^^^ use of possibly-uninitialized `*s`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0381`.
index 8c8bfdc0e4847a82fb8c79c164ff78af1ed60cc8..19813a491c96e4e9e22579263f953913d32f0107 100644 (file)
@@ -15,6 +15,7 @@ LL | fn uwu<const N: u8>() -> impl Traitor<N> {
    |
    = help: the following implementations were found:
              <u32 as Traitor<N, 2_u8>>
+             <u64 as Traitor<1_u8, 2_u8>>
 
 error[E0277]: the trait bound `u64: Traitor<1_u8, 1_u8>` is not satisfied
   --> $DIR/rp_impl_trait_fail.rs:22:13
@@ -24,6 +25,7 @@ LL | fn owo() -> impl Traitor {
    |
    = help: the following implementations were found:
              <u64 as Traitor<1_u8, 2_u8>>
+             <u32 as Traitor<N, 2_u8>>
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/const-generics/issue-93647.rs b/src/test/ui/const-generics/issue-93647.rs
new file mode 100644 (file)
index 0000000..c1a6bf6
--- /dev/null
@@ -0,0 +1,6 @@
+struct X<const N: usize = {
+    (||1usize)()
+    //~^ ERROR cannot call
+}>;
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issue-93647.stderr b/src/test/ui/const-generics/issue-93647.stderr
new file mode 100644 (file)
index 0000000..e2048ec
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0015]: cannot call non-const closure in constants
+  --> $DIR/issue-93647.rs:2:5
+   |
+LL |     (||1usize)()
+   |     ^^^^^^^^^^^^
+   |
+   = note: closures need an RFC before allowed to be called in constants
+   = 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 0c640a5ef7136c12f79c593b38e586f565df9b10..bebd0c6ac1202d656c67299d2dac1f19a105a02c 100644 (file)
@@ -13,7 +13,7 @@ fn consume<T: 'static>(_val: T)
 where
     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
     //~^ ERROR: overly complex generic constant
-    //~| ERROR: calls in constants are limited to constant functions
+    //~| ERROR: cannot call non-const operator in constants
 {
 }
 
@@ -21,7 +21,7 @@ fn test<T: 'static>()
 where
     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
     //~^ ERROR: overly complex generic constant
-    //~| ERROR: calls in constants are limited to constant functions
+    //~| ERROR: cannot call non-const operator in constants
 {
 }
 
index 2b8afe2ef09ed77040bf834394fce922a2008c60..c8690ecd0da7e84434306962292eb922f7abe4b8 100644 (file)
@@ -9,11 +9,19 @@ LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const operator in constants
   --> $DIR/issue-90318.rs:14:10
    |
 LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   |
+LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+   |                       ^^^^^^^^^
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: overly complex generic constant
   --> $DIR/issue-90318.rs:22:8
@@ -26,11 +34,19 @@ LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
    = help: consider moving this anonymous constant into a `const` function
    = note: this operation may be supported in the future
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const operator in constants
   --> $DIR/issue-90318.rs:22:10
    |
 LL |     If<{ TypeId::of::<T>() != TypeId::of::<()>() }>: True,
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/any.rs:LL:COL
+   |
+LL | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+   |                       ^^^^^^^^^
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
+   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/const-generics/min_const_generics/forbid-self-no-normalize.rs b/src/test/ui/const-generics/min_const_generics/forbid-self-no-normalize.rs
new file mode 100644 (file)
index 0000000..e1cf7b5
--- /dev/null
@@ -0,0 +1,15 @@
+trait AlwaysApplicable {
+    type Assoc;
+}
+impl<T: ?Sized> AlwaysApplicable for T {
+    type Assoc = usize;
+}
+
+trait BindsParam<T> {
+    type ArrayTy;
+}
+impl<T> BindsParam<T> for <T as AlwaysApplicable>::Assoc {
+    type ArrayTy = [u8; Self::MAX]; //~ ERROR generic `Self` types
+}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/min_const_generics/forbid-self-no-normalize.stderr b/src/test/ui/const-generics/min_const_generics/forbid-self-no-normalize.stderr
new file mode 100644 (file)
index 0000000..bda8859
--- /dev/null
@@ -0,0 +1,14 @@
+error: generic `Self` types are currently not permitted in anonymous constants
+  --> $DIR/forbid-self-no-normalize.rs:12:25
+   |
+LL |     type ArrayTy = [u8; Self::MAX];
+   |                         ^^^^
+   |
+note: not a concrete type
+  --> $DIR/forbid-self-no-normalize.rs:11:27
+   |
+LL | impl<T> BindsParam<T> for <T as AlwaysApplicable>::Assoc {
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index 9d7ca36545c9c650a2f931a7a5950045fa49c9aa..52f1c588258235db49b315efeea2a1034e26887c 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants
   --> $DIR/nested-type.rs:15:5
    |
 LL |     Foo::<17>::value()
    |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
index 4f32284ecb1e0571ffc5a9f32e046c35e8a63452..0e3c988ae4d8c9f34e285cc9b188953bffc74d28 100644 (file)
@@ -14,11 +14,13 @@ LL | | }]>;
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `Foo::{constant#0}::Foo::<17_usize>::value` in constants
   --> $DIR/nested-type.rs:15:5
    |
 LL |     Foo::<17>::value()
    |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 2 previous errors
 
index 039f996de96db2c66028ec44250158dcc9ef9635..5240f5c3b0b64b8d4cc3919b3cd167ecdfb3ce15 100644 (file)
@@ -13,7 +13,7 @@ fn value() -> usize {
     }
 
     Foo::<17>::value()
-    //~^ ERROR calls in constants are limited to constant functions
+    //~^ ERROR cannot call non-const fn
 }]>;
 
 fn main() {}
diff --git a/src/test/ui/const-generics/outer-lifetime-in-const-generic-default.rs b/src/test/ui/const-generics/outer-lifetime-in-const-generic-default.rs
new file mode 100644 (file)
index 0000000..3018439
--- /dev/null
@@ -0,0 +1,10 @@
+struct Foo<
+    'a,
+    const N: usize = {
+        let x: &'a ();
+        //~^ ERROR use of non-static lifetime `'a` in const generic
+        3
+    },
+>(&'a ());
+
+fn main() {}
diff --git a/src/test/ui/const-generics/outer-lifetime-in-const-generic-default.stderr b/src/test/ui/const-generics/outer-lifetime-in-const-generic-default.stderr
new file mode 100644 (file)
index 0000000..9d9555d
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0771]: use of non-static lifetime `'a` in const generic
+  --> $DIR/outer-lifetime-in-const-generic-default.rs:4:17
+   |
+LL |         let x: &'a ();
+   |                 ^^
+   |
+   = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0771`.
index db642988971e0266d10968e32b7afca1bca8070b..28e89559fe538653a62da22f7b34313c18828d7e 100644 (file)
@@ -4,5 +4,5 @@ fn f(x: usize) -> usize {
 
 fn main() {
     let _ = [0; f(2)];
-    //~^ ERROR calls in constants are limited to constant functions
+    //~^ ERROR cannot call non-const fn
 }
index 9761348bab824f77f70589ec67a437410a1b74fe..e46bcad0e1d0ea48dff0ea76cfce951496bdc8aa 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `f` in constants
   --> $DIR/const-call.rs:6:17
    |
 LL |     let _ = [0; f(2)];
    |                 ^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
index 1e181c465dba768c3b628cbd50c4b6c613ee9a39..f59ff329d18ace8ee4731ebdaf9724d0c53c3e82 100644 (file)
@@ -17,6 +17,12 @@ error[E0604]: only `u8` can be cast as `char`, not `i8`
    |
 LL |     : [u32; 5i8 as char as usize]
    |             ^^^^^^^^^^^ invalid cast
+   |
+help: try casting from `u8` instead
+  --> $DIR/const-eval-overflow-4b.rs:22:13
+   |
+LL |     : [u32; 5i8 as char as usize]
+   |             ^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
index 8da697fe7ef3bcbf4c71ad78ff50b0a96ebf32a4..2955f11716c418d8f1e8b8de2d5e2243fc068041 100644 (file)
@@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed
 LL | const Y: () = std::unreachable!();
    |               ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:12:15
    |
-   = note: this error originates in the macro `std::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::unreachable_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const_panic.rs:15:15
@@ -68,7 +68,7 @@ error[E0080]: evaluation of constant value failed
 LL | const Y_CORE: () = core::unreachable!();
    |                    ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:30:20
    |
-   = note: this error originates in the macro `core::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::unreachable_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const_panic.rs:33:20
index 62fe1715fecb5c9eae7e5c206a270e43020ecad7..cb3b08e0e09991c44bdf92ee5d9d37b3cb50daf4 100644 (file)
@@ -20,7 +20,7 @@ error[E0080]: evaluation of constant value failed
 LL | const C: () = std::unreachable!();
    |               ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:12:15
    |
-   = note: this error originates in the macro `std::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::unreachable_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const_panic_2021.rs:15:15
@@ -60,7 +60,7 @@ error[E0080]: evaluation of constant value failed
 LL | const C_CORE: () = core::unreachable!();
    |                    ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:27:20
    |
-   = note: this error originates in the macro `core::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::unreachable_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const_panic_2021.rs:30:20
index 52c0c13636687c47b875d7f15ae05dc5bee5dca6..417120c453e927427247b3e2c4b96c2ec87a169c 100644 (file)
@@ -12,7 +12,7 @@ error[E0080]: evaluation of constant value failed
 LL | const Y: () = unreachable!();
    |               ^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:11:15
    |
-   = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: this error originates in the macro `$crate::panic::unreachable_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const_panic_libcore_bin.rs:14:15
diff --git a/src/test/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr b/src/test/ui/consts/const-eval/ub-nonnull.chalk.64bit.stderr
new file mode 100644 (file)
index 0000000..2a4b6f3
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0284]: type annotations needed: cannot satisfy `<usize as SliceIndex<[u8]>>::Output == _`
+  --> $DIR/ub-nonnull.rs:19:30
+   |
+LL |     let out_of_bounds_ptr = &ptr[255];
+   |                              ^^^^^^^^ cannot satisfy `<usize as SliceIndex<[u8]>>::Output == _`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0284`.
diff --git a/src/test/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr b/src/test/ui/consts/const-eval/ub-wide-ptr.chalk.64bit.stderr
new file mode 100644 (file)
index 0000000..39352ca
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/ub-wide-ptr.rs:90:67
+   |
+LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
+   |                                                                   ^^^^^^^^^^^^^^ cannot infer type for type parameter `U` declared on the function `transmute`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
index ee07dfae47c38e0a318cc18806b7a0eef9ef48ec..eccda49db3eb54481ffd581cd0c07b0206c00960 100644 (file)
@@ -7,7 +7,7 @@
 const extern "C" fn bar() {
     unsafe {
         regular_in_block();
-        //~^ ERROR: calls in constant functions
+        //~^ ERROR: cannot call non-const fn
     }
 }
 
@@ -16,7 +16,7 @@ extern "C" fn regular() {}
 const extern "C" fn foo() {
     unsafe {
         regular();
-        //~^ ERROR: calls in constant functions
+        //~^ ERROR: cannot call non-const fn
     }
 }
 
index 348387ff5f827521fe56fe87f9e740467e4e3140..5acf22e4bc66e3591d94240f25ecee1e4f52b5dc 100644 (file)
@@ -1,14 +1,18 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `regular_in_block` in constant functions
   --> $DIR/const-extern-fn-call-extern-fn.rs:9:9
    |
 LL |         regular_in_block();
    |         ^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `regular` in constant functions
   --> $DIR/const-extern-fn-call-extern-fn.rs:18:9
    |
 LL |         regular();
    |         ^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 2 previous errors
 
index 948c162e8946d8c3a8a54d8ff6445b55727ebee5..abe68c17a0d7f1c0b7062547968dbf2d2db2bdb7 100644 (file)
@@ -4,9 +4,8 @@ const fn f(x: usize) -> usize {
     let mut sum = 0;
     for i in 0..x {
         //~^ ERROR mutable references
-        //~| ERROR calls in constant functions
-        //~| ERROR calls in constant functions
-        //~| ERROR E0080
+        //~| ERROR cannot convert
+        //~| ERROR cannot call non-const fn
         //~| ERROR `for` is not allowed in a `const fn`
         sum += i;
     }
index df24585e5551ac0e0018d09f6d125428666685dd..4d53cfc35e1c4ab88db8e8b0bca1e545a23c99b2 100644 (file)
@@ -5,7 +5,7 @@ LL | /     for i in 0..x {
 LL | |
 LL | |
 LL | |
-...  |
+LL | |
 LL | |         sum += i;
 LL | |     }
    | |_____^
@@ -13,11 +13,18 @@ LL | |     }
    = note: see issue #87575 <https://github.com/rust-lang/rust/issues/87575> for more information
    = help: add `#![feature(const_for)]` to the crate attributes to enable
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot convert `std::ops::Range<usize>` into an iterator in constant functions
   --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL | impl<I: Iterator> IntoIterator for I {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error[E0658]: mutable references are not allowed in constant functions
   --> $DIR/const-fn-error.rs:5:14
@@ -28,25 +35,15 @@ LL |     for i in 0..x {
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<std::ops::Range<usize> as Iterator>::next` in constant functions
   --> $DIR/const-fn-error.rs:5:14
    |
 LL |     for i in 0..x {
    |              ^^^^
-
-error[E0080]: evaluation of constant value failed
-  --> $DIR/const-fn-error.rs:5:14
    |
-LL |     for i in 0..x {
-   |              ^^^^
-   |              |
-   |              calling non-const function `<std::ops::Range<usize> as IntoIterator>::into_iter`
-   |              inside `f` at $DIR/const-fn-error.rs:5:14
-...
-LL |     let a : [i32; f(X)];
-   |                   ---- inside `main::{constant#0}` at $DIR/const-fn-error.rs:18:19
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
 
-Some errors have detailed explanations: E0015, E0080, E0658.
+Some errors have detailed explanations: E0015, E0658.
 For more information about an error, try `rustc --explain E0015`.
index df793d7dd7ec947a4833a7e8d1dd4eb44f60b36c..4c7effc0d158657594810410aa6a1ef27eecbc20 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `random` in constant functions
   --> $DIR/const-fn-not-safe-for-const.rs:14:5
    |
 LL |     random()
    |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error[E0013]: constant functions cannot refer to statics
   --> $DIR/const-fn-not-safe-for-const.rs:20:5
index 5fc1ee0e36948156eb9585d5910085e626d762e4..58bcb5f74ccf6254f2e9f538ea35e3a46e94ba12 100644 (file)
@@ -3,8 +3,8 @@
 
 const _: () = {
     for _ in 0..5 {}
-    //~^ error: calls in constants are limited to
-    //~| error: calls in constants are limited to
+    //~^ error: cannot convert
+    //~| error: cannot call non-const fn
 };
 
 fn main() {}
index a35c04b3570b2e542fdf960ec586c5a70bd2e318..b0dc43eb8e8508f0d23cb136faa64e168408afb2 100644 (file)
@@ -1,14 +1,23 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot convert `std::ops::Range<i32>` into an iterator in constants
   --> $DIR/const-for.rs:5:14
    |
 LL |     for _ in 0..5 {}
    |              ^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL | impl<I: Iterator> IntoIterator for I {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<std::ops::Range<i32> as Iterator>::next` in constants
   --> $DIR/const-for.rs:5:14
    |
 LL |     for _ in 0..5 {}
    |              ^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 2 previous errors
 
index a9411fb0e3d4c23c726540be5dc9879a6321541d..61b00be345feee4bb0cf3a42aaa397097a8de029 100644 (file)
@@ -19,18 +19,7 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
 LL | const S: &'static mut str = &mut " hello ";
    |                             ^^^^^^^^^^^^^^ cannot borrow as mutable
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/issue-76510.rs:5:1
-   |
-LL | const S: &'static mut str = &mut " hello ";
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const`
-   |
-   = 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) {
-               ╾─alloc3──╼ 07 00 00 00                         │ ╾──╼....
-           }
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0080, E0596, E0658, E0764.
-For more information about an error, try `rustc --explain E0080`.
+Some errors have detailed explanations: E0596, E0658, E0764.
+For more information about an error, try `rustc --explain E0596`.
index 9ad5f20d57cb2f2ea7b73a583fc599f6b40efa28..61b00be345feee4bb0cf3a42aaa397097a8de029 100644 (file)
@@ -19,18 +19,7 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
 LL | const S: &'static mut str = &mut " hello ";
    |                             ^^^^^^^^^^^^^^ cannot borrow as mutable
 
-error[E0080]: it is undefined behavior to use this value
-  --> $DIR/issue-76510.rs:5:1
-   |
-LL | const S: &'static mut str = &mut " hello ";
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered mutable reference in a `const`
-   |
-   = 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) {
-               ╾───────alloc3────────╼ 07 00 00 00 00 00 00 00 │ ╾──────╼........
-           }
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0080, E0596, E0658, E0764.
-For more information about an error, try `rustc --explain E0080`.
+Some errors have detailed explanations: E0596, E0658, E0764.
+For more information about an error, try `rustc --explain E0596`.
index 892f6c98116c2184953bc3fba45ad2e6f368876f..143d2fb6b9a3a1a599f36edcc222f4f1d7d34e83 100644 (file)
@@ -6,7 +6,6 @@
 //~^ ERROR: mutable references are not allowed in the final value of constants
 //~| ERROR: mutation through a reference is not allowed in constants
 //~| ERROR: cannot borrow data in a `&` reference as mutable
-//~| ERROR: it is undefined behavior to use this value
 
 const fn trigger() -> [(); unsafe {
         let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3));
index 6724984d8d7ac1f26f023cecc3e3bed91dc9488f..d301f8c4054c23bb901cac12cc877926b3a90607 100644 (file)
@@ -6,6 +6,10 @@ LL | const TUP: (usize,) = 5usize << 64;
    |
    = note: expected tuple `(usize,)`
                found type `usize`
+help: use a trailing comma to create a tuple with one element
+   |
+LL | const TUP: (usize,) = (5usize << 64,);
+   |                       +            ++
 
 error: aborting due to previous error
 
index d652b5268a8bf3594c8743eab58ca184713245d2..7d9e18cb341f38330e3e99e141386cf3fdeb935e 100644 (file)
@@ -4,7 +4,7 @@ error[E0658]: trait bounds other than `Sized` on const fn parameters are unstabl
 LL | const fn test1<T: std::ops::Add>() {}
    |                ^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: trait objects in const fn are unstable
@@ -13,7 +13,7 @@ error[E0658]: trait objects in const fn are unstable
 LL | const fn test2(_x: &dyn Send) {}
    |                ^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: trait objects in const fn are unstable
@@ -22,7 +22,7 @@ error[E0658]: trait objects in const fn are unstable
 LL | const fn test3() -> &'static dyn Send { loop {} }
    |                     ^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error: aborting due to 3 previous errors
index edf62f23266193b667da1d761005cd65908943de..ddddc8505c635102ec743013828870f80be4d7ee 100644 (file)
@@ -8,7 +8,7 @@ fn non_const() -> Thing {
 }
 
 pub const Q: i32 = match non_const() {
-    //~^ ERROR calls in constants are limited to constant functions
+    //~^ ERROR cannot call non-const fn
     Thing::This => 1,
     Thing::That => 0
 };
index ea9ea25f9e12d34d6bf1e0af16d6b7dda88b9fcf..66227f61e35638e985e8d10b59d8d31a9e68e4ee 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `non_const` in constants
   --> $DIR/issue-46843.rs:10:26
    |
 LL | pub const Q: i32 = match non_const() {
    |                          ^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
index 810158a295792194523fc5814ee520816b214b4e..d5f694986fc8997ad7048118407af6b563a86fe5 100644 (file)
@@ -11,7 +11,7 @@
     }
 
     unsafe { copy(src, dst, count) }
-    //~^ ERROR calls in constant functions are limited to constant functions
+    //~^ ERROR cannot call non-const fn
 }
 
 fn main() {}
index 5a42823a6052aa05726c72b4a1648267a0e300dc..b32b6398ece62b1e2e2a2892b81dc7c0d496444d 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `copy::copy::<T>` in constant functions
   --> $DIR/intrinsic_without_const_stab.rs:13:14
    |
 LL |     unsafe { copy(src, dst, count) }
    |              ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
index bf2c44169d48b8e70fc722e4f121615f0a295811..8b37268b0b205c5c8e29f276be7bc0ec395bb645 100644 (file)
@@ -9,7 +9,7 @@
 #[rustc_const_unstable(feature = "const_intrinsic_copy", issue = "80697")]
 #[inline]
 pub const unsafe fn stuff<T>(src: *const T, dst: *mut T, count: usize) {
-    unsafe { copy(src, dst, count) } //~ ERROR calls in constant functions are limited
+    unsafe { copy(src, dst, count) } //~ ERROR cannot call non-const fn
 }
 
 fn main() {}
index d4a2989e785e0c6967cc3eca6a974c64028f8b64..fcbb3724567fef5a252657bbc11d7b8030eb9815 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `copy::<T>` in constant functions
   --> $DIR/intrinsic_without_const_stab_fail.rs:12:14
    |
 LL |     unsafe { copy(src, dst, count) }
    |              ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
index e5bd7aafe41e6559c8867fa0b05baaa4e8a42521..f8131c9f3b717107d5d2530b29490d79adfdc163 100644 (file)
@@ -2,7 +2,7 @@
 
 const X: u8 =
     || -> u8 { 5 }()
-    //~^ ERROR calls in constants are limited to constant functions
+    //~^ ERROR cannot call non-const closure
 ;
 
 fn main() {}
index 3d274d777b0c75f8769b1ba7b0c3e6345fb18884..7ad1f752eb085fd56dececf014f75d64e81fc0fe 100644 (file)
@@ -1,8 +1,11 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const closure in constants
   --> $DIR/issue-28113.rs:4:5
    |
 LL |     || -> u8 { 5 }()
    |     ^^^^^^^^^^^^^^^^
+   |
+   = note: closures need an RFC before allowed to be called in constants
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
index e0fcf27833096b84766ba1a9c1fb5f0342622a84..d70b5a8c4e13af3e93a90c00e65c03b0a00b49e1 100644 (file)
@@ -8,7 +8,7 @@
 const bad_two : u32 = {
     {
         invalid();
-        //~^ ERROR: calls in constants are limited to constant functions, tuple structs and tuple variants
+        //~^ ERROR: cannot call non-const fn `invalid`
         0
     }
 };
@@ -30,7 +30,7 @@
 static bad_five : u32 = {
     {
         invalid();
-        //~^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
+        //~^ ERROR: cannot call non-const fn `invalid`
         0
     }
 };
@@ -52,7 +52,7 @@
 static mut bad_eight : u32 = {
     {
         invalid();
-        //~^ ERROR: calls in statics are limited to constant functions, tuple structs and tuple variants
+        //~^ ERROR: cannot call non-const fn `invalid`
         0
     }
 };
index 1d265875c5c97828ac47d84a5c38aeb6f7d4de70..b94bdc0e3df1181f6499be8f5dc9f0c52861d3a8 100644 (file)
@@ -1,20 +1,26 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `invalid` in constants
   --> $DIR/issue-32829-2.rs:10:9
    |
 LL |         invalid();
    |         ^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `invalid` in statics
   --> $DIR/issue-32829-2.rs:32:9
    |
 LL |         invalid();
    |         ^^^^^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `invalid` in statics
   --> $DIR/issue-32829-2.rs:54:9
    |
 LL |         invalid();
    |         ^^^^^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 3 previous errors
 
index cc6a485085372eb849052549a58c519d94fee30e..cac12b90970fe78b3f1ad19a1cb46c34f061ab00 100644 (file)
@@ -1,7 +1,7 @@
 fn xyz() -> u8 { 42 }
 
 const NUM: u8 = xyz();
-//~^ ERROR calls in constants are limited to constant functions, tuple structs and tuple variants
+//~^ ERROR cannot call non-const fn
 
 fn main() {
     match 1 {
index e508cbdd1dd53e3fbd64e86bdba6b9bc436a5193..2d1174af71c86218ccdbb0020539c0a29bfe9ed4 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `xyz` in constants
   --> $DIR/issue-43105.rs:3:17
    |
 LL | const NUM: u8 = xyz();
    |                 ^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: could not evaluate constant pattern
   --> $DIR/issue-43105.rs:8:9
index 90ea217698d6572f8040208d9f238c2e2d90d0d0..9c673d20b2a9565549532cd4ac1df0d0cab8cfba 100644 (file)
@@ -1,7 +1,7 @@
 #![feature(const_fn_fn_ptr_basics)]
 
 const fn foo() { (||{})() }
-//~^ ERROR calls in constant functions
+//~^ ERROR cannot call non-const closure
 
 const fn bad(input: fn()) {
     input()
index 500af0a40069a2e0171a180e336e0e0442cdab29..62a7c7db6b83ae0311894706e2ec70bcb2f69f3a 100644 (file)
@@ -1,8 +1,11 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/issue-56164.rs:3:18
    |
 LL | const fn foo() { (||{})() }
    |                  ^^^^^^^^
+   |
+   = note: closures need an RFC before allowed to be called in constant functions
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: function pointers are not allowed in const fn
   --> $DIR/issue-56164.rs:7:5
index d77fd9aa831bee8973e35b7a2be7073299421150..37958e7919d64890ddfd2df5d5c9e1ec8949d513 100644 (file)
@@ -3,7 +3,7 @@
 // in the length part of an array.
 
 struct Bug {
-    a: [(); (|| { 0 })()] //~ ERROR calls in constants are limited to
+    a: [(); (|| { 0 })()] //~ ERROR cannot call non-const closure
 }
 
 fn main() {}
index 74d70e18a24cb57d57369575c12b6e2eba359d67..74fbbc680f7e413ad6f6a07fdc759260e554e253 100644 (file)
@@ -1,8 +1,11 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const closure in constants
   --> $DIR/issue-68542-closure-in-array-len.rs:6:13
    |
 LL |     a: [(); (|| { 0 })()]
    |             ^^^^^^^^^^^^
+   |
+   = note: closures need an RFC before allowed to be called in constants
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
index 066764bc46fc4ca158168c9006c4cac16d495b8f..b85e612992549fdd3f78eded1cb9fc4dca92b83d 100644 (file)
@@ -1,4 +1,4 @@
-const FOO: *const u32 = { //~ ERROR encountered dangling pointer in final constant
+const FOO: *const u32 = {
     let x;
     &x //~ ERROR borrow of possibly-uninitialized variable: `x`
 };
index cf3fe18f802fbafb058a639f771d03fa031c7d31..734266a3453b580d2204657d1677d9635334417d 100644 (file)
@@ -4,15 +4,6 @@ error[E0381]: borrow of possibly-uninitialized variable: `x`
 LL |     &x
    |     ^^ use of possibly-uninitialized `x`
 
-error: encountered dangling pointer in final constant
-  --> $DIR/issue-78655.rs:1:1
-   |
-LL | / const FOO: *const u32 = {
-LL | |     let x;
-LL | |     &x
-LL | | };
-   | |__^
-
 error: could not evaluate constant pattern
   --> $DIR/issue-78655.rs:7:9
    |
@@ -25,6 +16,6 @@ error: could not evaluate constant pattern
 LL |     let FOO = FOO;
    |         ^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0381`.
index e767effcdd06f459d971aa143c0ba0f52d15d96e..0d28e06e53258cc592a104c01be868b0208f1b92 100644 (file)
@@ -6,20 +6,20 @@
 
 const fn f(a: &u8, b: &u8) -> bool {
     *a == *b
-    //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+    //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
 }
 
 const fn g(a: &&&&i64, b: &&&&i64) -> bool {
     ****a == ****b
-    //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+    //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
 }
 
 const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
     while let ([l, at @ ..], [r, bt @ ..]) = (a, b) {
         if *l == *r {
-        //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+        //~^ ERROR: cannot call non-const operator in constant functions [E0015]
         //~| HELP: consider dereferencing here
             a = at;
             b = bt;
index 35b3c8242aa0c7ff5011b93b07946b5094dee049..c6bfffd2c5c1567d17da4213ffbe59143140882f 100644 (file)
@@ -6,20 +6,20 @@
 
 const fn f(a: &u8, b: &u8) -> bool {
     a == b
-    //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+    //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
 }
 
 const fn g(a: &&&&i64, b: &&&&i64) -> bool {
     a == b
-    //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+    //~^ ERROR: cannot call non-const operator in constant functions [E0015]
     //~| HELP: consider dereferencing here
 }
 
 const fn h(mut a: &[u8], mut b: &[u8]) -> bool {
     while let ([l, at @ ..], [r, bt @ ..]) = (a, b) {
         if l == r {
-        //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants [E0015]
+        //~^ ERROR: cannot call non-const operator in constant functions [E0015]
         //~| HELP: consider dereferencing here
             a = at;
             b = bt;
index 0e33e6ebe5a5963adfccd3322ad6847ad4e89431..478445cfb39c5f9c356ee5297636e005210ff5aa 100644 (file)
@@ -1,31 +1,34 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const operator in constant functions
   --> $DIR/issue-90870.rs:8:5
    |
 LL |     a == b
    |     ^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 help: consider dereferencing here
    |
 LL |     *a == *b
    |     +     +
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const operator in constant functions
   --> $DIR/issue-90870.rs:14:5
    |
 LL |     a == b
    |     ^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 help: consider dereferencing here
    |
 LL |     ****a == ****b
    |     ++++     ++++
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const operator in constant functions
   --> $DIR/issue-90870.rs:21:12
    |
 LL |         if l == r {
    |            ^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 help: consider dereferencing here
    |
 LL |         if *l == *r {
diff --git a/src/test/ui/consts/issue-91560.fixed b/src/test/ui/consts/issue-91560.fixed
new file mode 100644 (file)
index 0000000..41b9d95
--- /dev/null
@@ -0,0 +1,21 @@
+// Regression test for issue #91560.
+
+// run-rustfix
+
+#![allow(unused,non_upper_case_globals)]
+
+fn foo() {
+    const length: usize = 2;
+    //~^ HELP: consider using `const`
+    let arr = [0; length];
+    //~^ ERROR: attempt to use a non-constant value in a constant [E0435]
+}
+
+fn bar() {
+    const length: usize = 2;
+    //~^ HELP: consider using `const`
+    let arr = [0; length];
+    //~^ ERROR: attempt to use a non-constant value in a constant [E0435]
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-91560.rs b/src/test/ui/consts/issue-91560.rs
new file mode 100644 (file)
index 0000000..04592fe
--- /dev/null
@@ -0,0 +1,21 @@
+// Regression test for issue #91560.
+
+// run-rustfix
+
+#![allow(unused,non_upper_case_globals)]
+
+fn foo() {
+    let mut length: usize = 2;
+    //~^ HELP: consider using `const`
+    let arr = [0; length];
+    //~^ ERROR: attempt to use a non-constant value in a constant [E0435]
+}
+
+fn bar() {
+    let   length: usize = 2;
+    //~^ HELP: consider using `const`
+    let arr = [0; length];
+    //~^ ERROR: attempt to use a non-constant value in a constant [E0435]
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/issue-91560.stderr b/src/test/ui/consts/issue-91560.stderr
new file mode 100644 (file)
index 0000000..e1b5d4c
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/issue-91560.rs:10:19
+   |
+LL |     let mut length: usize = 2;
+   |     -------------- help: consider using `const` instead of `let`: `const length`
+LL |
+LL |     let arr = [0; length];
+   |                   ^^^^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/issue-91560.rs:17:19
+   |
+LL |     let   length: usize = 2;
+   |     ------------ help: consider using `const` instead of `let`: `const length`
+LL |
+LL |     let arr = [0; length];
+   |                   ^^^^^^ non-constant value
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0435`.
index 4e1b7bf119c6d4b0398323a45de08b7a7672c2c7..258997597ea9d91f8228ac5c61bbaf4e6bbb233e 100644 (file)
@@ -1,7 +1,7 @@
 const fn foo(a: i32) -> Vec<i32> {
     vec![1, 2, 3]
     //~^ ERROR allocations are not allowed
-    //~| ERROR calls in constant functions
+    //~| ERROR cannot call non-const fn
 }
 
 fn main() {}
index fee43864e20dcf9d12d30acc9248bffc523b257d..74234108911dd198d40880018decf6baddbc0384 100644 (file)
@@ -6,12 +6,13 @@ LL |     vec![1, 2, 3]
    |
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `slice::<impl [i32]>::into_vec::<std::alloc::Global>` in constant functions
   --> $DIR/bad_const_fn_body_ice.rs:2:5
    |
 LL |     vec![1, 2, 3]
    |     ^^^^^^^^^^^^^
    |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
index fd1ab6f64bf56fe3f05a729de7f7c995b18c1be7..67cb604b6a7be0344258766ec7b3bd21478ab4d8 100644 (file)
@@ -136,7 +136,7 @@ error[E0658]: trait bounds other than `Sized` on const fn parameters are unstabl
 LL | const fn foo11<T: std::fmt::Display>(t: T) -> T { t }
    |                ^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
@@ -145,7 +145,7 @@ error[E0658]: trait bounds other than `Sized` on const fn parameters are unstabl
 LL | const fn foo11_2<T: Send>(t: T) -> T { t }
    |                  ^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0013]: constant functions cannot refer to statics
@@ -218,7 +218,7 @@ LL |
 LL |     const fn foo(&self) {}
    |     ------------------- function declared as const here
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
@@ -230,7 +230,7 @@ LL |
 LL |     const fn foo2(&self) {}
    |     -------------------- function declared as const here
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
@@ -242,7 +242,7 @@ LL |
 LL |     const fn foo3(&self) {}
    |     -------------------- function declared as const here
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable
@@ -251,7 +251,7 @@ error[E0658]: trait bounds other than `Sized` on const fn parameters are unstabl
 LL | const fn no_apit2(_x: AlanTuring<impl std::fmt::Debug>) {}
    |                                  ^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0493]: destructors cannot be evaluated at compile-time
@@ -268,7 +268,7 @@ error[E0658]: trait bounds other than `Sized` on const fn parameters are unstabl
 LL | const fn no_apit(_x: impl std::fmt::Debug) {}
    |                      ^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0493]: destructors cannot be evaluated at compile-time
@@ -285,7 +285,7 @@ error[E0658]: trait objects in const fn are unstable
 LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {}
    |                       ^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: trait objects in const fn are unstable
@@ -294,7 +294,7 @@ error[E0658]: trait objects in const fn are unstable
 LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: trait objects in const fn are unstable
@@ -305,7 +305,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1
    | |
    | function declared as const here
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: trait objects in const fn are unstable
@@ -316,7 +316,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1
    | |
    | function declared as const here
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: trait objects in const fn are unstable
@@ -327,7 +327,7 @@ LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1
    | |
    | function declared as const here
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: function pointers cannot appear in constant functions
index 6eec1df5aeca7ba9fb942827b42f7078ff287237..4c2199101d302318385feb16278201b7722667a8 100644 (file)
@@ -6,7 +6,7 @@ LL | const fn no_inner_dyn_trait2(x: Hide) {
 LL |     x.0.field;
    |     ^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error[E0658]: trait objects in const fn are unstable
@@ -17,7 +17,7 @@ LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) }
    | |
    | function declared as const here
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
index b8ec0c3c449ff6785be64498a97cbc74d595f56d..b6f34b922fae51548a3956459853637246e7a67a 100644 (file)
@@ -6,6 +6,6 @@ fn bar() -> Foo {
 }
 
 static foo: Foo = bar();
-//~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants
+//~^ ERROR cannot call non-const fn
 
 fn main() {}
index 30f68ba43722d92553e4d8bdb25a36e08b0eb0d2..2bac995eebf090244cd229eb05479cabb795eec3 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `bar` in statics
   --> $DIR/mir_check_nonconst.rs:8:19
    |
 LL | static foo: Foo = bar();
    |                   ^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/recursive.rs b/src/test/ui/consts/recursive.rs
new file mode 100644 (file)
index 0000000..664940c
--- /dev/null
@@ -0,0 +1,11 @@
+#![allow(unused)]
+
+const fn f<T>(x: T) { //~ WARN function cannot return without recursing
+    f(x);
+    //~^ ERROR any use of this value will cause an error
+    //~| WARN this was previously accepted by the compiler
+}
+
+const X: () = f(1);
+
+fn main() {}
diff --git a/src/test/ui/consts/recursive.stderr b/src/test/ui/consts/recursive.stderr
new file mode 100644 (file)
index 0000000..31ac1ff
--- /dev/null
@@ -0,0 +1,31 @@
+warning: function cannot return without recursing
+  --> $DIR/recursive.rs:3:1
+   |
+LL | const fn f<T>(x: T) {
+   | ^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |     f(x);
+   |     ---- recursive call site
+   |
+   = note: `#[warn(unconditional_recursion)]` on by default
+   = help: a `loop` may express intention better if this is on purpose
+
+error: any use of this value will cause an error
+  --> $DIR/recursive.rs:4:5
+   |
+LL |     f(x);
+   |     ^^^^
+   |     |
+   |     reached the configured maximum number of stack frames
+   |     inside `f::<i32>` at $DIR/recursive.rs:4:5
+   |     [... 126 additional calls inside `f::<i32>` at $DIR/recursive.rs:4:5 ...]
+   |     inside `X` at $DIR/recursive.rs:9:15
+...
+LL | const X: () = f(1);
+   | -------------------
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: aborting due to previous error; 1 warning emitted
+
index 928605356a16e3d94f07d1215c509599b1ece247..4ef25bd1334f3b30a85d5a086f270d0435a9acf7 100644 (file)
@@ -1,8 +1,14 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const closure in constant functions
   --> $DIR/unstable-const-fn-in-libcore.rs:24:26
    |
 LL |             Opt::None => f(),
    |                          ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL |     const fn unwrap_or_else<F: FnOnce() -> T + ~const std::ops::FnOnce<()>>(self, f: F) -> T {
+   |                                              +++++++++++++++++++++++++++++
 
 error[E0493]: destructors cannot be evaluated at compile-time
   --> $DIR/unstable-const-fn-in-libcore.rs:19:53
diff --git a/src/test/ui/derives/issue-91550.rs b/src/test/ui/derives/issue-91550.rs
new file mode 100644 (file)
index 0000000..56fd5ff
--- /dev/null
@@ -0,0 +1,29 @@
+use std::collections::HashSet;
+
+/// natural case from the issue
+struct Value(u32);
+
+fn main() {
+    let hs = HashSet::<Value>::new();
+    hs.insert(Value(0)); //~ ERROR
+}
+
+/// synthetic cases
+pub struct NoDerives;
+
+struct Object<T>(T);
+impl<T: Eq> Object<T> {
+    fn use_eq(&self) {}
+}
+impl<T: Ord> Object<T> {
+    fn use_ord(&self) {}
+}
+impl<T: Ord + PartialOrd> Object<T> {
+    fn use_ord_and_partial_ord(&self) {}
+}
+
+fn function(foo: Object<NoDerives>) {
+    foo.use_eq(); //~ ERROR
+    foo.use_ord(); //~ ERROR
+    foo.use_ord_and_partial_ord(); //~ ERROR
+}
diff --git a/src/test/ui/derives/issue-91550.stderr b/src/test/ui/derives/issue-91550.stderr
new file mode 100644 (file)
index 0000000..bf4b7c7
--- /dev/null
@@ -0,0 +1,84 @@
+error[E0599]: the method `insert` exists for struct `HashSet<Value>`, but its trait bounds were not satisfied
+  --> $DIR/issue-91550.rs:8:8
+   |
+LL | struct Value(u32);
+   | ------------------
+   | |
+   | doesn't satisfy `Value: Eq`
+   | doesn't satisfy `Value: Hash`
+...
+LL |     hs.insert(Value(0));
+   |        ^^^^^^ method cannot be called on `HashSet<Value>` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `Value: Eq`
+           `Value: Hash`
+help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]`
+   |
+LL | #[derive(Eq, Hash, PartialEq)]
+   |
+
+error[E0599]: the method `use_eq` exists for struct `Object<NoDerives>`, but its trait bounds were not satisfied
+  --> $DIR/issue-91550.rs:26:9
+   |
+LL | pub struct NoDerives;
+   | --------------------- doesn't satisfy `NoDerives: Eq`
+LL | 
+LL | struct Object<T>(T);
+   | -------------------- method `use_eq` not found for this
+...
+LL |     foo.use_eq();
+   |         ^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `NoDerives: Eq`
+help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]`
+   |
+LL | #[derive(Eq, PartialEq)]
+   |
+
+error[E0599]: the method `use_ord` exists for struct `Object<NoDerives>`, but its trait bounds were not satisfied
+  --> $DIR/issue-91550.rs:27:9
+   |
+LL | pub struct NoDerives;
+   | --------------------- doesn't satisfy `NoDerives: Ord`
+LL | 
+LL | struct Object<T>(T);
+   | -------------------- method `use_ord` not found for this
+...
+LL |     foo.use_ord();
+   |         ^^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `NoDerives: Ord`
+help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
+   |
+LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
+   |
+
+error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object<NoDerives>`, but its trait bounds were not satisfied
+  --> $DIR/issue-91550.rs:28:9
+   |
+LL | pub struct NoDerives;
+   | ---------------------
+   | |
+   | doesn't satisfy `NoDerives: Ord`
+   | doesn't satisfy `NoDerives: PartialOrd`
+LL | 
+LL | struct Object<T>(T);
+   | -------------------- method `use_ord_and_partial_ord` not found for this
+...
+LL |     foo.use_ord_and_partial_ord();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `Object<NoDerives>` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `NoDerives: Ord`
+           `NoDerives: PartialOrd`
+help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]`
+   |
+LL | #[derive(Eq, Ord, PartialEq, PartialOrd)]
+   |
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
index 13735ff2c5a1c57a2e1679f4432e26daec8520bf..4b1cbe80c506dabfa6c7432f7d4def8caac36f69 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-compare-mode-chalk
 pub trait DeclaredTrait {
     type Type;
 }
index 5381a717dc3cfd2312b14e3c2b0fecb6f88c48ae..dff980301911cc11fd94923bd4146720d7409880 100644 (file)
@@ -11,7 +11,7 @@ LL |     Foo::<i32>::bar(&1i8);
              <i8 as Foo<u16>>
              <i8 as Foo<u32>>
              <i8 as Foo<u64>>
-             <i8 as Foo<u8>>
+           and 5 others
 
 error[E0277]: the trait bound `u8: Foo<i32>` is not satisfied
   --> $DIR/issue-39802-show-5-trait-impls.rs:25:21
@@ -26,6 +26,7 @@ LL |     Foo::<i32>::bar(&1u8);
              <u8 as Foo<u16>>
              <u8 as Foo<u32>>
              <u8 as Foo<u64>>
+           and 5 others
 
 error[E0277]: the trait bound `bool: Foo<i32>` is not satisfied
   --> $DIR/issue-39802-show-5-trait-impls.rs:26:21
index 18835310bd5e87ec6541fa49df36540a60be1c64..d715d28b73c01a36c432262527b6ad5ae9e7a05a 100644 (file)
@@ -3,6 +3,12 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
    |
 LL |     1u32 as char;
    |     ^^^^^^^^^^^^ invalid cast
+   |
+help: try `char::from_u32` instead
+  --> $DIR/E0604.rs:2:5
+   |
+LL |     1u32 as char;
+   |     ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index b8cd7b7464ae3662b1214df44c28d67ccd6923a4..0ddb6fc99b004d4459e24dfd28c715ed69937ca6 100644 (file)
@@ -58,6 +58,12 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
    |
 LL |     0u32 as char;
    |     ^^^^^^^^^^^^ invalid cast
+   |
+help: try `char::from_u32` instead
+  --> $DIR/error-festival.rs:25:5
+   |
+LL |     0u32 as char;
+   |     ^^^^^^^^^^^^
 
 error[E0605]: non-primitive cast: `u8` as `Vec<u8>`
   --> $DIR/error-festival.rs:29:5
diff --git a/src/test/ui/feature-gates/feature-gate-allow_fail.rs b/src/test/ui/feature-gates/feature-gate-allow_fail.rs
deleted file mode 100644 (file)
index 287d4cc..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// check that #[allow_fail] is feature-gated
-
-#[allow_fail] //~ ERROR the `#[allow_fail]` attribute is an experimental feature
-fn ok_to_fail() {
-    assert!(false);
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-allow_fail.stderr b/src/test/ui/feature-gates/feature-gate-allow_fail.stderr
deleted file mode 100644 (file)
index 76115fb..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: the `#[allow_fail]` attribute is an experimental feature
-  --> $DIR/feature-gate-allow_fail.rs:3:1
-   |
-LL | #[allow_fail]
-   | ^^^^^^^^^^^^^
-   |
-   = note: see issue #46488 <https://github.com/rust-lang/rust/issues/46488> for more information
-   = help: add `#![feature(allow_fail)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
index 2851a9b0ae6a4cc8573d140610c632b3a79a2643..0202ccbe5a2d232339977f87fb5ea352c66d8d1d 100644 (file)
@@ -4,7 +4,7 @@ error[E0658]: const operands for inline assembly are unstable
 LL |         asm!("mov eax, {}", const 123);
    |                             ^^^^^^^^^
    |
-   = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+   = note: see issue #93332 <https://github.com/rust-lang/rust/issues/93332> for more information
    = help: add `#![feature(asm_const)]` to the crate attributes to enable
 
 error: aborting due to previous error
index 1b4188ae1adb868c5f8114b110e69c622d913c68..4a859430e044d988de37753e72d126173b5db2ed 100644 (file)
@@ -4,7 +4,7 @@ error[E0658]: inline assembly is not stable yet on this architecture
 LL |     asm!("");
    |     ^^^^^^^^
    |
-   = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+   = note: see issue #93335 <https://github.com/rust-lang/rust/issues/93335> for more information
    = help: add `#![feature(asm_experimental_arch)]` to the crate attributes to enable
 
 error: aborting due to previous error
index 99b61b829fbc846d13e7f2ef798c2a037a97d7e9..68f2d0f6c18b0bb6e78594abfa27e46b4b909db4 100644 (file)
@@ -4,7 +4,7 @@ error[E0658]: sym operands for inline assembly are unstable
 LL |         asm!("mov eax, {}", sym main);
    |                             ^^^^^^^^
    |
-   = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+   = note: see issue #93333 <https://github.com/rust-lang/rust/issues/93333> for more information
    = help: add `#![feature(asm_sym)]` to the crate attributes to enable
 
 error: aborting due to previous error
index 6b5bf286e7bca2ff8eb7f01efa1c84826b2e7a39..05e66acb556ada58da467b685bf863c7a7c30acc 100644 (file)
@@ -4,7 +4,7 @@ error[E0658]: the `may_unwind` option is unstable
 LL |         asm!("", options(may_unwind));
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #72016 <https://github.com/rust-lang/rust/issues/72016> for more information
+   = note: see issue #93334 <https://github.com/rust-lang/rust/issues/93334> for more information
    = help: add `#![feature(asm_unwind)]` to the crate attributes to enable
 
 error: aborting due to previous error
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic-equal-alignment.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic-equal-alignment.rs
new file mode 100644 (file)
index 0000000..3d692a0
--- /dev/null
@@ -0,0 +1,14 @@
+fn main() {
+    cfg!(target_has_atomic_equal_alignment = "8");
+    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+    cfg!(target_has_atomic_equal_alignment = "16");
+    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+    cfg!(target_has_atomic_equal_alignment = "32");
+    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+    cfg!(target_has_atomic_equal_alignment = "64");
+    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+    cfg!(target_has_atomic_equal_alignment = "128");
+    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+    cfg!(target_has_atomic_equal_alignment = "ptr");
+    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+}
diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic-equal-alignment.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic-equal-alignment.stderr
new file mode 100644 (file)
index 0000000..8ad3b03
--- /dev/null
@@ -0,0 +1,57 @@
+error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-target-has-atomic-equal-alignment.rs:2:10
+   |
+LL |     cfg!(target_has_atomic_equal_alignment = "8");
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #93822 <https://github.com/rust-lang/rust/issues/93822> for more information
+   = help: add `#![feature(cfg_target_has_atomic_equal_alignment)]` to the crate attributes to enable
+
+error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-target-has-atomic-equal-alignment.rs:4:10
+   |
+LL |     cfg!(target_has_atomic_equal_alignment = "16");
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #93822 <https://github.com/rust-lang/rust/issues/93822> for more information
+   = help: add `#![feature(cfg_target_has_atomic_equal_alignment)]` to the crate attributes to enable
+
+error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-target-has-atomic-equal-alignment.rs:6:10
+   |
+LL |     cfg!(target_has_atomic_equal_alignment = "32");
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #93822 <https://github.com/rust-lang/rust/issues/93822> for more information
+   = help: add `#![feature(cfg_target_has_atomic_equal_alignment)]` to the crate attributes to enable
+
+error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-target-has-atomic-equal-alignment.rs:8:10
+   |
+LL |     cfg!(target_has_atomic_equal_alignment = "64");
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #93822 <https://github.com/rust-lang/rust/issues/93822> for more information
+   = help: add `#![feature(cfg_target_has_atomic_equal_alignment)]` to the crate attributes to enable
+
+error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-target-has-atomic-equal-alignment.rs:10:10
+   |
+LL |     cfg!(target_has_atomic_equal_alignment = "128");
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #93822 <https://github.com/rust-lang/rust/issues/93822> for more information
+   = help: add `#![feature(cfg_target_has_atomic_equal_alignment)]` to the crate attributes to enable
+
+error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-target-has-atomic-equal-alignment.rs:12:10
+   |
+LL |     cfg!(target_has_atomic_equal_alignment = "ptr");
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #93822 <https://github.com/rust-lang/rust/issues/93822> for more information
+   = help: add `#![feature(cfg_target_has_atomic_equal_alignment)]` to the crate attributes to enable
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
index 049fdd84d8c22e71a8dae4a329b97cfbe60f74fe..df9c51cb176bc90ee53a0570bd6dfd5bc407aef1 100644 (file)
@@ -1,92 +1,4 @@
-#![feature(intrinsics, lang_items, no_core, rustc_attrs)]
-
-#![crate_type="rlib"]
-#![no_core]
-
-extern "rust-intrinsic" {
-    fn atomic_xadd<T>(dst: *mut T, src: T) -> T;
-}
-
-#[lang = "sized"]
-trait Sized {}
-#[lang = "copy"]
-trait Copy {}
-
-#[cfg(target_has_atomic = "8")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_u8(x: *mut u8) {
-    atomic_xadd(x, 1);
-    atomic_xadd(x, 1);
-}
-#[cfg(target_has_atomic = "8")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_i8(x: *mut i8) {
-    atomic_xadd(x, 1);
-}
-#[cfg(target_has_atomic = "16")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_u16(x: *mut u16) {
-    atomic_xadd(x, 1);
-}
-#[cfg(target_has_atomic = "16")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_i16(x: *mut i16) {
-    atomic_xadd(x, 1);
-}
-#[cfg(target_has_atomic = "32")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_u32(x: *mut u32) {
-    atomic_xadd(x, 1);
-}
-#[cfg(target_has_atomic = "32")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_i32(x: *mut i32) {
-    atomic_xadd(x, 1);
-}
-#[cfg(target_has_atomic = "64")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_u64(x: *mut u64) {
-    atomic_xadd(x, 1);
-}
-#[cfg(target_has_atomic = "64")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_i64(x: *mut i64) {
-    atomic_xadd(x, 1);
-}
-#[cfg(target_has_atomic = "128")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_u128(x: *mut u128) {
-    atomic_xadd(x, 1);
-}
-#[cfg(target_has_atomic = "128")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_i128(x: *mut i128) {
-    atomic_xadd(x, 1);
-}
-#[cfg(target_has_atomic = "ptr")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_usize(x: *mut usize) {
-    atomic_xadd(x, 1);
-}
-#[cfg(target_has_atomic = "ptr")]
-//~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-pub unsafe fn atomic_isize(x: *mut isize) {
-    atomic_xadd(x, 1);
-}
-
 fn main() {
-    cfg!(target_has_atomic = "8");
-    //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-    cfg!(target_has_atomic = "16");
-    //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-    cfg!(target_has_atomic = "32");
-    //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-    cfg!(target_has_atomic = "64");
-    //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-    cfg!(target_has_atomic = "128");
-    //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
-    cfg!(target_has_atomic = "ptr");
-    //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change
     cfg!(target_has_atomic_load_store = "8");
     //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change
     cfg!(target_has_atomic_load_store = "16");
@@ -99,20 +11,4 @@ fn main() {
     //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change
     cfg!(target_has_atomic_load_store = "ptr");
     //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change
-    cfg!(target_has_atomic_equal_alignment = "8");
-    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
-    cfg!(target_has_atomic_equal_alignment = "16");
-    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
-    cfg!(target_has_atomic_equal_alignment = "32");
-    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
-    cfg!(target_has_atomic_equal_alignment = "64");
-    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
-    cfg!(target_has_atomic_equal_alignment = "128");
-    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
-    cfg!(target_has_atomic_equal_alignment = "ptr");
-    //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
 }
-
-#[macro_export]
-#[rustc_builtin_macro]
-macro_rules! cfg { () => () }
index 16e1dc644008433ca55be33c2449b5fed9309028..b9e6830a9f0f89d32a5d65e1e7e815c5f9edeead 100644 (file)
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:15:7
-   |
-LL | #[cfg(target_has_atomic = "8")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:21:7
-   |
-LL | #[cfg(target_has_atomic = "8")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:26:7
-   |
-LL | #[cfg(target_has_atomic = "16")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:31:7
-   |
-LL | #[cfg(target_has_atomic = "16")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:36:7
-   |
-LL | #[cfg(target_has_atomic = "32")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:41:7
-   |
-LL | #[cfg(target_has_atomic = "32")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:46:7
-   |
-LL | #[cfg(target_has_atomic = "64")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:51:7
-   |
-LL | #[cfg(target_has_atomic = "64")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:56:7
-   |
-LL | #[cfg(target_has_atomic = "128")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:61:7
-   |
-LL | #[cfg(target_has_atomic = "128")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:66:7
-   |
-LL | #[cfg(target_has_atomic = "ptr")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:71:7
-   |
-LL | #[cfg(target_has_atomic = "ptr")]
-   |       ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:78:10
-   |
-LL |     cfg!(target_has_atomic = "8");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:80:10
-   |
-LL |     cfg!(target_has_atomic = "16");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:82:10
-   |
-LL |     cfg!(target_has_atomic = "32");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:84:10
-   |
-LL |     cfg!(target_has_atomic = "64");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:86:10
-   |
-LL |     cfg!(target_has_atomic = "128");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:88:10
-   |
-LL |     cfg!(target_has_atomic = "ptr");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
 error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:90:10
+  --> $DIR/feature-gate-cfg-target-has-atomic.rs:2:10
    |
 LL |     cfg!(target_has_atomic_load_store = "8");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
+   = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information
    = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
 
 error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:92:10
+  --> $DIR/feature-gate-cfg-target-has-atomic.rs:4:10
    |
 LL |     cfg!(target_has_atomic_load_store = "16");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
+   = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information
    = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
 
 error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:94:10
+  --> $DIR/feature-gate-cfg-target-has-atomic.rs:6:10
    |
 LL |     cfg!(target_has_atomic_load_store = "32");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
+   = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information
    = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
 
 error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:96:10
+  --> $DIR/feature-gate-cfg-target-has-atomic.rs:8:10
    |
 LL |     cfg!(target_has_atomic_load_store = "64");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
+   = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information
    = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
 
 error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:98:10
+  --> $DIR/feature-gate-cfg-target-has-atomic.rs:10:10
    |
 LL |     cfg!(target_has_atomic_load_store = "128");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
+   = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information
    = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
 
 error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:100:10
+  --> $DIR/feature-gate-cfg-target-has-atomic.rs:12:10
    |
 LL |     cfg!(target_has_atomic_load_store = "ptr");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:102:10
-   |
-LL |     cfg!(target_has_atomic_equal_alignment = "8");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:104:10
-   |
-LL |     cfg!(target_has_atomic_equal_alignment = "16");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:106:10
-   |
-LL |     cfg!(target_has_atomic_equal_alignment = "32");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:108:10
-   |
-LL |     cfg!(target_has_atomic_equal_alignment = "64");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:110:10
-   |
-LL |     cfg!(target_has_atomic_equal_alignment = "128");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
-   = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
-
-error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-has-atomic.rs:112:10
-   |
-LL |     cfg!(target_has_atomic_equal_alignment = "ptr");
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #32976 <https://github.com/rust-lang/rust/issues/32976> for more information
+   = note: see issue #94039 <https://github.com/rust-lang/rust/issues/94039> for more information
    = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable
 
-error: aborting due to 30 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_pin_internals.rs b/src/test/ui/feature-gates/feature-gate-unsafe_pin_internals.rs
new file mode 100644 (file)
index 0000000..0680d23
--- /dev/null
@@ -0,0 +1,17 @@
+// edition:2018
+#![forbid(incomplete_features, unsafe_code)]
+#![feature(unsafe_pin_internals)]
+//~^ ERROR the feature `unsafe_pin_internals` is incomplete and may not be safe to use
+
+use core::{marker::PhantomPinned, pin::Pin};
+
+/// The `unsafe_pin_internals` is indeed unsound.
+fn non_unsafe_pin_new_unchecked<T>(pointer: &mut T) -> Pin<&mut T> {
+    Pin { pointer }
+}
+
+fn main() {
+    let mut self_referential = PhantomPinned;
+    let _: Pin<&mut PhantomPinned> = non_unsafe_pin_new_unchecked(&mut self_referential);
+    core::mem::forget(self_referential); // move and disable drop glue!
+}
diff --git a/src/test/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr b/src/test/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr
new file mode 100644 (file)
index 0000000..4d0c931
--- /dev/null
@@ -0,0 +1,14 @@
+error: the feature `unsafe_pin_internals` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/feature-gate-unsafe_pin_internals.rs:3:12
+   |
+LL | #![feature(unsafe_pin_internals)]
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/feature-gate-unsafe_pin_internals.rs:2:11
+   |
+LL | #![forbid(incomplete_features, unsafe_code)]
+   |           ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
index f5f9631c3bcf9af99af2a4cdf279cb1b9ce8dbef..af8d8e92b20bdca8d3292a55f7f34104f18133c2 100644 (file)
@@ -13,7 +13,7 @@ union U22<T> { // OK
 }
 
 union U3 {
-    a: String, //~ ERROR unions may not contain fields that need dropping
+    a: String, //~ ERROR unions cannot contain fields that may need dropping
 }
 
 union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test!
@@ -21,7 +21,7 @@ union U32 { // field that does not drop but is not `Copy`, either -- this is the
 }
 
 union U4<T> {
-    a: T, //~ ERROR unions may not contain fields that need dropping
+    a: T, //~ ERROR unions cannot contain fields that may need dropping
 }
 
 union U5 { // Having a drop impl is OK
index 0967cb7ba8bd28496eb354928e22222250af39a2..9e4a89f80c852976fa3c6d9c2736c24574e160ab 100644 (file)
@@ -7,24 +7,26 @@ LL |     a: std::cell::RefCell<i32>,
    = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
    = help: add `#![feature(untagged_unions)]` to the crate attributes to enable
 
-error[E0740]: unions may not contain fields that need dropping
+error[E0740]: unions cannot contain fields that may need dropping
   --> $DIR/feature-gate-untagged_unions.rs:16:5
    |
 LL |     a: String,
    |     ^^^^^^^^^
    |
-help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
    |
 LL |     a: std::mem::ManuallyDrop<String>,
    |        +++++++++++++++++++++++      +
 
-error[E0740]: unions may not contain fields that need dropping
+error[E0740]: unions cannot contain fields that may need dropping
   --> $DIR/feature-gate-untagged_unions.rs:24:5
    |
 LL |     a: T,
    |     ^^^^
    |
-help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
    |
 LL |     a: std::mem::ManuallyDrop<T>,
    |        +++++++++++++++++++++++ +
diff --git a/src/test/ui/feature-gates/feature-gate-used_with_arg.rs b/src/test/ui/feature-gates/feature-gate-used_with_arg.rs
new file mode 100644 (file)
index 0000000..1c8f01b
--- /dev/null
@@ -0,0 +1,7 @@
+#[used(linker)] //~ ERROR `#[used(linker)]` is currently unstable
+static mut USED_LINKER: [usize; 1] = [0];
+
+#[used(compiler)] //~ ERROR `#[used(compiler)]` is currently unstable
+static mut USED_COMPILER: [usize; 1] = [0];
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-used_with_arg.stderr b/src/test/ui/feature-gates/feature-gate-used_with_arg.stderr
new file mode 100644 (file)
index 0000000..d115bf4
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0658]: `#[used(linker)]` is currently unstable
+  --> $DIR/feature-gate-used_with_arg.rs:1:1
+   |
+LL | #[used(linker)]
+   | ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #93798 <https://github.com/rust-lang/rust/issues/93798> for more information
+   = help: add `#![feature(used_with_arg)]` to the crate attributes to enable
+
+error[E0658]: `#[used(compiler)]` is currently unstable
+  --> $DIR/feature-gate-used_with_arg.rs:4:1
+   |
+LL | #[used(compiler)]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #93798 <https://github.com/rust-lang/rust/issues/93798> for more information
+   = help: add `#![feature(used_with_arg)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/fmt/format-args-capture-issue-93378.rs b/src/test/ui/fmt/format-args-capture-issue-93378.rs
new file mode 100644 (file)
index 0000000..6744444
--- /dev/null
@@ -0,0 +1,11 @@
+fn main() {
+    let a = "a";
+    let b = "b";
+
+    println!("{a} {b} {} {} {c} {}", c = "c");
+    //~^ ERROR: invalid reference to positional arguments 1 and 2 (there is 1 argument)
+
+    let n = 1;
+    println!("{a:.n$} {b:.*}");
+    //~^ ERROR: invalid reference to positional argument 0 (no arguments were given)
+}
diff --git a/src/test/ui/fmt/format-args-capture-issue-93378.stderr b/src/test/ui/fmt/format-args-capture-issue-93378.stderr
new file mode 100644 (file)
index 0000000..b8e2b2a
--- /dev/null
@@ -0,0 +1,22 @@
+error: invalid reference to positional arguments 1 and 2 (there is 1 argument)
+  --> $DIR/format-args-capture-issue-93378.rs:5:26
+   |
+LL |     println!("{a} {b} {} {} {c} {}", c = "c");
+   |                          ^^     ^^
+   |
+   = note: positional arguments are zero-based
+
+error: invalid reference to positional argument 0 (no arguments were given)
+  --> $DIR/format-args-capture-issue-93378.rs:9:23
+   |
+LL |     println!("{a:.n$} {b:.*}");
+   |                   -   ^^^--^
+   |                   |      |
+   |                   |      this precision flag adds an extra required argument at position 0, which is why there are 3 arguments expected
+   |                   this parameter corresponds to the precision flag
+   |
+   = note: positional arguments are zero-based
+   = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/fmt/format-args-capture-issue-94010.rs b/src/test/ui/fmt/format-args-capture-issue-94010.rs
new file mode 100644 (file)
index 0000000..bd03e9c
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    const FOO: i32 = 123;
+    println!("{foo:X}");
+    //~^ ERROR: cannot find value `foo` in this scope
+    println!("{:.foo$}", 0);
+    //~^ ERROR: cannot find value `foo` in this scope
+}
diff --git a/src/test/ui/fmt/format-args-capture-issue-94010.stderr b/src/test/ui/fmt/format-args-capture-issue-94010.stderr
new file mode 100644 (file)
index 0000000..ed90dc8
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0425]: cannot find value `foo` in this scope
+  --> $DIR/format-args-capture-issue-94010.rs:3:16
+   |
+LL |     const FOO: i32 = 123;
+   |     --------------------- similarly named constant `FOO` defined here
+LL |     println!("{foo:X}");
+   |                ^^^ help: a constant with a similar name exists (notice the capitalization): `FOO`
+
+error[E0425]: cannot find value `foo` in this scope
+  --> $DIR/format-args-capture-issue-94010.rs:5:18
+   |
+LL |     const FOO: i32 = 123;
+   |     --------------------- similarly named constant `FOO` defined here
+...
+LL |     println!("{:.foo$}", 0);
+   |                  ^^^ help: a constant with a similar name exists (notice the capitalization): `FOO`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
index d53c206003f94391b45bd886c64b94cfd4234775..d980e7be273e8547e6568eb47df192fafd3603c0 100644 (file)
@@ -7,40 +7,40 @@ LL |     format!("{valuea} {valueb}", valuea=5, valuec=7);
    |             formatting specifier missing
 
 error[E0425]: cannot find value `foo` in this scope
-  --> $DIR/format-args-capture-missing-variables.rs:2:17
+  --> $DIR/format-args-capture-missing-variables.rs:2:18
    |
 LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
-   |                 ^^^^^ not found in this scope
+   |                  ^^^ not found in this scope
 
 error[E0425]: cannot find value `bar` in this scope
-  --> $DIR/format-args-capture-missing-variables.rs:2:26
+  --> $DIR/format-args-capture-missing-variables.rs:2:27
    |
 LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
-   |                          ^^^^^ not found in this scope
+   |                           ^^^ not found in this scope
 
 error[E0425]: cannot find value `foo` in this scope
-  --> $DIR/format-args-capture-missing-variables.rs:6:14
+  --> $DIR/format-args-capture-missing-variables.rs:6:15
    |
 LL |     format!("{foo}");
-   |              ^^^^^ not found in this scope
+   |               ^^^ not found in this scope
 
 error[E0425]: cannot find value `valueb` in this scope
-  --> $DIR/format-args-capture-missing-variables.rs:8:23
+  --> $DIR/format-args-capture-missing-variables.rs:8:24
    |
 LL |     format!("{valuea} {valueb}", valuea=5, valuec=7);
-   |                       ^^^^^^^^ not found in this scope
+   |                        ^^^^^^ not found in this scope
 
 error[E0425]: cannot find value `foo` in this scope
-  --> $DIR/format-args-capture-missing-variables.rs:14:9
+  --> $DIR/format-args-capture-missing-variables.rs:14:10
    |
 LL |         {foo}
-   |         ^^^^^ not found in this scope
+   |          ^^^ not found in this scope
 
 error[E0425]: cannot find value `foo` in this scope
-  --> $DIR/format-args-capture-missing-variables.rs:19:13
+  --> $DIR/format-args-capture-missing-variables.rs:19:14
    |
 LL |     panic!("{foo} {bar}", bar=1);
-   |             ^^^^^ not found in this scope
+   |              ^^^ not found in this scope
 
 error: aborting due to 7 previous errors
 
index e830a5bc9c5c86947d40cbb331377b23beb9b233..d31d2a6c33657fff6b4975c399e33784cea5ccb2 100644 (file)
@@ -5,6 +5,7 @@ fn main() {
     named_argument_takes_precedence_to_captured();
     formatting_parameters_can_be_captured();
     capture_raw_strings_and_idents();
+    repeated_capture();
 
     #[cfg(panic = "unwind")]
     {
@@ -80,3 +81,10 @@ fn formatting_parameters_can_be_captured() {
     let s = format!("{x:-^width$.precision$}");
     assert_eq!(&s, "--7.000--");
 }
+
+fn repeated_capture() {
+    let a = 1;
+    let b = 2;
+    let s = format!("{a} {b} {a}");
+    assert_eq!(&s, "1 2 1");
+}
index acc4e95f5bb7ef2d0519b432c6f26225070fceca..3f1f1006713ba46d9ffbdbee1af523e4ddfcb635 100644 (file)
@@ -263,34 +263,34 @@ LL |     println!("{:.*}");
    = note: for information about formatting flags, visit https://doc.rust-lang.org/std/fmt/index.html
 
 error[E0425]: cannot find value `foo` in this scope
-  --> $DIR/ifmt-bad-arg.rs:27:17
+  --> $DIR/ifmt-bad-arg.rs:27:18
    |
 LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
-   |                 ^^^^^ not found in this scope
+   |                  ^^^ not found in this scope
 
 error[E0425]: cannot find value `bar` in this scope
-  --> $DIR/ifmt-bad-arg.rs:27:26
+  --> $DIR/ifmt-bad-arg.rs:27:27
    |
 LL |     format!("{} {foo} {} {bar} {}", 1, 2, 3);
-   |                          ^^^^^ not found in this scope
+   |                           ^^^ not found in this scope
 
 error[E0425]: cannot find value `foo` in this scope
-  --> $DIR/ifmt-bad-arg.rs:31:14
+  --> $DIR/ifmt-bad-arg.rs:31:15
    |
 LL |     format!("{foo}");
-   |              ^^^^^ not found in this scope
+   |               ^^^ not found in this scope
 
 error[E0425]: cannot find value `valueb` in this scope
-  --> $DIR/ifmt-bad-arg.rs:45:23
+  --> $DIR/ifmt-bad-arg.rs:45:24
    |
 LL |     format!("{valuea} {valueb}", valuea=5, valuec=7);
-   |                       ^^^^^^^^ not found in this scope
+   |                        ^^^^^^ not found in this scope
 
 error[E0425]: cannot find value `foo` in this scope
-  --> $DIR/ifmt-bad-arg.rs:60:9
+  --> $DIR/ifmt-bad-arg.rs:60:10
    |
 LL |         {foo}
-   |         ^^^^^ not found in this scope
+   |          ^^^ not found in this scope
 
 error[E0308]: mismatched types
   --> $DIR/ifmt-bad-arg.rs:78:32
diff --git a/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs
new file mode 100644 (file)
index 0000000..26deb59
--- /dev/null
@@ -0,0 +1,22 @@
+struct Struct<T>(T);
+impl Struct<T>
+//~^ ERROR cannot find type `T` in this scope
+//~| NOTE not found in this scope
+//~| HELP you might be missing a type parameter
+where
+    T: Copy,
+    //~^ ERROR cannot find type `T` in this scope
+    //~| NOTE not found in this scope
+{
+    // The part where it claims that there is no method named `len` is a bug. Feel free to fix it.
+    // This test is intended to ensure that a different bug, where it claimed
+    // that `v` was a function, does not regress.
+    fn method(v: Vec<u8>) { v.len(); }
+    //~^ ERROR type annotations needed
+    //~| NOTE cannot infer type
+    //~| NOTE type must be known at this point
+    //~| ERROR no method named `len`
+    //~| NOTE private field, not a method
+}
+
+fn main() {}
diff --git a/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr b/src/test/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr
new file mode 100644 (file)
index 0000000..958ce3c
--- /dev/null
@@ -0,0 +1,32 @@
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/fn-help-with-err-generic-is-not-function.rs:2:13
+   |
+LL | impl Struct<T>
+   |     -       ^ not found in this scope
+   |     |
+   |     help: you might be missing a type parameter: `<T>`
+
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/fn-help-with-err-generic-is-not-function.rs:7:5
+   |
+LL |     T: Copy,
+   |     ^ not found in this scope
+
+error[E0282]: type annotations needed
+  --> $DIR/fn-help-with-err-generic-is-not-function.rs:14:31
+   |
+LL |     fn method(v: Vec<u8>) { v.len(); }
+   |                               ^^^ cannot infer type
+   |
+   = note: type must be known at this point
+
+error[E0599]: no method named `len` found for struct `Vec<u8>` in the current scope
+  --> $DIR/fn-help-with-err-generic-is-not-function.rs:14:31
+   |
+LL |     fn method(v: Vec<u8>) { v.len(); }
+   |                               ^^^ private field, not a method
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0282, E0412, E0599.
+For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/functions-closures/fn-help-with-err.rs b/src/test/ui/functions-closures/fn-help-with-err.rs
new file mode 100644 (file)
index 0000000..f8a81af
--- /dev/null
@@ -0,0 +1,16 @@
+// This test case checks the behavior of typeck::check::method::suggest::is_fn on Ty::Error.
+fn main() {
+    let arc = std::sync::Arc::new(oops);
+    //~^ ERROR cannot find value `oops` in this scope
+    //~| NOTE not found
+    // The error "note: `arc` is a function, perhaps you wish to call it" MUST NOT appear.
+    arc.blablabla();
+    //~^ ERROR no method named `blablabla`
+    //~| NOTE method not found
+    let arc2 = std::sync::Arc::new(|| 1);
+    // The error "note: `arc2` is a function, perhaps you wish to call it" SHOULD appear
+    arc2.blablabla();
+    //~^ ERROR no method named `blablabla`
+    //~| NOTE method not found
+    //~| NOTE `arc2` is a function, perhaps you wish to call it
+}
diff --git a/src/test/ui/functions-closures/fn-help-with-err.stderr b/src/test/ui/functions-closures/fn-help-with-err.stderr
new file mode 100644 (file)
index 0000000..4d6b328
--- /dev/null
@@ -0,0 +1,24 @@
+error[E0425]: cannot find value `oops` in this scope
+  --> $DIR/fn-help-with-err.rs:3:35
+   |
+LL |     let arc = std::sync::Arc::new(oops);
+   |                                   ^^^^ not found in this scope
+
+error[E0599]: no method named `blablabla` found for struct `Arc<_>` in the current scope
+  --> $DIR/fn-help-with-err.rs:7:9
+   |
+LL |     arc.blablabla();
+   |         ^^^^^^^^^ method not found in `Arc<_>`
+
+error[E0599]: no method named `blablabla` found for struct `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>` in the current scope
+  --> $DIR/fn-help-with-err.rs:12:10
+   |
+LL |     arc2.blablabla();
+   |          ^^^^^^^^^ method not found in `Arc<[closure@$DIR/fn-help-with-err.rs:10:36: 10:40]>`
+   |
+   = note: `arc2` is a function, perhaps you wish to call it
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0425, E0599.
+For more information about an error, try `rustc --explain E0425`.
index 8540f7617acde619cffd4b819c56b9f2a77c0135..914a7d71dc4210853587198f854b7202ade0ce9e 100644 (file)
@@ -1,4 +1,5 @@
 // build-pass
+// compile-flags: -Zdrop-tracking
 
 // FIXME(eholk): temporarily disabled while drop range tracking is disabled
 // (see generator_interior.rs:27)
@@ -114,6 +115,22 @@ fn nested_loop() {
     };
 }
 
+fn loop_continue(b: bool) {
+    let _ = || {
+        let mut arr = [Ptr];
+        let mut count = 0;
+        drop(arr);
+        while count < 3 {
+            count += 1;
+            yield;
+            if b {
+                arr = [Ptr];
+                continue;
+            }
+        }
+    };
+}
+
 fn main() {
     one_armed_if(true);
     if_let(Some(41));
@@ -122,4 +139,5 @@ fn main() {
     reinit();
     loop_uninit();
     nested_loop();
+    loop_continue(true);
 }
diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.rs b/src/test/ui/generic-associated-types/bugs/issue-80626.rs
new file mode 100644 (file)
index 0000000..aea8aaf
--- /dev/null
@@ -0,0 +1,17 @@
+// check-fail
+
+// This should pass, but it requires `Sized` to be coinductive.
+
+#![feature(generic_associated_types)]
+
+trait Allocator {
+    type Allocated<T>;
+}
+
+enum LinkedList<A: Allocator> {
+    Head,
+    Next(A::Allocated<Self>)
+    //~^ overflow
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-80626.stderr b/src/test/ui/generic-associated-types/bugs/issue-80626.stderr
new file mode 100644 (file)
index 0000000..e18af9c
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0275]: overflow evaluating the requirement `LinkedList<A>: Sized`
+  --> $DIR/issue-80626.rs:13:10
+   |
+LL |     Next(A::Allocated<Self>)
+   |          ^^^^^^^^^^^^^^^^^^
+   |
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     Next(&A::Allocated<Self>)
+   |          +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     Next(Box<A::Allocated<Self>>)
+   |          ++++                  +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.rs b/src/test/ui/generic-associated-types/bugs/issue-86218.rs
new file mode 100644 (file)
index 0000000..3f8776a
--- /dev/null
@@ -0,0 +1,27 @@
+// check-fail
+
+// This should pass, but seems to run into a TAIT issue.
+
+#![feature(generic_associated_types)]
+#![feature(type_alias_impl_trait)]
+
+pub trait Stream {
+    type Item;
+}
+
+impl Stream for () {
+    type Item = i32;
+}
+
+trait Yay<AdditionalValue> {
+    type InnerStream<'s>: Stream<Item = i32> + 's;
+    fn foo<'s>() -> Self::InnerStream<'s>;
+}
+
+impl<'a> Yay<&'a ()> for () {
+    type InnerStream<'s> = impl Stream<Item = i32> + 's;
+    //~^ the type
+    fn foo<'s>() -> Self::InnerStream<'s> { todo!() }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-86218.stderr b/src/test/ui/generic-associated-types/bugs/issue-86218.stderr
new file mode 100644 (file)
index 0000000..9f4efc0
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0477]: the type `impl Stream<Item = i32>` does not fulfill the required lifetime
+  --> $DIR/issue-86218.rs:22:28
+   |
+LL |     type InnerStream<'s> = impl Stream<Item = i32> + 's;
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: type must outlive the lifetime `'s` as defined here as required by this binding
+  --> $DIR/issue-86218.rs:22:22
+   |
+LL |     type InnerStream<'s> = impl Stream<Item = i32> + 's;
+   |                      ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0477`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.rs b/src/test/ui/generic-associated-types/bugs/issue-87735.rs
new file mode 100644 (file)
index 0000000..5f7a42a
--- /dev/null
@@ -0,0 +1,45 @@
+// check-fail
+
+// This should pass, but we need an extension of implied bounds (probably).
+
+#![feature(generic_associated_types)]
+
+pub trait AsRef2 {
+  type Output<'a> where Self: 'a;
+
+  fn as_ref2<'a>(&'a self) -> Self::Output<'a>;
+}
+
+impl<T> AsRef2 for Vec<T> {
+  type Output<'a> where Self: 'a = &'a [T];
+
+  fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
+    &self[..]
+  }
+}
+
+#[derive(Debug)]
+struct Foo<T>(T);
+#[derive(Debug)]
+struct FooRef<'a, U>(&'a [U]);
+
+impl<'b, T, U> AsRef2 for Foo<T> //~ the type parameter
+where
+    // * `for<'b, 'c> T: AsRef2<Output<'b> = &'c [U]>>` does not work
+    //
+    // * `U` is unconstrained but should be allowed in this context because `Output` is
+    // an associated type
+    T: AsRef2<Output<'b> = &'b [U]>,
+    U: 'b
+{
+  type Output<'a> where Self: 'a = FooRef<'a, U>;
+
+  fn as_ref2<'a>(&'a self) -> Self::Output<'a> {
+    FooRef(self.0.as_ref2())
+  }
+}
+
+fn main() {
+    let foo = Foo(vec![1, 2, 3]);
+    dbg!(foo.as_ref2());
+}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87735.stderr b/src/test/ui/generic-associated-types/bugs/issue-87735.stderr
new file mode 100644 (file)
index 0000000..31b3a96
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-87735.rs:26:13
+   |
+LL | impl<'b, T, U> AsRef2 for Foo<T>
+   |             ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.rs b/src/test/ui/generic-associated-types/bugs/issue-87748.rs
new file mode 100644 (file)
index 0000000..4dbaf42
--- /dev/null
@@ -0,0 +1,22 @@
+// check-fail
+
+// This should pass, but unnormalized input args aren't treated as implied.
+
+#![feature(generic_associated_types)]
+
+trait MyTrait {
+    type Assoc<'a, 'b> where 'b: 'a;
+    fn do_sth(arg: Self::Assoc<'_, '_>);
+}
+
+struct Foo;
+
+impl MyTrait for Foo {
+    type Assoc<'a, 'b> where 'b: 'a = u32;
+
+    fn do_sth(_: u32) {} //~ lifetime bound
+    // fn do_sth(_: Self::Assoc<'static, 'static>) {}
+    // fn do_sth(_: Self::Assoc<'_, '_>) {}
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr
new file mode 100644 (file)
index 0000000..c38d447
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0478]: lifetime bound not satisfied
+  --> $DIR/issue-87748.rs:17:5
+   |
+LL |     fn do_sth(_: u32) {}
+   |     ^^^^^^^^^^^^^^^^^
+   |
+note: lifetime parameter instantiated with the anonymous lifetime #2 defined here
+  --> $DIR/issue-87748.rs:17:5
+   |
+LL |     fn do_sth(_: u32) {}
+   |     ^^^^^^^^^^^^^^^^^
+note: but lifetime parameter must outlive the anonymous lifetime #1 defined here
+  --> $DIR/issue-87748.rs:17:5
+   |
+LL |     fn do_sth(_: u32) {}
+   |     ^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0478`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87755.rs b/src/test/ui/generic-associated-types/bugs/issue-87755.rs
new file mode 100644 (file)
index 0000000..1cd3534
--- /dev/null
@@ -0,0 +1,21 @@
+// check-fail
+
+// This should pass.
+
+#![feature(generic_associated_types)]
+
+use std::fmt::Debug;
+
+trait Foo {
+    type Ass where Self::Ass: Debug;
+}
+
+#[derive(Debug)]
+struct Bar;
+
+impl Foo for Bar {
+    type Ass = Bar;
+    //~^ overflow
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87755.stderr b/src/test/ui/generic-associated-types/bugs/issue-87755.stderr
new file mode 100644 (file)
index 0000000..d2dc991
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0275]: overflow evaluating the requirement `<Bar as Foo>::Ass == _`
+  --> $DIR/issue-87755.rs:17:16
+   |
+LL |     type Ass = Bar;
+   |                ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87803.rs b/src/test/ui/generic-associated-types/bugs/issue-87803.rs
new file mode 100644 (file)
index 0000000..3d2ff38
--- /dev/null
@@ -0,0 +1,26 @@
+// check-fail
+
+// This should pass, but using a type alias vs a reference directly
+// changes late-bound -> early-bound.
+
+#![feature(generic_associated_types)]
+
+trait Scanner {
+    type Input<'a>;
+    type Token<'a>;
+
+    fn scan<'a>(&mut self, i : Self::Input<'a>) -> Self::Token<'a>;
+}
+
+struct IdScanner();
+
+impl Scanner for IdScanner {
+    type Input<'a> = &'a str;
+    type Token<'a> = &'a str;
+
+    fn scan<'a>(&mut self, s : &'a str) -> &'a str { //~ lifetime parameters
+        s
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87803.stderr b/src/test/ui/generic-associated-types/bugs/issue-87803.stderr
new file mode 100644 (file)
index 0000000..759c044
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0195]: lifetime parameters or bounds on method `scan` do not match the trait declaration
+  --> $DIR/issue-87803.rs:21:12
+   |
+LL |     fn scan<'a>(&mut self, i : Self::Input<'a>) -> Self::Token<'a>;
+   |            ---- lifetimes in impl do not match this method in trait
+...
+LL |     fn scan<'a>(&mut self, s : &'a str) -> &'a str {
+   |            ^^^^ lifetimes do not match method in trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0195`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.rs b/src/test/ui/generic-associated-types/bugs/issue-88382.rs
new file mode 100644 (file)
index 0000000..f4633ca
--- /dev/null
@@ -0,0 +1,31 @@
+// check-fail
+
+// This should pass, but has a missed normalization due to HRTB.
+
+#![feature(generic_associated_types)]
+
+trait Iterable {
+    type Iterator<'a> where Self: 'a;
+    fn iter(&self) -> Self::Iterator<'_>;
+}
+
+struct SomeImplementation();
+
+impl Iterable for SomeImplementation {
+    type Iterator<'a> = std::iter::Empty<usize>;
+    fn iter(&self) -> Self::Iterator<'_> {
+        std::iter::empty()
+    }
+}
+
+fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) {
+    f(&mut i.iter());
+}
+
+fn main() {
+    do_something(SomeImplementation(), |_| ());
+    do_something(SomeImplementation(), test);
+    //~^ type mismatch
+}
+
+fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88382.stderr b/src/test/ui/generic-associated-types/bugs/issue-88382.stderr
new file mode 100644 (file)
index 0000000..05bc58c
--- /dev/null
@@ -0,0 +1,20 @@
+error[E0631]: type mismatch in function arguments
+  --> $DIR/issue-88382.rs:27:40
+   |
+LL |     do_something(SomeImplementation(), test);
+   |     ------------                       ^^^^ expected signature of `for<'a> fn(&mut <SomeImplementation as Iterable>::Iterator<'a>) -> _`
+   |     |
+   |     required by a bound introduced by this call
+...
+LL | fn test<'a, I: Iterable>(_: &mut I::Iterator<'a>) {}
+   | ------------------------------------------------- found signature of `for<'r> fn(&'r mut std::iter::Empty<usize>) -> _`
+   |
+note: required by a bound in `do_something`
+  --> $DIR/issue-88382.rs:21:56
+   |
+LL | fn do_something<I: Iterable>(i: I, mut f: impl for<'a> Fn(&mut I::Iterator<'a>)) {
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `do_something`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0631`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88460.rs b/src/test/ui/generic-associated-types/bugs/issue-88460.rs
new file mode 100644 (file)
index 0000000..7e62790
--- /dev/null
@@ -0,0 +1,31 @@
+// check-fail
+
+// This should pass, but has a missed normalization due to HRTB.
+
+#![feature(generic_associated_types)]
+
+pub trait Marker {}
+
+pub trait Trait {
+    type Assoc<'a>;
+}
+
+fn test<T>(value: T)
+where
+    T: Trait,
+    for<'a> T::Assoc<'a>: Marker,
+{
+}
+
+impl Marker for () {}
+
+struct Foo;
+
+impl Trait for Foo {
+    type Assoc<'a> = ();
+}
+
+fn main() {
+    test(Foo);
+    //~^ the trait bound
+}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88460.stderr b/src/test/ui/generic-associated-types/bugs/issue-88460.stderr
new file mode 100644 (file)
index 0000000..604658d
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0277]: the trait bound `for<'a> <_ as Trait>::Assoc<'a>: Marker` is not satisfied
+  --> $DIR/issue-88460.rs:29:5
+   |
+LL |     test(Foo);
+   |     ^^^^ the trait `for<'a> Marker` is not implemented for `<_ as Trait>::Assoc<'a>`
+   |
+note: required by a bound in `test`
+  --> $DIR/issue-88460.rs:16:27
+   |
+LL | fn test<T>(value: T)
+   |    ---- required by a bound in this
+...
+LL |     for<'a> T::Assoc<'a>: Marker,
+   |                           ^^^^^^ required by this bound in `test`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88526.rs b/src/test/ui/generic-associated-types/bugs/issue-88526.rs
new file mode 100644 (file)
index 0000000..90568fc
--- /dev/null
@@ -0,0 +1,34 @@
+// check-fail
+
+// This should pass, but requires more logic.
+
+#![feature(generic_associated_types)]
+
+trait A {
+    type I<'a>;
+}
+
+pub struct TestA<F>
+{
+    f: F,
+}
+
+impl<F> A for TestA<F> {
+    type I<'a> = &'a F;
+}
+
+struct TestB<Q, F>
+{
+    q: Q,
+    f: F,
+}
+
+impl<'q, Q, I, F> A for TestB<Q, F> //~ the type parameter
+where
+    Q: A<I<'q> = &'q I>,
+    F: Fn(I),
+{
+    type I<'a> = ();
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-88526.stderr b/src/test/ui/generic-associated-types/bugs/issue-88526.stderr
new file mode 100644 (file)
index 0000000..ccc5ae0
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0207]: the type parameter `I` is not constrained by the impl trait, self type, or predicates
+  --> $DIR/issue-88526.rs:26:13
+   |
+LL | impl<'q, Q, I, F> A for TestB<Q, F>
+   |             ^ unconstrained type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0207`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.rs b/src/test/ui/generic-associated-types/bugs/issue-89008.rs
new file mode 100644 (file)
index 0000000..5d85084
--- /dev/null
@@ -0,0 +1,43 @@
+// check-fail
+// edition:2021
+
+// This should pass, but seems to run into a TAIT bug.
+
+#![feature(type_alias_impl_trait)]
+#![feature(generic_associated_types)]
+
+use std::future::Future;
+
+trait Stream {
+    type Item;
+}
+
+struct Empty<T>(T);
+impl<T> Stream for Empty<T> {
+    type Item = ();
+}
+fn empty<T>() -> Empty<T> {
+    todo!()
+}
+
+trait X {
+    type LineStream<'a, Repr>: Stream<Item = Repr> where Self: 'a;
+
+    type LineStreamFut<'a,Repr>: Future<Output = Self::LineStream<'a, Repr>> where Self: 'a;
+
+    fn line_stream<'a,Repr>(&'a self) -> Self::LineStreamFut<'a,Repr>;
+}
+
+struct Y;
+
+impl X for Y {
+    type LineStream<'a, Repr> = impl Stream<Item = Repr>; //~ could not find
+
+    type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>> ;
+
+    fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> { //~ type mismatch
+        async {empty()}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/bugs/issue-89008.stderr b/src/test/ui/generic-associated-types/bugs/issue-89008.stderr
new file mode 100644 (file)
index 0000000..48745fe
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0271]: type mismatch resolving `<impl Future<Output = [async output]> as Future>::Output == impl Stream<Item = Repr>`
+  --> $DIR/issue-89008.rs:38:43
+   |
+LL |     type LineStream<'a, Repr> = impl Stream<Item = Repr>;
+   |                                 ------------------------ the expected opaque type
+...
+LL |     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found struct `Empty`
+   |
+   = note: expected opaque type `impl Stream<Item = Repr>`
+                   found struct `Empty<_>`
+
+error: could not find defining uses
+  --> $DIR/issue-89008.rs:34:33
+   |
+LL |     type LineStream<'a, Repr> = impl Stream<Item = Repr>;
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
index 5be431f2933b30c78b18024e1a95951657c39cbd..bd0dea372194d4f14a6b4c90c975b6c33abe0510 100644 (file)
@@ -19,8 +19,13 @@ LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
 error[E0478]: lifetime bound not satisfied
   --> $DIR/impl_bounds.rs:17:35
    |
+LL |     type B<'a, 'b> where 'a: 'b;
+   |     ---------------------------- definition of `B` from trait
+...
 LL |     type B<'a, 'b> where 'b: 'a = (&'a(), &'b ());
-   |                                   ^^^^^^^^^^^^^^^
+   |                                -  ^^^^^^^^^^^^^^^
+   |                                |
+   |                                help: try copying this clause from the trait: `, 'a: 'b`
    |
 note: lifetime parameter instantiated with the lifetime `'a` as defined here
   --> $DIR/impl_bounds.rs:17:12
index 1bbf7aac5cdabc6ff70bb90f645e3f85ccda02f8..01f99fa448749fdd3a346d844e678c290dec8e73 100644 (file)
@@ -17,6 +17,7 @@ impl<T> UnsafeCopy for T {}
 fn main() {
     let b = Box::new(42usize);
     let copy = <()>::copy(&b);
+    //~^ type annotations needed
 
     let raw_b = Box::deref(&b) as *const _;
     let raw_copy = Box::deref(&copy) as *const _;
index 8517eb9fa21026c915453e4dcb1463593b7cee28..e7ebf5964ba4125d0e05d8d54a65d90de213b621 100644 (file)
@@ -27,6 +27,13 @@ help: consider restricting type parameter `T`
 LL |     type Copy<T: std::clone::Clone>: Copy = Box<T>;
    |                +++++++++++++++++++
 
-error: aborting due to 2 previous errors
+error[E0282]: type annotations needed
+  --> $DIR/issue-74824.rs:19:16
+   |
+LL |     let copy = <()>::copy(&b);
+   |                ^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `copy`
+
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0277, E0282.
+For more information about an error, try `rustc --explain E0277`.
index e397390783f66857560e8be8ad68f9dda875d229..c97d17811ba7c918b72d01d6521aa4ca1d301f0e 100644 (file)
@@ -8,7 +8,7 @@ trait A<'a> {
     // FIXME(generic_associated_types): Remove one of the below bounds
     // https://github.com/rust-lang/rust/pull/90678#discussion_r744976085
     where
-        'a: 'b, Self: 'a, Self: 'b;
+        Self: 'a, Self: 'b;
 
     fn a(&'a self) -> Self::B<'a>;
 }
@@ -17,8 +17,7 @@ trait A<'a> {
 
 impl<'a> A<'a> for C {
     type B<'b> = impl Clone;
-    //~^ ERROR: lifetime bound not satisfied
-    //~| ERROR: could not find defining uses
+    //~^ ERROR: could not find defining uses
 
     fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope
 }
index cb462871ccd32b7ce26f81ece5e897455eef32b9..4e4f86bbac87c512d0212b17ab60d55a92466615 100644 (file)
@@ -1,22 +1,5 @@
-error[E0478]: lifetime bound not satisfied
-  --> $DIR/issue-88595.rs:19:18
-   |
-LL |     type B<'b> = impl Clone;
-   |                  ^^^^^^^^^^
-   |
-note: lifetime parameter instantiated with the lifetime `'a` as defined here
-  --> $DIR/issue-88595.rs:18:6
-   |
-LL | impl<'a> A<'a> for C {
-   |      ^^
-note: but lifetime parameter must outlive the lifetime `'b` as defined here
-  --> $DIR/issue-88595.rs:19:12
-   |
-LL |     type B<'b> = impl Clone;
-   |            ^^
-
 error: non-defining opaque type use in defining scope
-  --> $DIR/issue-88595.rs:23:23
+  --> $DIR/issue-88595.rs:22:23
    |
 LL |     fn a(&'a self) -> Self::B<'a> {}
    |                       ^^^^^^^^^^^
@@ -35,6 +18,5 @@ error: could not find defining uses
 LL |     type B<'b> = impl Clone;
    |                  ^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0478`.
index 23e8d08af34286699d69da3704caa99698abbcf9..f8fb71bbddb4b8673145ec7592e03efe984a3334 100644 (file)
@@ -1,8 +1,13 @@
 error[E0477]: the type `&mut ()` does not fulfill the required lifetime
   --> $DIR/issue-90014.rs:14:20
    |
+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:14:14
diff --git a/src/test/ui/generic-associated-types/issue-91139.rs b/src/test/ui/generic-associated-types/issue-91139.rs
new file mode 100644 (file)
index 0000000..2b82d29
--- /dev/null
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+trait Foo<T> {
+    type Type<'a>
+    where
+        T: 'a;
+}
+
+impl<T> Foo<T> for () {
+    type Type<'a>
+    where
+        T: 'a,
+    = ();
+}
+
+fn foo<T>() {
+    let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+}
+
+pub fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-91762.rs b/src/test/ui/generic-associated-types/issue-91762.rs
new file mode 100644 (file)
index 0000000..b259a3c
--- /dev/null
@@ -0,0 +1,30 @@
+// check-fail
+
+// FIXME(generic_associated_types): We almost certaintly want this to pass, but
+// it's particularly difficult currently, because we need a way of specifying
+// that `<Self::Base as Functor>::With<T> = Self` without using that when we have
+// a `U`. See `https://github.com/rust-lang/rust/pull/92728` for a (hacky)
+// solution. This might be better to just wait for Chalk.
+
+#![feature(generic_associated_types)]
+
+pub trait Functor {
+    type With<T>;
+
+    fn fmap<T, U>(this: Self::With<T>) -> Self::With<U>;
+}
+
+pub trait FunctorExt<T>: Sized {
+    type Base: Functor<With<T> = Self>;
+
+    fn fmap<U>(self) {
+        let arg: <Self::Base as Functor>::With<T>;
+        let ret: <Self::Base as Functor>::With<U>;
+
+        arg = self;
+        ret = <Self::Base as Functor>::fmap(arg);
+        //~^ type annotations needed
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-91762.stderr b/src/test/ui/generic-associated-types/issue-91762.stderr
new file mode 100644 (file)
index 0000000..a9c465c
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-91762.rs:25:15
+   |
+LL |         ret = <Self::Base as Functor>::fmap(arg);
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the associated function `fmap`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/src/test/ui/generic-associated-types/issue-92033.rs b/src/test/ui/generic-associated-types/issue-92033.rs
new file mode 100644 (file)
index 0000000..1d5f7d5
--- /dev/null
@@ -0,0 +1,39 @@
+#![feature(generic_associated_types)]
+
+struct Texture;
+
+trait Surface {
+    type TextureIter<'a>: Iterator<Item = &'a Texture>
+    where
+        Self: 'a;
+
+    fn get_texture(&self) -> Self::TextureIter<'_>;
+}
+
+trait Swapchain {
+    type Surface<'a>: Surface
+    where
+        Self: 'a;
+
+    fn get_surface(&self) -> Self::Surface<'_>;
+}
+
+impl<'s> Surface for &'s Texture {
+    type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
+    //~^ ERROR the type
+
+    fn get_texture(&self) -> Self::TextureIter<'_> {
+        let option: Option<&Texture> = Some(self);
+        option.into_iter()
+    }
+}
+
+impl Swapchain for Texture {
+    type Surface<'a> = &'a Texture;
+
+    fn get_surface(&self) -> Self::Surface<'_> {
+        self
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-92033.stderr b/src/test/ui/generic-associated-types/issue-92033.stderr
new file mode 100644 (file)
index 0000000..caa6618
--- /dev/null
@@ -0,0 +1,22 @@
+error[E0477]: the type `&'s Texture` does not fulfill the required lifetime
+  --> $DIR/issue-92033.rs:22:28
+   |
+LL | /     type TextureIter<'a>: Iterator<Item = &'a Texture>
+LL | |     where
+LL | |         Self: 'a;
+   | |_________________- 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:22:22
+   |
+LL |     type TextureIter<'a> = std::option::IntoIter<&'a Texture>;
+   |                      ^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0477`.
index fcc53b4ede0cb65ceacc59a96c18bcdfdf0214d8..300907adbfc11546356902ade82985d5496c45b6 100644 (file)
@@ -140,11 +140,19 @@ trait NotInReturn {
 // We obviously error for `Iterator`, but we should also error for `Item`
 trait IterableTwo {
     type Item<'a>;
+    //~^ missing required
     type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
     //~^ missing required
     fn iter<'a>(&'a self) -> Self::Iterator<'a>;
 }
 
+trait IterableTwoWhere {
+    type Item<'a>;
+    //~^ missing required
+    type Iterator<'a>: Iterator<Item = Self::Item<'a>> where Self: 'a;
+    fn iter<'a>(&'a self) -> Self::Iterator<'a>;
+}
+
 // We also should report region outlives clauses. Here, we know that `'y: 'x`,
 // because of `&'x &'y`, so we require that `'b: 'a`.
 trait RegionOutlives {
index 3b9146ad875a34b36394f4b81e72910f92c8be0a..fdb1f50a7764c94d3e61b83ee87851107fc48929 100644 (file)
@@ -108,8 +108,19 @@ LL |     type Bar<'b>;
    = note: this bound is currently required to ensure that impls have maximum flexibility
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
+error: missing required bound on `Item`
+  --> $DIR/self-outlives-lint.rs:142:5
+   |
+LL |     type Item<'a>;
+   |     ^^^^^^^^^^^^^-
+   |                  |
+   |                  help: add the required where clause: `where Self: 'a`
+   |
+   = note: this bound is currently required to ensure that impls have maximum flexibility
+   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
 error: missing required bound on `Iterator`
-  --> $DIR/self-outlives-lint.rs:143:5
+  --> $DIR/self-outlives-lint.rs:144:5
    |
 LL |     type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
@@ -119,8 +130,19 @@ LL |     type Iterator<'a>: Iterator<Item = Self::Item<'a>>;
    = note: this bound is currently required to ensure that impls have maximum flexibility
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
+error: missing required bound on `Item`
+  --> $DIR/self-outlives-lint.rs:150:5
+   |
+LL |     type Item<'a>;
+   |     ^^^^^^^^^^^^^-
+   |                  |
+   |                  help: add the required where clause: `where Self: 'a`
+   |
+   = note: this bound is currently required to ensure that impls have maximum flexibility
+   = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
+
 error: missing required bound on `Bar`
-  --> $DIR/self-outlives-lint.rs:151:5
+  --> $DIR/self-outlives-lint.rs:159:5
    |
 LL |     type Bar<'a, 'b>;
    |     ^^^^^^^^^^^^^^^^-
@@ -131,7 +153,7 @@ LL |     type Bar<'a, 'b>;
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
 error: missing required bound on `Fut`
-  --> $DIR/self-outlives-lint.rs:167:5
+  --> $DIR/self-outlives-lint.rs:175:5
    |
 LL |     type Fut<'out>;
    |     ^^^^^^^^^^^^^^-
@@ -141,5 +163,5 @@ LL |     type Fut<'out>;
    = note: this bound is currently required to ensure that impls have maximum flexibility
    = note: we are soliciting feedback, see issue #87479 <https://github.com/rust-lang/rust/issues/87479> for more information
 
-error: aborting due to 13 previous errors
+error: aborting due to 15 previous errors
 
index 45dcb74a6e05c41cbbc263b916c9f642aa5d8228..da45f0d133deb955110f952a392c4acb68efb8dd 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-// ignore-compare-mode-chalk
 
 #![feature(fn_traits,
            step_trait,
index a519397806e0703ee7e83076dc191016722e607f..17a6a85787442cf8489e2bb712af3a57c4362ac6 100644 (file)
@@ -1,5 +1,4 @@
 // edition:2018
-// ignore-compare-mode-chalk
 
 #![feature(type_alias_impl_trait)]
 
index 97545ba3d1124c755df086a10ff9195b445ef00f..b76b564dfb139352cd83be0a07b8d560c69b0d0d 100644 (file)
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `impl Future<Output = [async output]>: Copy` is not satisfied
-  --> $DIR/issue-55872-2.rs:14:20
+  --> $DIR/issue-55872-2.rs:13:20
    |
 LL |     fn foo<T>() -> Self::E {
    |                    ^^^^^^^ the trait `Copy` is not implemented for `impl Future<Output = [async output]>`
 
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-55872-2.rs:14:28
+  --> $DIR/issue-55872-2.rs:13:28
    |
 LL |       fn foo<T>() -> Self::E {
    |  ____________________________^
index bbd940254178ce45ffe4dfff6ec5c35b8808f50d..183728b0f7f0a5224386c52da030a73c3899ea6d 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-compare-mode-chalk
 #![feature(type_alias_impl_trait)]
 
 pub trait Bar {
index 60654ec34610fc24321c244905b55dc66950a454..39d870dc003bb580de5d2e8f0cc66cd99141bdd3 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-55872.rs:13:28
+  --> $DIR/issue-55872.rs:12:28
    |
 LL |       fn foo<T>() -> Self::E {
    |  ____________________________^
index af65b79d3e838b58464797920d81d463decc68c6..b947fc1d2396faca035781daa60a7ed5b4dda046 100644 (file)
@@ -1,4 +1,5 @@
 // check-pass
+// ignore-compare-mode-chalk
 
 #![allow(dead_code)]
 
diff --git a/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.rs
new file mode 100644 (file)
index 0000000..d9de73a
--- /dev/null
@@ -0,0 +1,51 @@
+// A test exploiting the bug behind #25860 except with
+// implied trait bounds which currently don't exist without `-Zchalk`.
+use std::marker::PhantomData;
+struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
+where
+    T: Convert<'a, 'b>;
+
+trait Convert<'a, 'b>: Sized {
+    fn cast(&'a self) -> &'b Self;
+}
+impl<'long: 'short, 'short, T> Convert<'long, 'short> for T {
+    fn cast(&'long self) -> &'short T {
+        self
+    }
+}
+
+// This function will compile once we add implied trait bounds.
+//
+// If we're not careful with our impl, the transformations
+// in `bad` would succeed, which is unsound ✨
+//
+// FIXME: the error is pretty bad, this should say
+//
+//     `T: Convert<'in_, 'out>` is not implemented
+//
+// help: needed by `Foo<'in_, 'out, T>`
+//
+// Please ping @lcnr if your changes end up causing `badboi` to compile.
+fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) -> &'out T {
+    //~^ ERROR lifetime mismatch
+    sadness.cast()
+}
+
+fn bad<'short, T>(value: &'short T) -> &'static T {
+    let x: for<'in_, 'out> fn(Foo<'in_, 'out, T>, &'in_ T) -> &'out T = badboi;
+    let x: for<'out> fn(Foo<'short, 'out, T>, &'short T) -> &'out T = x;
+    let x: for<'out> fn(Foo<'static, 'out, T>, &'short T) -> &'out T = x;
+    let x: fn(Foo<'static, 'static, T>, &'short T) -> &'static T = x;
+    x(Foo(PhantomData), value)
+}
+
+// Use `bad` to cause a segfault.
+fn main() {
+    let mut outer: Option<&'static u32> = Some(&3);
+    let static_ref: &'static &'static u32 = match outer {
+        Some(ref reference) => bad(reference),
+        None => unreachable!(),
+    };
+    outer = None;
+    println!("{}", static_ref);
+}
diff --git a/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-guard.stderr
new file mode 100644 (file)
index 0000000..b020ea6
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0623]: lifetime mismatch
+  --> $DIR/hrlt-implied-trait-bounds-guard.rs:29:29
+   |
+LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ T) -> &'out T {
+   |                             ^^^^^^^^^^^^^^^^^^                       -------
+   |                             |
+   |                             this parameter and the return type are declared with different lifetimes...
+   |                             ...but data from `x` is returned here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0623`.
diff --git a/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs b/src/test/ui/implied-bounds/hrlt-implied-trait-bounds-roundtrip.rs
new file mode 100644 (file)
index 0000000..69847d6
--- /dev/null
@@ -0,0 +1,35 @@
+// check-pass
+struct Foo<'a>(&'a ())
+where
+    (): Trait<'a>;
+
+trait Trait<'a> {
+    fn id<T>(value: &'a T) -> &'static T;
+}
+
+impl Trait<'static> for () {
+    fn id<T>(value: &'static T) -> &'static T {
+        value
+    }
+}
+
+fn could_use_implied_bounds<'a, T>(_: Foo<'a>, x: &'a T) -> &'static T
+where
+    (): Trait<'a>, // This could be an implied bound
+{
+    <()>::id(x)
+}
+
+fn main() {
+    let bar: for<'a, 'b> fn(Foo<'a>, &'b ()) = |_, _| {};
+
+    // If `could_use_implied_bounds` were to use implied bounds,
+    // keeping 'a late-bound, then we could assign that function
+    // to this variable.
+    let bar: for<'a> fn(Foo<'a>, &'a ()) = bar;
+
+    // In this case, the subtyping relation here would be unsound,
+    // allowing us to transmute lifetimes. This currently compiles
+    // because we incorrectly deal with implied bounds inside of binders.
+    let _bar: for<'a, 'b> fn(Foo<'a>, &'b ()) = bar;
+}
index 21bbc6f20b294341ca41140e956ff44a9f154caf..c29a15025a9c29d27c802af015d131b03c2187c7 100644 (file)
@@ -1,6 +1,7 @@
-// When a MULTI-character string literal is used where a char should be,
+// When a MULTI/NO-character string literal is used where a char should be,
 // DO NOT suggest changing to single quotes.
 
 fn main() {
     let _: char = "foo"; //~ ERROR mismatched types
+    let _: char = ""; //~ ERROR mismatched types
 }
index c3ba17a5579ad55978a625e643626d21bc0fa646..297ca2b548f7141d2b90868739dd7f67a06f2c55 100644 (file)
@@ -6,6 +6,14 @@ LL |     let _: char = "foo";
    |            |
    |            expected due to this
 
-error: aborting due to previous error
+error[E0308]: mismatched types
+  --> $DIR/char-as-str-multi.rs:6:19
+   |
+LL |     let _: char = "";
+   |            ----   ^^ expected `char`, found `&str`
+   |            |
+   |            expected due to this
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/issues/issue-14772.rs b/src/test/ui/issues/issue-14772.rs
deleted file mode 100644 (file)
index 8f67452..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// compile-flags: --test
-
-#[test]
-mod foo {} //~ ERROR only functions may be used as tests
-
-fn main() {}
diff --git a/src/test/ui/issues/issue-14772.stderr b/src/test/ui/issues/issue-14772.stderr
deleted file mode 100644 (file)
index 253fec5..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-error: only functions may be used as tests
-  --> $DIR/issue-14772.rs:4:1
-   |
-LL | mod foo {}
-   | ^^^^^^^^^^
-
-error: aborting due to previous error
-
index 5a276f27886d29830b85009b2ad518f162f24f5a..60a2bf1e2d66083485e4539df7124141a9523d69 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `Y::foo` in statics
   --> $DIR/issue-16538.rs:15:23
    |
 LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error[E0133]: use of extern static is unsafe and requires unsafe function or block
   --> $DIR/issue-16538.rs:15:30
index 8365a1dbf6e5ebdb92e1a4fa9ae7c860629b8fb8..2ba9dfa2bc5f844c62d484d8b4b80db45b1e37be 100644 (file)
@@ -14,11 +14,13 @@ LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
    |
    = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
 
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `Y::foo` in statics
   --> $DIR/issue-16538.rs:15:23
    |
 LL | static foo: &Y::X = &*Y::foo(Y::x as *const Y::X);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 3 previous errors
 
index d67f184720e6cb82be639057fdc5bc888390bdcd..ac24648e49e915fda9e1e08a72cb55744c1c3155 100644 (file)
@@ -1,4 +1,5 @@
 // run-pass
+// ignore-wasm32-bare FIXME(#93923) llvm miscompilation
 
 use std::collections::HashMap;
 use std::path::Path;
index efa4e614be5b0e4f3e29eb4176b50461f3df8e86..7fe0900ed5fde143d23b9553d1a0208db49b357a 100644 (file)
@@ -1,10 +1,10 @@
-// ignore-compare-mode-chalk
-
 trait Next {
     type Next: Next;
 }
 
-struct GetNext<T: Next> { t: T }
+struct GetNext<T: Next> {
+    t: T,
+}
 
 impl<T: Next> Next for GetNext<T> {
     type Next = <GetNext<T> as Next>::Next;
index 7866b931ec4b9d023e41fb3555d8ad86aef6a21c..95e1f60d8b029b607d7dacc9a0785ce84f9c534c 100644 (file)
@@ -1,9 +1,10 @@
-// ignore-compare-mode-chalk
 trait Next {
     type Next: Next;
 }
 
-struct GetNext<T: Next> { t: T }
+struct GetNext<T: Next> {
+    t: T,
+}
 
 impl<T: Next> Next for GetNext<T> {
     type Next = <GetNext<T::Next> as Next>::Next;
index b345e90178742ee0049c08d733b604f2a1df7a0d..7519e632d5446ac10cd64a698b6199bac31214ac 100644 (file)
@@ -1,12 +1,12 @@
 error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next: Sized`
-  --> $DIR/issue-23122-2.rs:9:17
+  --> $DIR/issue-23122-2.rs:10:17
    |
 LL |     type Next = <GetNext<T::Next> as Next>::Next;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_23122_2`)
 note: required because of the requirements on the impl of `Next` for `GetNext<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<T as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next as Next>::Next>`
-  --> $DIR/issue-23122-2.rs:8:15
+  --> $DIR/issue-23122-2.rs:9:15
    |
 LL | impl<T: Next> Next for GetNext<T> {
    |               ^^^^     ^^^^^^^^^^
index a139ad0d3e3233517f959fc8f371e1d102079264..ba12e1ad0211bffcbd8d9beff612c91d2749cccd 100644 (file)
@@ -2,7 +2,7 @@
 struct B;
 
 static S: &'static B = &A;
-//~^ ERROR calls in statics are limited to constant functions
+//~^ ERROR cannot perform deref coercion on `A` in statics
 
 use std::ops::Deref;
 
index d6eb3760cdf40366a965b290fb1098fc3575b3a5..5c35250bc3f39e86454a4b4a3ed4f4c0749d39b1 100644 (file)
@@ -1,8 +1,21 @@
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot perform deref coercion on `A` in statics
   --> $DIR/issue-25901.rs:4:24
    |
 LL | static S: &'static B = &A;
    |                        ^^
+   |
+   = note: attempting to deref into `B`
+note: deref defined here
+  --> $DIR/issue-25901.rs:10:5
+   |
+LL |     type Target = B;
+   |     ^^^^^^^^^^^^^^^^
+note: impl defined here, but it is not `const`
+  --> $DIR/issue-25901.rs:9:1
+   |
+LL | impl Deref for A {
+   | ^^^^^^^^^^^^^^^^
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
index 184f5cb26c54633c1795eb1c69e215ff5ad773cd..1241fb0b1f85f88bee59636c155911ea3e0fd0f5 100644 (file)
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-compare-mode-chalk
 #[derive(Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
 struct Array<T> {
     f00: [T; 00],
index f6b56610ec7d93d18ae832d4f0cb62093a49e4a4..8db9e00588564c3ca4c102feb72598ae6eb9429c 100644 (file)
@@ -1,10 +1,15 @@
 // run-pass
-// ignore-compare-mode-chalk
+
 struct Foo<A: Repr>(<A as Repr>::Data);
 
-impl<A> Copy for Foo<A> where <A as Repr>::Data: Copy { }
-impl<A> Clone for Foo<A> where <A as Repr>::Data: Clone {
-    fn clone(&self) -> Self { Foo(self.0.clone()) }
+impl<A> Copy for Foo<A> where <A as Repr>::Data: Copy {}
+impl<A> Clone for Foo<A>
+where
+    <A as Repr>::Data: Clone,
+{
+    fn clone(&self) -> Self {
+        Foo(self.0.clone())
+    }
 }
 
 trait Repr {
@@ -15,5 +20,4 @@ impl<A> Repr for A {
     type Data = u32;
 }
 
-fn main() {
-}
+fn main() {}
index dda6145e65adaf17bebb523a07a1c967ee5bb109..2697d46bdb2f42a510b6d12f7bf9c1a19abec2f0 100644 (file)
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `for<'a> (): Trait2<'a>` is not satisfied
-  --> $DIR/issue-35570.rs:8:4
+  --> $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 `()`
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'a> Trait2<'a>` is not implemented for `()`
 
 error: aborting due to previous error
 
index e0c47197eaa034427219ccc538f435f3920500d8..9cae6cf5e7665ced8faeb73dab67ad3676e0b3c0 100644 (file)
@@ -1,5 +1,4 @@
 // check-pass
-// ignore-compare-mode-chalk
 
 #![feature(associated_type_defaults)]
 
index 3d765daa7cdef1a5ffed4eca68131f192d891a1d..ea27e7bd2508f9ecc26f7bf14dd65577c2dcd5ba 100644 (file)
@@ -1,14 +1,18 @@
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<Dim3 as Dim>::dim` in constants
   --> $DIR/issue-39559-2.rs:14:24
    |
 LL |     let array: [usize; Dim3::dim()]
    |                        ^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<Dim3 as Dim>::dim` in constants
   --> $DIR/issue-39559-2.rs:16:15
    |
 LL |         = [0; Dim3::dim()];
    |               ^^^^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 2 previous errors
 
index c1a3084f30eae913a45cf42cee6afe236677e5f3..5809a56cd4b6b638d5f6811fd8b72d28aebae0ab 100644 (file)
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/issue-55796.rs:18:9
+  --> $DIR/issue-55796.rs:16:9
    |
 LL | pub trait Graph<'a> {
    |                 -- lifetime `'a` defined here
@@ -8,7 +8,7 @@ LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
 
 error: lifetime may not live long enough
-  --> $DIR/issue-55796.rs:23:9
+  --> $DIR/issue-55796.rs:21:9
    |
 LL | pub trait Graph<'a> {
    |                 -- lifetime `'a` defined here
index 1086669ee7463cb0c4bb7009f6c5eb6f87e21209..d802ce3b6cfbf88f70715c8436d79afd35c34e6a 100644 (file)
@@ -1,5 +1,3 @@
-// ignore-compare-mode-chalk
-
 pub trait EdgeTrait<N> {
     fn target(&self) -> N;
 }
@@ -16,12 +14,12 @@ pub trait Graph<'a> {
 
     fn out_neighbors(&'a self, u: &Self::Node) -> Box<dyn Iterator<Item = Self::Node>> {
         Box::new(self.out_edges(u).map(|e| e.target()))
-//~^ ERROR cannot infer
+        //~^ ERROR cannot infer
     }
 
     fn in_neighbors(&'a self, u: &Self::Node) -> Box<dyn Iterator<Item = Self::Node>> {
         Box::new(self.in_edges(u).map(|e| e.target()))
-//~^ ERROR cannot infer
+        //~^ ERROR cannot infer
     }
 }
 
index 304339657f0a96a5b4da1acec6a52973d182af8a..569a13f45bce8580fbd013d176e9bdf017e061fe 100644 (file)
@@ -1,22 +1,22 @@
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/issue-55796.rs:18:9
+  --> $DIR/issue-55796.rs:16:9
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/issue-55796.rs:7:17
+  --> $DIR/issue-55796.rs:5:17
    |
 LL | pub trait Graph<'a> {
    |                 ^^
-note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:18:40: 18:54]>` will meet its required lifetime bounds
-  --> $DIR/issue-55796.rs:18:9
+note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:16:40: 16:54]>` will meet its required lifetime bounds
+  --> $DIR/issue-55796.rs:16:9
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the types are compatible
-  --> $DIR/issue-55796.rs:18:9
+  --> $DIR/issue-55796.rs:16:9
    |
 LL |         Box::new(self.out_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,24 +24,24 @@ LL |         Box::new(self.out_edges(u).map(|e| e.target()))
               found `Box<dyn Iterator<Item = <Self as Graph<'a>>::Node>>`
 
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
-  --> $DIR/issue-55796.rs:23:9
+  --> $DIR/issue-55796.rs:21:9
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
-  --> $DIR/issue-55796.rs:7:17
+  --> $DIR/issue-55796.rs:5:17
    |
 LL | pub trait Graph<'a> {
    |                 ^^
-note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:23:39: 23:53]>` will meet its required lifetime bounds
-  --> $DIR/issue-55796.rs:23:9
+note: ...so that the type `Map<<Self as Graph<'a>>::EdgesIter, [closure@$DIR/issue-55796.rs:21:39: 21:53]>` will meet its required lifetime bounds
+  --> $DIR/issue-55796.rs:21:9
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: but, the lifetime must be valid for the static lifetime...
 note: ...so that the types are compatible
-  --> $DIR/issue-55796.rs:23:9
+  --> $DIR/issue-55796.rs:21:9
    |
 LL |         Box::new(self.in_edges(u).map(|e| e.target()))
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 44ea9f12d38ff8012f8a752e5ce1b7ccd6fafec2..36e9932602fb035ae668baa819915bbb57b88f7a 100644 (file)
@@ -1,6 +1,5 @@
 // build-pass
 // ignore-tidy-filelength
-// ignore-compare-mode-chalk
 #![crate_type = "rlib"]
 
 fn banana(v: &str) -> u32 {
index 4c6c83f2612f6bc5603d6eeead4d75b983af3729..9655108876f19f0c8a937ef96c0ca170361e540b 100644 (file)
@@ -1,4 +1,4 @@
-// compile-flags: -Zinstrument-coverage -Ccodegen-units=4 --crate-type dylib -Copt-level=0
+// compile-flags: -Cinstrument-coverage -Ccodegen-units=4 --crate-type dylib -Copt-level=0
 // build-pass
 // needs-profiler-support
 
diff --git a/src/test/ui/iterators/collect-into-slice.rs b/src/test/ui/iterators/collect-into-slice.rs
new file mode 100644 (file)
index 0000000..905752d
--- /dev/null
@@ -0,0 +1,15 @@
+fn process_slice(data: &[i32]) {
+    //~^ NOTE required by a bound in this
+    todo!()
+}
+
+fn main() {
+    let some_generated_vec = (0..10).collect();
+    //~^ ERROR the size for values of type `[i32]` cannot be known at compilation time
+    //~| ERROR a value of type `[i32]` cannot be built since `[i32]` has no definite size
+    //~| NOTE try explicitly collecting into a `Vec<{integer}>`
+    //~| NOTE required by a bound in `collect`
+    //~| NOTE all local variables must have a statically known size
+    //~| NOTE doesn't have a size known at compile-time
+    process_slice(&some_generated_vec);
+}
diff --git a/src/test/ui/iterators/collect-into-slice.stderr b/src/test/ui/iterators/collect-into-slice.stderr
new file mode 100644 (file)
index 0000000..521f239
--- /dev/null
@@ -0,0 +1,26 @@
+error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
+  --> $DIR/collect-into-slice.rs:7:9
+   |
+LL |     let some_generated_vec = (0..10).collect();
+   |         ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[i32]`
+   = note: all local variables must have a statically known size
+   = help: unsized locals are gated as an unstable feature
+
+error[E0277]: a value of type `[i32]` cannot be built since `[i32]` has no definite size
+  --> $DIR/collect-into-slice.rs:7:38
+   |
+LL |     let some_generated_vec = (0..10).collect();
+   |                                      ^^^^^^^ try explicitly collecting into a `Vec<{integer}>`
+   |
+   = help: the trait `FromIterator<{integer}>` is not implemented for `[i32]`
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+   |
+LL |     fn collect<B: FromIterator<Self::Item>>(self) -> B
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `collect`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 6977804708d5ea2f133097d88f1ced129895a57f..e147366a22410bf6e903f0639f4eae3468bdd3d4 100644 (file)
@@ -6,6 +6,10 @@ LL |     assert_copy::<&'static mut isize>();
    |
    = help: the following implementations were found:
              <isize as Copy>
+             <f32 as Copy>
+             <f64 as Copy>
+             <i128 as Copy>
+           and 10 others
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
    |
@@ -20,6 +24,10 @@ LL |     assert_copy::<&'a mut isize>();
    |
    = help: the following implementations were found:
              <isize as Copy>
+             <f32 as Copy>
+             <f64 as Copy>
+             <i128 as Copy>
+           and 10 others
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
    |
index ed129a1d13388189766ebed2270a0f565121972b..e6ff1f662bde9c9b85cd6ee359854cc865f640e9 100644 (file)
@@ -17,6 +17,10 @@ LL |     '\●'
    |       ^ unknown character escape
    |
    = help: for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals>
+help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal
+   |
+LL |     r"\●"
+   |     ~~~~~
 
 error: unknown character escape: `\u{25cf}`
   --> $DIR/lex-bad-char-literals-1.rs:14:7
@@ -25,6 +29,10 @@ LL |     "\●"
    |       ^ unknown character escape
    |
    = help: for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals>
+help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal
+   |
+LL |     r"\●"
+   |     ~~~~~
 
 error: aborting due to 4 previous errors
 
index 004ab386b3ff071d6a10b72f2c0337d023eee37d..57e5ab42f79d3a641d1406e9ccc9239aff81c003 100644 (file)
@@ -315,17 +315,17 @@ fn test_expr() {
     assert_eq!(stringify_expr!(mac! { ... }), "mac! { ... }");
 
     // ExprKind::Struct
-    assert_eq!(stringify_expr!(Struct {}), "Struct{}"); // FIXME
+    assert_eq!(stringify_expr!(Struct {}), "Struct {}");
     #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5151
-    assert_eq!(stringify_expr!(<Struct as Trait>::Type {}), "<Struct as Trait>::Type{}");
-    assert_eq!(stringify_expr!(Struct { .. }), "Struct{..}"); // FIXME
-    assert_eq!(stringify_expr!(Struct { ..base }), "Struct{..base}"); // FIXME
-    assert_eq!(stringify_expr!(Struct { x }), "Struct{x,}");
-    assert_eq!(stringify_expr!(Struct { x, .. }), "Struct{x, ..}");
-    assert_eq!(stringify_expr!(Struct { x, ..base }), "Struct{x, ..base}");
-    assert_eq!(stringify_expr!(Struct { x: true }), "Struct{x: true,}");
-    assert_eq!(stringify_expr!(Struct { x: true, .. }), "Struct{x: true, ..}");
-    assert_eq!(stringify_expr!(Struct { x: true, ..base }), "Struct{x: true, ..base}");
+    assert_eq!(stringify_expr!(<Struct as Trait>::Type {}), "<Struct as Trait>::Type {}");
+    assert_eq!(stringify_expr!(Struct { .. }), "Struct { .. }");
+    assert_eq!(stringify_expr!(Struct { ..base }), "Struct { ..base }");
+    assert_eq!(stringify_expr!(Struct { x }), "Struct { x }");
+    assert_eq!(stringify_expr!(Struct { x, .. }), "Struct { x, .. }");
+    assert_eq!(stringify_expr!(Struct { x, ..base }), "Struct { x, ..base }");
+    assert_eq!(stringify_expr!(Struct { x: true }), "Struct { x: true }");
+    assert_eq!(stringify_expr!(Struct { x: true, .. }), "Struct { x: true, .. }");
+    assert_eq!(stringify_expr!(Struct { x: true, ..base }), "Struct { x: true, ..base }");
 
     // ExprKind::Repeat
     assert_eq!(stringify_expr!([(); 0]), "[(); 0]");
diff --git a/src/test/ui/macros/unreachable-arg.edition_2021.stderr b/src/test/ui/macros/unreachable-arg.edition_2021.stderr
new file mode 100644 (file)
index 0000000..d70ef31
--- /dev/null
@@ -0,0 +1,13 @@
+error: format argument must be a string literal
+  --> $DIR/unreachable-arg.rs:15:18
+   |
+LL |     unreachable!(a);
+   |                  ^
+   |
+help: you might be missing a string literal to format with
+   |
+LL |     unreachable!("{}", a);
+   |                  +++++
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/unreachable-arg.rs b/src/test/ui/macros/unreachable-arg.rs
new file mode 100644 (file)
index 0000000..4024bd2
--- /dev/null
@@ -0,0 +1,16 @@
+// ignore-emscripten no processes
+
+// revisions: edition_2015 edition_2021
+// [edition_2015]edition:2015
+// [edition_2021]edition:2021
+// [edition_2015]run-fail
+// [edition_2021]check-fail
+// [edition_2015]error-pattern:internal error: entered unreachable code: hello
+// [edition_2021]error-pattern:format argument must be a string literal
+
+#![allow(non_fmt_panics)]
+
+fn main() {
+    let a = "hello";
+    unreachable!(a);
+}
diff --git a/src/test/ui/macros/unreachable-format-arg.rs b/src/test/ui/macros/unreachable-format-arg.rs
new file mode 100644 (file)
index 0000000..ff059ad
--- /dev/null
@@ -0,0 +1,15 @@
+// run-fail
+// ignore-emscripten no processes
+
+// revisions: edition_2015 edition_2021
+// [edition_2015]edition:2015
+// [edition_2021]edition:2021
+// [edition_2015]error-pattern:internal error: entered unreachable code: x is {x}
+// [edition_2021]error-pattern:internal error: entered unreachable code: x is 5
+
+#![allow(non_fmt_panics)]
+
+fn main() {
+    let x = 5;
+    unreachable!("x is {x}");
+}
diff --git a/src/test/ui/macros/unreachable-format-args.edition_2015.stderr b/src/test/ui/macros/unreachable-format-args.edition_2015.stderr
new file mode 100644 (file)
index 0000000..dda45d1
--- /dev/null
@@ -0,0 +1,12 @@
+error: there is no argument named `x`
+  --> $DIR/unreachable-format-args.rs:13:5
+   |
+LL |     unreachable!("x is {x} and y is {y}", y = 0);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: did you intend to capture a variable `x` from the surrounding scope?
+   = note: to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
+   = note: this error originates in the macro `$crate::concat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/macros/unreachable-format-args.rs b/src/test/ui/macros/unreachable-format-args.rs
new file mode 100644 (file)
index 0000000..04a31fc
--- /dev/null
@@ -0,0 +1,14 @@
+// ignore-emscripten no processes
+
+// revisions: edition_2015 edition_2021
+// [edition_2015]edition:2015
+// [edition_2021]edition:2021
+// [edition_2015]check-fail
+// [edition_2021]run-fail
+// [edition_2015]error-pattern:there is no argument named `x`
+// [edition_2021]error-pattern:internal error: entered unreachable code: x is 5 and y is 0
+
+fn main() {
+    let x = 5;
+    unreachable!("x is {x} and y is {y}", y = 0);
+}
index 7f91d5ed42ce4d6c446585c160b6af6ab8871ed1..6dbf24baf2315d8c05d7a3481fb96107b8062d0e 100644 (file)
@@ -99,6 +99,12 @@ error[E0604]: only `u8` can be cast as `char`, not `u32`
    |
 LL |     let _ = 0x61u32 as char;
    |             ^^^^^^^^^^^^^^^ invalid cast
+   |
+help: try `char::from_u32` instead
+  --> $DIR/cast-rfc0401.rs:41:13
+   |
+LL |     let _ = 0x61u32 as char;
+   |             ^^^^^^^^^^^^^^^
 
 error[E0606]: casting `bool` as `f32` is invalid
   --> $DIR/cast-rfc0401.rs:43:13
index 4519833b864867f106ff167242eb73fe9c436331..cebcca944af82b9ef1524ed622476f6dc393e080 100644 (file)
@@ -8,7 +8,7 @@ fn main() {
 
     [(); { for _ in 0usize.. {}; 0}];
     //~^ ERROR `for` is not allowed in a `const`
-    //~| ERROR calls in constants are limited to constant functions
+    //~| ERROR cannot convert
     //~| ERROR mutable references are not allowed in constants
-    //~| ERROR calls in constants are limited to constant functions
+    //~| ERROR cannot call non-const fn
 }
index 216b56f7059041da119ecd4accfe4addc0f00e9f..8c1755205f0253b82f6026b5d05f2508c4d831f0 100644 (file)
@@ -38,11 +38,18 @@ LL |     [(); loop { break }];
    |                 expected `usize`, found `()`
    |                 help: give it a value of the expected type: `break 42`
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot convert `RangeFrom<usize>` into an iterator in constants
   --> $DIR/issue-52443.rs:9:21
    |
 LL |     [(); { for _ in 0usize.. {}; 0}];
    |                     ^^^^^^^^
+   |
+note: impl defined here, but it is not `const`
+  --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+   |
+LL | impl<I: Iterator> IntoIterator for I {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error[E0658]: mutable references are not allowed in constants
   --> $DIR/issue-52443.rs:9:21
@@ -53,11 +60,13 @@ LL |     [(); { for _ in 0usize.. {}; 0}];
    = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
 
-error[E0015]: calls in constants are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<RangeFrom<usize> as Iterator>::next` in constants
   --> $DIR/issue-52443.rs:9:21
    |
 LL |     [(); { for _ in 0usize.. {}; 0}];
    |                     ^^^^^^^^
+   |
+   = note: calls in constants are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 6 previous errors; 1 warning emitted
 
index 9af5180343bf28c71a5a97589be702205da2fcd2..c834f8bd9c4f5b545c7e335b38f73c6670c21062 100644 (file)
@@ -4,7 +4,7 @@ error[E0658]: trait objects in const fn are unstable
 LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() }
    |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
+   = note: see issue #93706 <https://github.com/rust-lang/rust/issues/93706> for more information
    = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable
 
 error: aborting due to previous error
index d15e402460794c1e0b129a14074ebd9eeb483495..5109a0e4a683de41ab74b825f5589f5b709011dc 100644 (file)
@@ -1,16 +1,14 @@
 // Regression test for #53789.
 //
 // check-pass
-// ignore-compare-mode-chalk
 
+use std::cmp::Ord;
 use std::collections::BTreeMap;
 use std::ops::Range;
-use std::cmp::Ord;
 
 macro_rules! valuetree {
     () => {
-        type ValueTree =
-            <Self::Strategy as $crate::Strategy>::Value;
+        type ValueTree = <Self::Strategy as $crate::Strategy>::Value;
     };
 }
 
@@ -41,7 +39,9 @@ macro_rules! product_type {
 macro_rules! default {
     ($type: ty, $val: expr) => {
         impl Default for $type {
-            fn default() -> Self { $val.into() }
+            fn default() -> Self {
+                $val.into()
+            }
         }
     };
 }
@@ -90,21 +90,17 @@ trait ValueTree {
 }
 
 trait Strategy {
-    type Value : ValueTree;
+    type Value: ValueTree;
 }
 
 #[derive(Clone)]
-struct VecStrategy<T : Strategy> {
+struct VecStrategy<T: Strategy> {
     element: T,
     size: Range<usize>,
 }
 
-fn vec<T : Strategy>(element: T, size: Range<usize>)
-                     -> VecStrategy<T> {
-    VecStrategy {
-        element: element,
-        size: size,
-    }
+fn vec<T: Strategy>(element: T, size: Range<usize>) -> VecStrategy<T> {
+    VecStrategy { element: element, size: size }
 }
 
 type ValueFor<S> = <<S as Strategy>::Value as ValueTree>::Value;
@@ -124,7 +120,6 @@ trait Arbitrary<'a>: Sized {
 struct SizeBounds(Range<usize>);
 default!(SizeBounds, 0..100);
 
-
 impl From<Range<usize>> for SizeBounds {
     fn from(high: Range<usize>) -> Self {
         unimplemented!()
@@ -137,24 +132,26 @@ fn from(high: SizeBounds) -> Self {
     }
 }
 
-
-fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters)
-                                  -> StrategyType<'a, A> {
+fn any_with<'a, A: Arbitrary<'a>>(args: A::Parameters) -> StrategyType<'a, A> {
     unimplemented!()
 }
 
-impl<K: ValueTree, V: ValueTree> Strategy for (K, V) where
-    <K as ValueTree>::Value: Ord {
+impl<K: ValueTree, V: ValueTree> Strategy for (K, V)
+where
+    <K as ValueTree>::Value: Ord,
+{
     type Value = TupleValueTree<(K, V)>;
 }
 
-impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)> where
-    <K as ValueTree>::Value: Ord {
+impl<K: ValueTree, V: ValueTree> ValueTree for TupleValueTree<(K, V)>
+where
+    <K as ValueTree>::Value: Ord,
+{
     type Value = BTreeMapValueTree<K, V>;
 }
 
 #[derive(Clone)]
-struct VecValueTree<T : ValueTree> {
+struct VecValueTree<T: ValueTree> {
     elements: Vec<T>,
 }
 
@@ -185,8 +182,8 @@ impl<'a, A, B> Arbitrary<'a> for BTreeMap<A, B>
 where
     A: Arbitrary<'static> + Ord,
     B: Arbitrary<'static>,
-StrategyFor<A>: 'static,
-StrategyFor<B>: 'static,
+    StrategyFor<A>: 'static,
+    StrategyFor<B>: 'static,
 {
     valuetree!();
     type Parameters = RangedParams2<A::Parameters, B::Parameters>;
@@ -208,10 +205,14 @@ fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
     }
 }
 
-fn btree_map<K : Strategy + 'static, V : Strategy + 'static>
-    (key: K, value: V, size: Range<usize>)
-     -> BTreeMapStrategy<K, V>
-where ValueFor<K> : Ord {
+fn btree_map<K: Strategy + 'static, V: Strategy + 'static>(
+    key: K,
+    value: V,
+    size: Range<usize>,
+) -> BTreeMapStrategy<K, V>
+where
+    ValueFor<K>: Ord,
+{
     unimplemented!()
 }
 
@@ -245,4 +246,4 @@ pub fn new(source: S, fun: F) -> Self {
     }
 }
 
-fn main() { }
+fn main() {}
index 459198eec5a8e50c55919233daf59655e84e721f..983d6a06afada75c7edffd8500d13cacbf15bc7b 100644 (file)
@@ -6,7 +6,7 @@ LL |     with_signature(x, |mut y| Box::new(y.next()))
    |
    = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#2r), std::alloc::Global>,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
                (),
            ]
    = note: number of external vids: 3
@@ -42,7 +42,7 @@ LL |     with_signature(x, |mut y| Box::new(y.next()))
    |
    = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#2r), std::alloc::Global>,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#2r)>,
                (),
            ]
    = note: number of external vids: 3
@@ -69,7 +69,7 @@ LL |     with_signature(x, |mut y| Box::new(y.next()))
    |
    = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#3r), std::alloc::Global>,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
                (),
            ]
    = note: number of external vids: 4
@@ -105,7 +105,7 @@ LL |     with_signature(x, |mut y| Box::new(y.next()))
    |
    = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#3r), std::alloc::Global>,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn Anything + '_#3r)>,
                (),
            ]
    = note: number of external vids: 4
index 6e8b3021d330c9139fb1a6519c28558b3441ba89..88d73e7a729a92f5826d545af0bcf947c986f650 100644 (file)
@@ -6,7 +6,7 @@ LL |     with_signature(x, |y| y)
    |
    = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [
                i32,
-               extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r), std::alloc::Global>,
+               extern "rust-call" fn((std::boxed::Box<T>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>,
                (),
            ]
    = note: number of external vids: 3
index d226f4129aa826efd26360cc79fd940cb127a9fa..5191f1877a9eee221ad850e24fe7be65d3306ac9 100644 (file)
@@ -11,6 +11,7 @@ static S: &str = "{bla}";
 #[allow(unreachable_code)]
 fn main() {
     panic!("{}", "here's a brace: {"); //~ WARN panic message contains a brace
+    unreachable!("{}", "here's a brace: {"); //~ WARN panic message contains a brace
     std::panic!("{}", "another one: }"); //~ WARN panic message contains a brace
     core::panic!("{}", "Hello {}"); //~ WARN panic message contains an unused formatting placeholder
     assert!(false, "{}", "{:03x} {test} bla");
@@ -24,6 +25,8 @@ fn main() {
     debug_assert!(false, "{}", "{{}} bla"); //~ WARN panic message contains braces
     panic!("{}", C); //~ WARN panic message is not a string literal
     panic!("{}", S); //~ WARN panic message is not a string literal
+    unreachable!("{}", S); //~ WARN panic message is not a string literal
+    unreachable!("{}", S); //~ WARN panic message is not a string literal
     std::panic::panic_any(123); //~ WARN panic message is not a string literal
     core::panic!("{}", &*"abc"); //~ WARN panic message is not a string literal
     std::panic::panic_any(Some(123)); //~ WARN panic message is not a string literal
@@ -41,8 +44,10 @@ fn main() {
     }
 
     std::panic::panic_any(a!()); //~ WARN panic message is not a string literal
+    unreachable!("{}", a!()); //~ WARN panic message is not a string literal
 
     panic!("{}", 1); //~ WARN panic message is not a string literal
+    unreachable!("{}", 1); //~ WARN panic message is not a string literal
     assert!(false, "{}", 1); //~ WARN panic message is not a string literal
     debug_assert!(false, "{}", 1); //~ WARN panic message is not a string literal
 
index 2ffd7638ae0a04fa7e2e5179a1dd5fcbd29cf4b6..d0d06b79775949647b66c6150975e74573982b86 100644 (file)
@@ -11,6 +11,7 @@
 #[allow(unreachable_code)]
 fn main() {
     panic!("here's a brace: {"); //~ WARN panic message contains a brace
+    unreachable!("here's a brace: {"); //~ WARN panic message contains a brace
     std::panic!("another one: }"); //~ WARN panic message contains a brace
     core::panic!("Hello {}"); //~ WARN panic message contains an unused formatting placeholder
     assert!(false, "{:03x} {test} bla");
@@ -24,6 +25,8 @@ fn main() {
     debug_assert!(false, "{{}} bla"); //~ WARN panic message contains braces
     panic!(C); //~ WARN panic message is not a string literal
     panic!(S); //~ WARN panic message is not a string literal
+    unreachable!(S); //~ WARN panic message is not a string literal
+    unreachable!(S); //~ WARN panic message is not a string literal
     std::panic!(123); //~ WARN panic message is not a string literal
     core::panic!(&*"abc"); //~ WARN panic message is not a string literal
     panic!(Some(123)); //~ WARN panic message is not a string literal
@@ -41,8 +44,10 @@ macro_rules! a {
     }
 
     panic!(a!()); //~ WARN panic message is not a string literal
+    unreachable!(a!()); //~ WARN panic message is not a string literal
 
     panic!(format!("{}", 1)); //~ WARN panic message is not a string literal
+    unreachable!(format!("{}", 1)); //~ WARN panic message is not a string literal
     assert!(false, format!("{}", 1)); //~ WARN panic message is not a string literal
     debug_assert!(false, format!("{}", 1)); //~ WARN panic message is not a string literal
 
index f9e6d89513630c6211ae3a3248e818718c7119ed..3305e5cc9068d81d726ce34a59b6fb2561a6f5bb 100644 (file)
@@ -12,7 +12,19 @@ LL |     panic!("{}", "here's a brace: {");
    |            +++++
 
 warning: panic message contains a brace
-  --> $DIR/non-fmt-panic.rs:14:31
+  --> $DIR/non-fmt-panic.rs:14:35
+   |
+LL |     unreachable!("here's a brace: {");
+   |                                   ^
+   |
+   = note: this message is not used as a format string, but will be in Rust 2021
+help: add a "{}" format string to use the message literally
+   |
+LL |     unreachable!("{}", "here's a brace: {");
+   |                  +++++
+
+warning: panic message contains a brace
+  --> $DIR/non-fmt-panic.rs:15:31
    |
 LL |     std::panic!("another one: }");
    |                               ^
@@ -24,7 +36,7 @@ LL |     std::panic!("{}", "another one: }");
    |                 +++++
 
 warning: panic message contains an unused formatting placeholder
-  --> $DIR/non-fmt-panic.rs:15:25
+  --> $DIR/non-fmt-panic.rs:16:25
    |
 LL |     core::panic!("Hello {}");
    |                         ^^
@@ -40,7 +52,7 @@ LL |     core::panic!("{}", "Hello {}");
    |                  +++++
 
 warning: panic message contains unused formatting placeholders
-  --> $DIR/non-fmt-panic.rs:16:21
+  --> $DIR/non-fmt-panic.rs:17:21
    |
 LL |     assert!(false, "{:03x} {test} bla");
    |                     ^^^^^^ ^^^^^^
@@ -56,7 +68,7 @@ LL |     assert!(false, "{}", "{:03x} {test} bla");
    |                    +++++
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:18:20
+  --> $DIR/non-fmt-panic.rs:19:20
    |
 LL |     assert!(false, S);
    |                    ^
@@ -69,7 +81,7 @@ LL |     assert!(false, "{}", S);
    |                    +++++
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:20:20
+  --> $DIR/non-fmt-panic.rs:21:20
    |
 LL |     assert!(false, 123);
    |                    ^^^
@@ -82,7 +94,7 @@ LL |     assert!(false, "{}", 123);
    |                    +++++
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:22:20
+  --> $DIR/non-fmt-panic.rs:23:20
    |
 LL |     assert!(false, Some(123));
    |                    ^^^^^^^^^
@@ -95,7 +107,7 @@ LL |     assert!(false, "{:?}", Some(123));
    |                    +++++++
 
 warning: panic message contains braces
-  --> $DIR/non-fmt-panic.rs:24:27
+  --> $DIR/non-fmt-panic.rs:25:27
    |
 LL |     debug_assert!(false, "{{}} bla");
    |                           ^^^^
@@ -107,7 +119,7 @@ LL |     debug_assert!(false, "{}", "{{}} bla");
    |                          +++++
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:25:12
+  --> $DIR/non-fmt-panic.rs:26:12
    |
 LL |     panic!(C);
    |            ^
@@ -120,7 +132,7 @@ LL |     panic!("{}", C);
    |            +++++
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:26:12
+  --> $DIR/non-fmt-panic.rs:27:12
    |
 LL |     panic!(S);
    |            ^
@@ -133,7 +145,33 @@ LL |     panic!("{}", S);
    |            +++++
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:27:17
+  --> $DIR/non-fmt-panic.rs:28:18
+   |
+LL |     unreachable!(S);
+   |                  ^
+   |
+   = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+help: add a "{}" format string to Display the message
+   |
+LL |     unreachable!("{}", S);
+   |                  +++++
+
+warning: panic message is not a string literal
+  --> $DIR/non-fmt-panic.rs:29:18
+   |
+LL |     unreachable!(S);
+   |                  ^
+   |
+   = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+help: add a "{}" format string to Display the message
+   |
+LL |     unreachable!("{}", S);
+   |                  +++++
+
+warning: panic message is not a string literal
+  --> $DIR/non-fmt-panic.rs:30:17
    |
 LL |     std::panic!(123);
    |                 ^^^
@@ -150,7 +188,7 @@ LL |     std::panic::panic_any(123);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:28:18
+  --> $DIR/non-fmt-panic.rs:31:18
    |
 LL |     core::panic!(&*"abc");
    |                  ^^^^^^^
@@ -163,7 +201,7 @@ LL |     core::panic!("{}", &*"abc");
    |                  +++++
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:29:12
+  --> $DIR/non-fmt-panic.rs:32:12
    |
 LL |     panic!(Some(123));
    |            ^^^^^^^^^
@@ -180,7 +218,7 @@ LL |     std::panic::panic_any(Some(123));
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 warning: panic message contains an unused formatting placeholder
-  --> $DIR/non-fmt-panic.rs:30:12
+  --> $DIR/non-fmt-panic.rs:33:12
    |
 LL |     panic!(concat!("{", "}"));
    |            ^^^^^^^^^^^^^^^^^
@@ -196,7 +234,7 @@ LL |     panic!("{}", concat!("{", "}"));
    |            +++++
 
 warning: panic message contains braces
-  --> $DIR/non-fmt-panic.rs:31:5
+  --> $DIR/non-fmt-panic.rs:34:5
    |
 LL |     panic!(concat!("{", "{"));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -208,7 +246,7 @@ LL |     panic!("{}", concat!("{", "{"));
    |            +++++
 
 warning: panic message contains an unused formatting placeholder
-  --> $DIR/non-fmt-panic.rs:33:37
+  --> $DIR/non-fmt-panic.rs:36:37
    |
 LL |     fancy_panic::fancy_panic!("test {} 123");
    |                                     ^^
@@ -216,7 +254,7 @@ LL |     fancy_panic::fancy_panic!("test {} 123");
    = note: this message is not used as a format string when given without arguments, but will be in Rust 2021
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:43:12
+  --> $DIR/non-fmt-panic.rs:46:12
    |
 LL |     panic!(a!());
    |            ^^^^
@@ -233,7 +271,20 @@ LL |     std::panic::panic_any(a!());
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:45:12
+  --> $DIR/non-fmt-panic.rs:47:18
+   |
+LL |     unreachable!(a!());
+   |                  ^^^^
+   |
+   = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+help: add a "{}" format string to Display the message
+   |
+LL |     unreachable!("{}", a!());
+   |                  +++++
+
+warning: panic message is not a string literal
+  --> $DIR/non-fmt-panic.rs:49:12
    |
 LL |     panic!(format!("{}", 1));
    |            ^^^^^^^^^^^^^^^^
@@ -248,7 +299,22 @@ LL +     panic!("{}", 1);
    | 
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:46:20
+  --> $DIR/non-fmt-panic.rs:50:18
+   |
+LL |     unreachable!(format!("{}", 1));
+   |                  ^^^^^^^^^^^^^^^^
+   |
+   = note: this usage of unreachable!() is deprecated; it will be a hard error in Rust 2021
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
+   = note: the unreachable!() macro supports formatting, so there's no need for the format!() macro here
+help: remove the `format!(..)` macro call
+   |
+LL -     unreachable!(format!("{}", 1));
+LL +     unreachable!("{}", 1);
+   | 
+
+warning: panic message is not a string literal
+  --> $DIR/non-fmt-panic.rs:51:20
    |
 LL |     assert!(false, format!("{}", 1));
    |                    ^^^^^^^^^^^^^^^^
@@ -263,7 +329,7 @@ LL +     assert!(false, "{}", 1);
    | 
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:47:26
+  --> $DIR/non-fmt-panic.rs:52:26
    |
 LL |     debug_assert!(false, format!("{}", 1));
    |                          ^^^^^^^^^^^^^^^^
@@ -278,7 +344,7 @@ LL +     debug_assert!(false, "{}", 1);
    | 
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:49:12
+  --> $DIR/non-fmt-panic.rs:54:12
    |
 LL |     panic![123];
    |            ^^^
@@ -295,7 +361,7 @@ LL |     std::panic::panic_any(123);
    |     ~~~~~~~~~~~~~~~~~~~~~~   ~
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:50:12
+  --> $DIR/non-fmt-panic.rs:55:12
    |
 LL |     panic!{123};
    |            ^^^
@@ -312,7 +378,7 @@ LL |     std::panic::panic_any(123);
    |     ~~~~~~~~~~~~~~~~~~~~~~   ~
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:67:12
+  --> $DIR/non-fmt-panic.rs:72:12
    |
 LL |     panic!(v);
    |     ------ ^
@@ -323,7 +389,7 @@ LL |     panic!(v);
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:68:20
+  --> $DIR/non-fmt-panic.rs:73:20
    |
 LL |     assert!(false, v);
    |                    ^
@@ -332,7 +398,7 @@ LL |     assert!(false, v);
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:72:12
+  --> $DIR/non-fmt-panic.rs:77:12
    |
 LL |     panic!(v);
    |            ^
@@ -349,7 +415,7 @@ LL |     std::panic::panic_any(v);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:73:20
+  --> $DIR/non-fmt-panic.rs:78:20
    |
 LL |     assert!(false, v);
    |                    ^
@@ -362,7 +428,7 @@ LL |     assert!(false, "{:?}", v);
    |                    +++++++
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:77:12
+  --> $DIR/non-fmt-panic.rs:82:12
    |
 LL |     panic!(v);
    |            ^
@@ -379,7 +445,7 @@ LL |     std::panic::panic_any(v);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:78:20
+  --> $DIR/non-fmt-panic.rs:83:20
    |
 LL |     assert!(false, v);
    |                    ^
@@ -392,7 +458,7 @@ LL |     assert!(false, "{}", v);
    |                    +++++
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:82:12
+  --> $DIR/non-fmt-panic.rs:87:12
    |
 LL |     panic!(v);
    |            ^
@@ -409,7 +475,7 @@ LL |     std::panic::panic_any(v);
    |     ~~~~~~~~~~~~~~~~~~~~~
 
 warning: panic message is not a string literal
-  --> $DIR/non-fmt-panic.rs:83:20
+  --> $DIR/non-fmt-panic.rs:88:20
    |
 LL |     assert!(false, v);
    |                    ^
@@ -421,5 +487,5 @@ help: add a "{}" format string to Display the message
 LL |     assert!(false, "{}", v);
    |                    +++++
 
-warning: 30 warnings emitted
+warning: 35 warnings emitted
 
index 36549cbc554bfdd1a6b504989006afbb6c51750f..d4b39c670162de049294613d48660d5cf1f65862 100644 (file)
@@ -1,6 +1,6 @@
 // build-pass
 // ignore-pass
-// no-system-llvm
+// min-llvm-version: 14.0.0
 // revisions: all inline merge1 merge2
 // compile-flags: --crate-type=lib -Cdebuginfo=1 -Copt-level=2
 //
@@ -14,7 +14,7 @@
 // [merge1] compile-flags: -Cremark=all    -Cremark=giraffe
 // [merge2] compile-flags: -Cremark=inline -Cremark=giraffe
 //
-// error-pattern: inline: f not inlined into g
+// error-pattern: inline: 'f' not inlined into 'g'
 // dont-check-compiler-stderr
 
 #[no_mangle]
diff --git a/src/test/ui/panics/default-backtrace-ice.rs b/src/test/ui/panics/default-backtrace-ice.rs
new file mode 100644 (file)
index 0000000..fd86a3f
--- /dev/null
@@ -0,0 +1,9 @@
+// unset-rustc-env:RUST_BACKTRACE
+// compile-flags:-Z treat-err-as-bug=1
+// error-pattern:stack backtrace:
+// failure-status:101
+// normalize-stderr-test "note: .*" -> ""
+// normalize-stderr-test "thread 'rustc' .*" -> ""
+// normalize-stderr-test "  .*\n" -> ""
+
+fn main() { missing_ident; }
diff --git a/src/test/ui/panics/default-backtrace-ice.stderr b/src/test/ui/panics/default-backtrace-ice.stderr
new file mode 100644 (file)
index 0000000..a0025d7
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0425]: cannot find value `missing_ident` in this scope
+LL | fn main() { missing_ident; }
+
+
+stack backtrace:
+
+error: internal compiler error: unexpected panic
+
+
+
+
+
+
+
+
+
+query stack during panic:
+end of query stack
diff --git a/src/test/ui/parser/bad-escape-suggest-raw-string.rs b/src/test/ui/parser/bad-escape-suggest-raw-string.rs
new file mode 100644 (file)
index 0000000..978b92c
--- /dev/null
@@ -0,0 +1,7 @@
+fn main() {
+    let ok = r"ab\[c";
+    let bad = "ab\[c";
+    //~^ ERROR unknown character escape: `[`
+    //~| HELP for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals>
+    //~| HELP if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal
+}
diff --git a/src/test/ui/parser/bad-escape-suggest-raw-string.stderr b/src/test/ui/parser/bad-escape-suggest-raw-string.stderr
new file mode 100644 (file)
index 0000000..fc34bd3
--- /dev/null
@@ -0,0 +1,14 @@
+error: unknown character escape: `[`
+  --> $DIR/bad-escape-suggest-raw-string.rs:3:19
+   |
+LL |     let bad = "ab\[c";
+   |                   ^ unknown character escape
+   |
+   = help: for more information, visit <https://static.rust-lang.org/doc/master/reference.html#literals>
+help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal
+   |
+LL |     let bad = r"ab\[c";
+   |               ~~~~~~~~
+
+error: aborting due to previous error
+
index 5a29ce2221fc2c218b77664d36450fbf03e4201b..5f8d4315de829c48c21c2766f9a8c05ea23c4c1a 100644 (file)
@@ -4,7 +4,7 @@ error[E0703]: invalid ABI: found `invalid-ab_isize`
 LL |   "invalid-ab_isize"
    |   ^^^^^^^^^^^^^^^^^^ invalid ABI
    |
-   = help: valid ABIs: Rust, C, C-unwind, cdecl, stdcall, stdcall-unwind, fastcall, vectorcall, thiscall, thiscall-unwind, aapcs, win64, sysv64, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
+   = help: valid ABIs: Rust, C, C-unwind, cdecl, cdecl-unwind, stdcall, stdcall-unwind, fastcall, fastcall-unwind, vectorcall, vectorcall-unwind, thiscall, thiscall-unwind, aapcs, aapcs-unwind, win64, win64-unwind, sysv64, sysv64-unwind, ptx-kernel, msp430-interrupt, x86-interrupt, amdgpu-kernel, efiapi, avr-interrupt, avr-non-blocking-interrupt, C-cmse-nonsecure-call, wasm, system, system-unwind, rust-intrinsic, rust-call, platform-intrinsic, unadjusted
 
 error: aborting due to previous error
 
index 7be8b25363e09e750e294c98fe61bc5b40e0c364..261fcb5f9183e9a34b42b74ac1c1ecc95e44c556 100644 (file)
@@ -1,4 +1,15 @@
 fn main() {
     f<'a,>
     //~^ ERROR expected
+    //~| ERROR expected
+}
+
+fn bar(a: usize, b: usize) -> usize {
+    a + b
+}
+
+fn foo() {
+    let x = 1;
+    bar('y, x);
+    //~^ ERROR expected
 }
index 20e6c3ed8a8d5d7a45e053c8717a1d46040ff76a..900f21a7ccef461ae7465a9c8f3d846439dadd5e 100644 (file)
@@ -1,3 +1,9 @@
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/issue-93282.rs:2:9
+   |
+LL |     f<'a,>
+   |         ^ expected `while`, `for`, `loop` or `{` after a label
+
 error: expected one of `.`, `:`, `;`, `?`, `for`, `loop`, `while`, `{`, `}`, or an operator, found `,`
   --> $DIR/issue-93282.rs:2:9
    |
@@ -9,5 +15,11 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
 LL |     f::<'a,>
    |      ++
 
-error: aborting due to previous error
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/issue-93282.rs:13:11
+   |
+LL |     bar('y, x);
+   |           ^ expected `while`, `for`, `loop` or `{` after a label
+
+error: aborting due to 3 previous errors
 
index 68636f6b907ef7448d2dc922408ff2f544a424d8..f29fd7a5472d45ce75e870a02b78979c0e94f921 100644 (file)
@@ -22,10 +22,12 @@ fn main() {
     let _ = f<'_, i8>();
     //~^ ERROR expected one of
     //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+    //~| ERROR expected
 
     f<'_>();
     //~^ comparison operators cannot be chained
     //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+    //~| ERROR expected
 
     let _ = f<u8>;
     //~^ ERROR comparison operators cannot be chained
index cde6f8c674f4b5c53c61a5e43c70f046456a7f83..92d700753dc1b24665bce4e45eb9e056f363e215 100644 (file)
@@ -53,6 +53,12 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
 LL |     let _ = f::<u8, i8>();
    |              ++
 
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/require-parens-for-chained-comparison.rs:22:17
+   |
+LL |     let _ = f<'_, i8>();
+   |                 ^ expected `while`, `for`, `loop` or `{` after a label
+
 error: expected one of `.`, `:`, `;`, `?`, `else`, `for`, `loop`, `while`, `{`, or an operator, found `,`
   --> $DIR/require-parens-for-chained-comparison.rs:22:17
    |
@@ -64,8 +70,14 @@ help: use `::<...>` instead of `<...>` to specify lifetime, type, or const argum
 LL |     let _ = f::<'_, i8>();
    |              ++
 
+error: expected `while`, `for`, `loop` or `{` after a label
+  --> $DIR/require-parens-for-chained-comparison.rs:27:9
+   |
+LL |     f<'_>();
+   |         ^ expected `while`, `for`, `loop` or `{` after a label
+
 error: comparison operators cannot be chained
-  --> $DIR/require-parens-for-chained-comparison.rs:26:6
+  --> $DIR/require-parens-for-chained-comparison.rs:27:6
    |
 LL |     f<'_>();
    |      ^  ^
@@ -76,7 +88,7 @@ LL |     f::<'_>();
    |      ++
 
 error: comparison operators cannot be chained
-  --> $DIR/require-parens-for-chained-comparison.rs:30:14
+  --> $DIR/require-parens-for-chained-comparison.rs:32:14
    |
 LL |     let _ = f<u8>;
    |              ^  ^
@@ -84,5 +96,5 @@ LL |     let _ = f<u8>;
    = 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 8 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/pin-macro/cant_access_internals.rs b/src/test/ui/pin-macro/cant_access_internals.rs
new file mode 100644 (file)
index 0000000..120d088
--- /dev/null
@@ -0,0 +1,13 @@
+// edition:2018
+#![feature(pin_macro)]
+
+use core::{
+    marker::PhantomPinned,
+    mem,
+    pin::{pin, Pin},
+};
+
+fn main() {
+    let mut phantom_pinned = pin!(PhantomPinned);
+    mem::take(phantom_pinned.pointer); //~ ERROR use of unstable library feature 'unsafe_pin_internals'
+}
diff --git a/src/test/ui/pin-macro/cant_access_internals.stderr b/src/test/ui/pin-macro/cant_access_internals.stderr
new file mode 100644 (file)
index 0000000..060c9c4
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0658]: use of unstable library feature 'unsafe_pin_internals'
+  --> $DIR/cant_access_internals.rs:12:15
+   |
+LL |     mem::take(phantom_pinned.pointer);
+   |               ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(unsafe_pin_internals)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs b/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs
new file mode 100644 (file)
index 0000000..ca2b6cf
--- /dev/null
@@ -0,0 +1,29 @@
+// edition:2018
+#![feature(pin_macro)]
+
+use core::{
+    convert::identity,
+    marker::PhantomPinned,
+    mem::drop as stuff,
+    pin::pin,
+};
+
+fn function_call_stops_borrow_extension() {
+    let phantom_pinned = identity(pin!(PhantomPinned));
+    //~^ ERROR temporary value dropped while borrowed
+    stuff(phantom_pinned)
+}
+
+fn promotion_only_works_for_the_innermost_block() {
+    let phantom_pinned = {
+        let phantom_pinned = pin!(PhantomPinned);
+        //~^ ERROR temporary value dropped while borrowed
+        phantom_pinned
+    };
+    stuff(phantom_pinned)
+}
+
+fn main() {
+    function_call_stops_borrow_extension();
+    promotion_only_works_for_the_innermost_block();
+}
diff --git a/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr b/src/test/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr
new file mode 100644 (file)
index 0000000..4971263
--- /dev/null
@@ -0,0 +1,31 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/lifetime_errors_on_promotion_misusage.rs:12:35
+   |
+LL |     let phantom_pinned = identity(pin!(PhantomPinned));
+   |                                   ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
+   |                                   |
+   |                                   creates a temporary which is freed while still in use
+LL |
+LL |     stuff(phantom_pinned)
+   |           -------------- borrow later used here
+   |
+   = note: consider using a `let` binding to create a longer lived value
+   = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/lifetime_errors_on_promotion_misusage.rs:19:30
+   |
+LL |     let phantom_pinned = {
+   |         -------------- borrow later stored here
+LL |         let phantom_pinned = pin!(PhantomPinned);
+   |                              ^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
+...
+LL |     };
+   |     - temporary value is freed at the end of this statement
+   |
+   = note: consider using a `let` binding to create a longer lived value
+   = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
index a648d6b6d4b54d92f103161d6586ebedc29fd4fd..ec54851fcf9d7c4dae3ad885c867d1bc06070478 100644 (file)
@@ -32,9 +32,7 @@ fn main() {
                                             lit.set_span(crate::Span::recover_proc_macro_span(2));
                                             lit
                                         } else {
-                                           {
-                                               ::core::panicking::panic("internal error: entered unreachable code")
-                                           }
+                                           ::core::panicking::panic("internal error: entered unreachable code")
                                        }
                                 })),
                         crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3b}',
diff --git a/src/test/ui/ptr_ops/issue-80309-safe.rs b/src/test/ui/ptr_ops/issue-80309-safe.rs
new file mode 100644 (file)
index 0000000..ca3778a
--- /dev/null
@@ -0,0 +1,17 @@
+// run-pass
+// min-llvm-version: 13.0
+// compiler-flags: -O
+
+// Regression test for issue #80309
+
+pub fn zero(x: usize) -> usize {
+    std::ptr::null::<i8>().wrapping_add(x) as usize - x
+}
+pub fn qux(x: &[i8]) -> i8 {
+    x[zero(x.as_ptr() as usize)]
+}
+
+fn main() {
+    let z = vec![42, 43];
+    println!("{}", qux(&z));
+}
diff --git a/src/test/ui/ptr_ops/issue-80309.rs b/src/test/ui/ptr_ops/issue-80309.rs
new file mode 100644 (file)
index 0000000..bbec101
--- /dev/null
@@ -0,0 +1,14 @@
+// run-pass
+// min-llvm-version: 13.0
+// compiler-flags: -O
+
+// Regression test for issue #80309
+
+pub unsafe fn foo(x: *const i8) -> i8 {
+    *x.wrapping_sub(x as _).wrapping_add(x as _)
+}
+
+fn main() {
+    let x = 42;
+    println!("{}", unsafe { foo(&x) });
+}
index 44ef13c740c061ba150e5659ed4b4fc7971da33e..6844e86653299c00810f2b600408e18710338e72 100644 (file)
@@ -1,8 +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:4
+  --> $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 >)
-   |    ^^^^^^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
+   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'z> Trait2<'y, 'z>` is not implemented for `T`
    |
 help: consider restricting type parameter `T`
    |
index 707b38cf37af0f3bd1796c4aa858ebdf0aaaeea4..49d72158e92ba8a813d451b2f29937b764edd16c 100644 (file)
@@ -1,6 +1,6 @@
 [$DIR/dbg-macro-expected-behavior.rs:20] Unit = Unit
 [$DIR/dbg-macro-expected-behavior.rs:21] a = Unit
-[$DIR/dbg-macro-expected-behavior.rs:27] Point{x: 42, y: 24,} = Point {
+[$DIR/dbg-macro-expected-behavior.rs:27] Point { x: 42, y: 24 } = Point {
     x: 42,
     y: 24,
 }
index 33e839fd1203d51b5e70e6d9aa0e24e79df29a91..24b9235bb9a76fe28359c1bbaa9604b367e53a44 100644 (file)
@@ -22,7 +22,8 @@ pub const fn add_i32(a: i32, b: i32) -> i32 {
 
 pub const fn add_u32(a: u32, b: u32) -> u32 {
     a.plus(b)
-    //~^ ERROR calls in constant functions are limited to constant functions
+    //~^ ERROR the trait bound
+    //~| ERROR cannot call non-const fn
 }
 
 fn main() {}
index 5a73c4debb481d0bfe1c47bb657c2490c9ed5692..1fc9db277610e5a45c483fe8ef6f8e04274816b6 100644 (file)
@@ -1,9 +1,24 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/call-const-trait-method-fail.rs:24:5
+error[E0277]: the trait bound `u32: ~const Plus` is not satisfied
+  --> $DIR/call-const-trait-method-fail.rs:24:7
    |
 LL |     a.plus(b)
-   |     ^^^^^^^^^
+   |       ^^^^^^^ the trait `~const Plus` is not implemented for `u32`
+   |
+note: the trait `Plus` is implemented for `u32`, but that implementation is not `const`
+  --> $DIR/call-const-trait-method-fail.rs:24:7
+   |
+LL |     a.plus(b)
+   |       ^^^^^^^
+
+error[E0015]: cannot call non-const fn `<u32 as Plus>::plus` in constant functions
+  --> $DIR/call-const-trait-method-fail.rs:24:7
+   |
+LL |     a.plus(b)
+   |       ^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
index e96249ff2fd5a4710f2c9b68166e438e136dc9f0..e81e0d1e571c32283e6ad127683f2c8fb97d363c 100644 (file)
@@ -3,7 +3,8 @@
 
 pub const fn equals_self<T: PartialEq>(t: &T) -> bool {
     *t == *t
-    //~^ ERROR calls in constant functions are limited to constant functions
+    //~^ ERROR can't compare
+    //~| ERROR cannot call non-const
 }
 
 fn main() {}
index 818c582869631f9bc70f22b5be7077b0d34955a7..3963f64ad32b3b90b59cb9f2b9ae9b7588012b38 100644 (file)
@@ -1,9 +1,28 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0277]: can't compare `T` with `T` in const contexts
+  --> $DIR/call-generic-method-fail.rs:5:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^ no implementation for `T == T`
+   |
+note: the trait `PartialEq` is implemented for `T`, but that implementation is not `const`
   --> $DIR/call-generic-method-fail.rs:5:5
    |
 LL |     *t == *t
    |     ^^^^^^^^
 
-error: aborting due to previous error
+error[E0015]: cannot call non-const operator in constant functions
+  --> $DIR/call-generic-method-fail.rs:5:5
+   |
+LL |     *t == *t
+   |     ^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+help: consider further restricting this bound
+   |
+LL | pub const fn equals_self<T: PartialEq + ~const std::cmp::PartialEq>(t: &T) -> bool {
+   |                                       ++++++++++++++++++++++++++++
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
index 3a7074163523b0dab00be8a7c79ec3ebf47031d3..b3e3dd62be804bfa406e7e432f989e2486499cd0 100644 (file)
@@ -9,7 +9,7 @@ fn non_const() {}
 
 impl const T for S {
     fn foo() { non_const() }
-    //~^ ERROR calls in constant functions
+    //~^ ERROR cannot call non-const fn
 }
 
 fn main() {}
index aaec67161a6afe241b7eaee1a55cc7ec3b7f6f7e..9e49785c589e16516a6aaa5ea2cfe1213de21061 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `non_const` in constant functions
   --> $DIR/const-check-fns-in-const-impl.rs:11:16
    |
 LL |     fn foo() { non_const() }
    |                ^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
index 7a0db9c98ea61d53d8b7135b3429b114218515a2..3e87787a09195aedbdbc0fe420f33aad50a95663 100644 (file)
@@ -23,7 +23,8 @@ fn b(self) {}
 
 const fn test() {
     NonConstImpl.a();
-    //~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple variants
+    //~^ ERROR the trait bound
+    //~| ERROR cannot call non-const fn
     ConstImpl.a();
 }
 
index 63e4095af29437295bb6bc8a63b28326bba2a94b..948830d6def58f7388ccf8d5859f74fe410947cd 100644 (file)
@@ -1,9 +1,24 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/const-default-method-bodies.rs:25:5
+error[E0277]: the trait bound `NonConstImpl: ~const ConstDefaultFn` is not satisfied
+  --> $DIR/const-default-method-bodies.rs:25:18
    |
 LL |     NonConstImpl.a();
-   |     ^^^^^^^^^^^^^^^^
+   |                  ^^^ the trait `~const ConstDefaultFn` is not implemented for `NonConstImpl`
+   |
+note: the trait `ConstDefaultFn` is implemented for `NonConstImpl`, but that implementation is not `const`
+  --> $DIR/const-default-method-bodies.rs:25:18
+   |
+LL |     NonConstImpl.a();
+   |                  ^^^
+
+error[E0015]: cannot call non-const fn `<NonConstImpl as ConstDefaultFn>::a` in constant functions
+  --> $DIR/const-default-method-bodies.rs:25:18
+   |
+LL |     NonConstImpl.a();
+   |                  ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
index 3f553a8ee70793d26d3a4f48d1c51fdb1a6974fb..3ca9abb139b86e03753ef05983a639b40360af8b 100644 (file)
@@ -1,9 +1,24 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/cross-crate.rs:15:5
+error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
+  --> $DIR/cross-crate.rs:15:14
    |
 LL |     NonConst.func();
-   |     ^^^^^^^^^^^^^^^
+   |              ^^^^^^ the trait `~const cross_crate::MyTrait` is not implemented for `cross_crate::NonConst`
+   |
+note: the trait `cross_crate::MyTrait` is implemented for `cross_crate::NonConst`, but that implementation is not `const`
+  --> $DIR/cross-crate.rs:15:14
+   |
+LL |     NonConst.func();
+   |              ^^^^^^
+
+error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:15:14
+   |
+LL |     NonConst.func();
+   |              ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
index 4bd3359947d948729c35569d4be29bfc912ad8db..fa049ab86ff49c0b1016760e0e3618e7cf4b5463 100644 (file)
@@ -12,10 +12,10 @@ fn non_const_context() {
 }
 
 const fn const_context() {
-    NonConst.func();
-    //~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+    NonConst.func(); //~ ERROR: cannot call non-const fn
+    //[gated]~^ ERROR: the trait bound
     Const.func();
-    //[stock]~^ ERROR: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+    //[stock]~^ ERROR: cannot call non-const fn
 }
 
 fn main() {}
index 9908f47a7b28858b0c717963e2cb936f74e35380..ea75ad0aeaf8c2eba9b92532aa86fa856f9a9833 100644 (file)
@@ -1,14 +1,18 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/cross-crate.rs:15:5
+error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:15:14
    |
 LL |     NonConst.func();
-   |     ^^^^^^^^^^^^^^^
+   |              ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/cross-crate.rs:17:5
+error[E0015]: cannot call non-const fn `<cross_crate::Const as cross_crate::MyTrait>::func` in constant functions
+  --> $DIR/cross-crate.rs:17:11
    |
 LL |     Const.func();
-   |     ^^^^^^^^^^^^
+   |           ^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to 2 previous errors
 
index cccb856c2f675f4c71a95ef72aafb04e11ea6926..4d087b5180be4c29cf259a646ecf83181eae0eaf 100644 (file)
@@ -8,7 +8,8 @@ fn a(&self) {}
     #[default_method_body_is_const]
     fn b(&self) {
         ().a()
-        //~^ ERROR calls in constant functions are limited
+        //~^ ERROR the trait bound
+        //~| ERROR cannot call
     }
 }
 
index 91f4d2fd4b0e847a466caea09db4627d19e2f3e7..db4d61f88ab2f08a85e66bae320e31da06633aa5 100644 (file)
@@ -1,9 +1,24 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
-  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:9
+error[E0277]: the trait bound `(): ~const Tr` is not satisfied
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
    |
 LL |         ().a()
-   |         ^^^^^^
+   |            ^^^ the trait `~const Tr` is not implemented for `()`
+   |
+note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+   |
+LL |         ().a()
+   |            ^^^
+
+error[E0015]: cannot call non-const fn `<() as Tr>::a` in constant functions
+  --> $DIR/default-method-body-is-const-same-trait-ck.rs:10:12
+   |
+LL |         ().a()
+   |            ^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
index 157005bba7b7593782f11a4ca5627b9d85a38731..cbe3fe0ce5f3f461be5606e7687de5ef0ce92459 100644 (file)
@@ -7,7 +7,8 @@ pub trait A {
 
 pub const fn foo<T: A>() -> bool {
     T::assoc()
-    //~^ ERROR calls in constant functions are limited
+    //~^ ERROR the trait bound
+    //~| ERROR cannot call non-const fn
 }
 
 fn main() {}
index 931baac5389e6fbf69afa85354a022482f38033e..931c0b3658fd9d4f0d26e30a29ca46fbc36b0256 100644 (file)
@@ -1,9 +1,24 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0277]: the trait bound `T: ~const A` is not satisfied
+  --> $DIR/issue-88155.rs:9:5
+   |
+LL |     T::assoc()
+   |     ^^^^^^^^^^ the trait `~const A` is not implemented for `T`
+   |
+note: the trait `A` is implemented for `T`, but that implementation is not `const`
+  --> $DIR/issue-88155.rs:9:5
+   |
+LL |     T::assoc()
+   |     ^^^^^^^^^^
+
+error[E0015]: cannot call non-const fn `<T as A>::assoc` in constant functions
   --> $DIR/issue-88155.rs:9:5
    |
 LL |     T::assoc()
    |     ^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0015`.
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
index c6975da7121f9a80765ff70dc5424ed094e63e9a..2f54c09e31c9e023d5e31966b3f89f72762e8727 100644 (file)
@@ -11,7 +11,7 @@ fn non_const_context() -> Vec<usize> {
 
 const fn const_context() -> Vec<usize> {
     Default::default()
-    //[stock]~^ ERROR calls in constant functions are limited
+    //[stock]~^ ERROR cannot call non-const fn
 }
 
 fn main() {
index 55a0daaaec7bda40771f4457f9437eaa1a5e94d2..0b450a9474282bc5502f9ec2333e585b089da1cd 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `<Vec<usize> as Default>::default` in constant functions
   --> $DIR/std-impl-gate.rs:13:5
    |
 LL |     Default::default()
    |     ^^^^^^^^^^^^^^^^^^
+   |
+   = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.rs b/src/test/ui/specialization/deafult-associated-type-bound-1.rs
deleted file mode 100644 (file)
index 6eb2aa9..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Check that we check that default associated types satisfy the required
-// bounds on them.
-// ignore-compare-mode-chalk
-
-#![feature(specialization)]
-//~^ WARNING `specialization` is incomplete
-
-trait X {
-    type U: Clone;
-    fn unsafe_clone(&self, x: Option<&Self::U>) {
-        x.cloned();
-    }
-}
-
-// We cannot normalize `<T as X>::U` to `str` here, because the default could
-// be overridden. The error here must therefore be found by a method other than
-// normalization.
-impl<T> X for T {
-    default type U = str;
-    //~^ ERROR the trait bound `str: Clone` is not satisfied
-}
-
-pub fn main() {
-    1.unsafe_clone(None);
-}
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr
deleted file mode 100644 (file)
index 9e400f8..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/deafult-associated-type-bound-1.rs:5:12
-   |
-LL | #![feature(specialization)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
-   = help: consider using `min_specialization` instead, which is more stable and complete
-
-error[E0277]: the trait bound `str: Clone` is not satisfied
-  --> $DIR/deafult-associated-type-bound-1.rs:19:22
-   |
-LL |     default type U = str;
-   |                      ^^^ the trait `Clone` is not implemented for `str`
-   |
-note: required by a bound in `X::U`
-  --> $DIR/deafult-associated-type-bound-1.rs:9:13
-   |
-LL |     type U: Clone;
-   |             ^^^^^ required by this bound in `X::U`
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.rs b/src/test/ui/specialization/deafult-associated-type-bound-2.rs
deleted file mode 100644 (file)
index 0a21b1f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Check that generic predicates are also checked for default associated types.
-#![feature(specialization)]
-//~^ WARNING `specialization` is incomplete
-
-trait X<T> {
-    type U: PartialEq<T>;
-    fn unsafe_compare(x: Option<Self::U>, y: Option<T>) {
-        match (x, y) {
-            (Some(a), Some(b)) => a == b,
-            _ => false,
-        };
-    }
-}
-
-impl<B: 'static, T> X<B> for T {
-    default type U = &'static B;
-    //~^ ERROR can't compare `&'static B` with `B`
-}
-
-pub fn main() {
-    <i32 as X<i32>>::unsafe_compare(None, None);
-}
diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr
deleted file mode 100644 (file)
index 47ea69d..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/deafult-associated-type-bound-2.rs:2:12
-   |
-LL | #![feature(specialization)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
-   = help: consider using `min_specialization` instead, which is more stable and complete
-
-error[E0277]: can't compare `&'static B` with `B`
-  --> $DIR/deafult-associated-type-bound-2.rs:16:22
-   |
-LL |     default type U = &'static B;
-   |                      ^^^^^^^^^^ no implementation for `&'static B == B`
-   |
-   = help: the trait `PartialEq<B>` is not implemented for `&'static B`
-note: required by a bound in `X::U`
-  --> $DIR/deafult-associated-type-bound-2.rs:6:13
-   |
-LL |     type U: PartialEq<T>;
-   |             ^^^^^^^^^^^^ required by this bound in `X::U`
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
-   |
-LL | impl<B: 'static, T> X<B> for T where &'static B: PartialEq<B> {
-   |                                ++++++++++++++++++++++++++++++
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.rs b/src/test/ui/specialization/deafult-generic-associated-type-bound.rs
deleted file mode 100644 (file)
index 0f5714e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// Check that default generics associated types are validated.
-
-#![feature(specialization)]
-#![feature(generic_associated_types)]
-//~^^ WARNING `specialization` is incomplete
-
-trait X {
-    type U<'a>: PartialEq<&'a Self> where Self: 'a;
-    fn unsafe_compare<'b>(x: Option<Self::U<'b>>, y: Option<&'b Self>) {
-        match (x, y) {
-            (Some(a), Some(b)) => a == b,
-            _ => false,
-        };
-    }
-}
-
-impl<T: 'static> X for T {
-    default type U<'a> = &'a T;
-    //~^ ERROR can't compare `T` with `T`
-}
-
-struct NotComparable;
-
-pub fn main() {
-    <NotComparable as X>::unsafe_compare(None, None);
-}
diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr
deleted file mode 100644 (file)
index da5fe97..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/deafult-generic-associated-type-bound.rs:3:12
-   |
-LL | #![feature(specialization)]
-   |            ^^^^^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
-   = help: consider using `min_specialization` instead, which is more stable and complete
-
-error[E0277]: can't compare `T` with `T`
-  --> $DIR/deafult-generic-associated-type-bound.rs:18:26
-   |
-LL |     default type U<'a> = &'a T;
-   |                          ^^^^^ no implementation for `T == T`
-   |
-   = note: required because of the requirements on the impl of `PartialEq` for `&'a T`
-note: required by a bound in `X::U`
-  --> $DIR/deafult-generic-associated-type-bound.rs:8:17
-   |
-LL |     type U<'a>: PartialEq<&'a Self> where Self: 'a;
-   |                 ^^^^^^^^^^^^^^^^^^^ required by this bound in `X::U`
-help: consider further restricting this bound
-   |
-LL | impl<T: 'static + std::cmp::PartialEq> X for T {
-   |                 +++++++++++++++++++++
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/specialization/default-associated-type-bound-1.rs b/src/test/ui/specialization/default-associated-type-bound-1.rs
new file mode 100644 (file)
index 0000000..c043114
--- /dev/null
@@ -0,0 +1,24 @@
+// Check that we check that default associated types satisfy the required
+// bounds on them.
+
+#![feature(specialization)]
+//~^ WARNING `specialization` is incomplete
+
+trait X {
+    type U: Clone;
+    fn unsafe_clone(&self, x: Option<&Self::U>) {
+        x.cloned();
+    }
+}
+
+// We cannot normalize `<T as X>::U` to `str` here, because the default could
+// be overridden. The error here must therefore be found by a method other than
+// normalization.
+impl<T> X for T {
+    default type U = str;
+    //~^ ERROR the trait bound `str: Clone` is not satisfied
+}
+
+pub fn main() {
+    1.unsafe_clone(None);
+}
diff --git a/src/test/ui/specialization/default-associated-type-bound-1.stderr b/src/test/ui/specialization/default-associated-type-bound-1.stderr
new file mode 100644 (file)
index 0000000..f88acfb
--- /dev/null
@@ -0,0 +1,27 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/default-associated-type-bound-1.rs:4:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+
+error[E0277]: the trait bound `str: Clone` is not satisfied
+  --> $DIR/default-associated-type-bound-1.rs:18:22
+   |
+LL |     default type U = str;
+   |                      ^^^ the trait `Clone` is not implemented for `str`
+   |
+   = help: the following implementations were found:
+             <String as Clone>
+note: required by a bound in `X::U`
+  --> $DIR/default-associated-type-bound-1.rs:8:13
+   |
+LL |     type U: Clone;
+   |             ^^^^^ required by this bound in `X::U`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/specialization/default-associated-type-bound-2.rs b/src/test/ui/specialization/default-associated-type-bound-2.rs
new file mode 100644 (file)
index 0000000..0a21b1f
--- /dev/null
@@ -0,0 +1,22 @@
+// Check that generic predicates are also checked for default associated types.
+#![feature(specialization)]
+//~^ WARNING `specialization` is incomplete
+
+trait X<T> {
+    type U: PartialEq<T>;
+    fn unsafe_compare(x: Option<Self::U>, y: Option<T>) {
+        match (x, y) {
+            (Some(a), Some(b)) => a == b,
+            _ => false,
+        };
+    }
+}
+
+impl<B: 'static, T> X<B> for T {
+    default type U = &'static B;
+    //~^ ERROR can't compare `&'static B` with `B`
+}
+
+pub fn main() {
+    <i32 as X<i32>>::unsafe_compare(None, None);
+}
diff --git a/src/test/ui/specialization/default-associated-type-bound-2.stderr b/src/test/ui/specialization/default-associated-type-bound-2.stderr
new file mode 100644 (file)
index 0000000..0fd1f65
--- /dev/null
@@ -0,0 +1,30 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/default-associated-type-bound-2.rs:2:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+
+error[E0277]: can't compare `&'static B` with `B`
+  --> $DIR/default-associated-type-bound-2.rs:16:22
+   |
+LL |     default type U = &'static B;
+   |                      ^^^^^^^^^^ no implementation for `&'static B == B`
+   |
+   = help: the trait `PartialEq<B>` is not implemented for `&'static B`
+note: required by a bound in `X::U`
+  --> $DIR/default-associated-type-bound-2.rs:6:13
+   |
+LL |     type U: PartialEq<T>;
+   |             ^^^^^^^^^^^^ required by this bound in `X::U`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | impl<B: 'static, T> X<B> for T where &'static B: PartialEq<B> {
+   |                                ++++++++++++++++++++++++++++++
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/specialization/default-generic-associated-type-bound.rs b/src/test/ui/specialization/default-generic-associated-type-bound.rs
new file mode 100644 (file)
index 0000000..0f5714e
--- /dev/null
@@ -0,0 +1,26 @@
+// Check that default generics associated types are validated.
+
+#![feature(specialization)]
+#![feature(generic_associated_types)]
+//~^^ WARNING `specialization` is incomplete
+
+trait X {
+    type U<'a>: PartialEq<&'a Self> where Self: 'a;
+    fn unsafe_compare<'b>(x: Option<Self::U<'b>>, y: Option<&'b Self>) {
+        match (x, y) {
+            (Some(a), Some(b)) => a == b,
+            _ => false,
+        };
+    }
+}
+
+impl<T: 'static> X for T {
+    default type U<'a> = &'a T;
+    //~^ ERROR can't compare `T` with `T`
+}
+
+struct NotComparable;
+
+pub fn main() {
+    <NotComparable as X>::unsafe_compare(None, None);
+}
diff --git a/src/test/ui/specialization/default-generic-associated-type-bound.stderr b/src/test/ui/specialization/default-generic-associated-type-bound.stderr
new file mode 100644 (file)
index 0000000..58c6667
--- /dev/null
@@ -0,0 +1,30 @@
+warning: the feature `specialization` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/default-generic-associated-type-bound.rs:3:12
+   |
+LL | #![feature(specialization)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+   = help: consider using `min_specialization` instead, which is more stable and complete
+
+error[E0277]: can't compare `T` with `T`
+  --> $DIR/default-generic-associated-type-bound.rs:18:26
+   |
+LL |     default type U<'a> = &'a T;
+   |                          ^^^^^ no implementation for `T == T`
+   |
+   = note: required because of the requirements on the impl of `PartialEq` for `&'a T`
+note: required by a bound in `X::U`
+  --> $DIR/default-generic-associated-type-bound.rs:8:17
+   |
+LL |     type U<'a>: PartialEq<&'a Self> where Self: 'a;
+   |                 ^^^^^^^^^^^^^^^^^^^ required by this bound in `X::U`
+help: consider further restricting this bound
+   |
+LL | impl<T: 'static + std::cmp::PartialEq> X for T {
+   |                 +++++++++++++++++++++
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
index 7d499c611a43c35428075fd51a1bc698bb1b6cd3..57e64737d0faa53ae4f203234006c37f9761ab9b 100644 (file)
@@ -1,12 +1,26 @@
 #![feature(staged_api)]
+#![feature(const_trait_impl)]
+#![stable(feature = "stable", since = "1.0.0")]
 
-#![stable(feature = "rust1", since = "1.0.0")]
+#[stable(feature = "stable", since = "1.0.0")]
+pub const fn foo() {} //~ ERROR function has missing const stability attribute
 
-#[stable(feature = "foo", since = "1.0.0")]
-pub const fn foo() {}
-//~^ ERROR rustc_const_stable
+#[unstable(feature = "unstable", issue = "none")]
+pub const fn bar() {} // ok because function is unstable
 
-#[unstable(feature = "bar", issue = "none")]
-pub const fn bar() {} // ok
+#[stable(feature = "stable", since = "1.0.0")]
+pub struct Foo;
+impl Foo {
+    #[stable(feature = "stable", since = "1.0.0")]
+    pub const fn foo() {} //~ ERROR associated function has missing const stability attribute
+
+    #[unstable(feature = "unstable", issue = "none")]
+    pub const fn bar() {} // ok because function is unstable
+}
+
+// FIXME Once #![feature(const_trait_impl)] is allowed to be stable, add a test
+// for const trait impls. Right now, a "trait methods cannot be stable const fn"
+// error is emitted. This occurs prior to the lint being tested here, such that
+// the lint cannot currently be tested on this use case.
 
 fn main() {}
index 450a5303fd86f9ff2b5e6d275a767643d8f7b6a8..7eba99a477abe0ed5a14f5933d3546c591e907a5 100644 (file)
@@ -1,8 +1,14 @@
-error: `#[stable]` const functions must also be either `#[rustc_const_stable]` or `#[rustc_const_unstable]`
+error: function has missing const stability attribute
   --> $DIR/missing-const-stability.rs:6:1
    |
 LL | pub const fn foo() {}
    | ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to previous error
+error: associated function has missing const stability attribute
+  --> $DIR/missing-const-stability.rs:15:5
+   |
+LL |     pub const fn foo() {}
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
 
index ef98aa546ebdd0f795f7e1bd548752b37b0da745..84fc638a973cb58a1b3582138e59e81addc3b7fc 100644 (file)
@@ -1,8 +1,10 @@
-error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
+error[E0015]: cannot call non-const fn `foo` in statics
   --> $DIR/static-vec-repeat-not-constant.rs:3:25
    |
 LL | static a: [isize; 2] = [foo(); 2];
    |                         ^^^^^
+   |
+   = note: calls in statics are limited to constant functions, tuple structs and tuple variants
 
 error: aborting due to previous error
 
index 2c3ee5fcb803908fd7d50eba98ea1fc55ae16a95..5403b8d6d2871ae65a8f548ff6e39e2e2b9a1659 100644 (file)
@@ -10,6 +10,12 @@ fn main() {
 
     let _: Option<(i8,)> = Some();
     //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
+
+    let _: Option<(i32,)> = Some(5_usize);
+    //~^ ERROR mismatched types
+
+    let _: Option<(i32,)> = Some((5_usize));
+    //~^ ERROR mismatched types
 }
 
 fn int_bool(_: (i32, bool)) {
index a2ad602dbd47a0e65fa8eb1b6f69a7e9060f506e..ddcdfb1c3b34413be0a3bc9e6504cbb75db0897a 100644 (file)
@@ -15,7 +15,7 @@ LL |     int_bool(1, 2);
    |     expected 1 argument
    |
 note: function defined here
-  --> $DIR/args-instead-of-tuple-errors.rs:15:4
+  --> $DIR/args-instead-of-tuple-errors.rs:21:4
    |
 LL | fn int_bool(_: (i32, bool)) {
    |    ^^^^^^^^ --------------
@@ -28,6 +28,25 @@ LL |     let _: Option<(i8,)> = Some();
    |                            |
    |                            expected 1 argument
 
-error: aborting due to 3 previous errors
+error[E0308]: mismatched types
+  --> $DIR/args-instead-of-tuple-errors.rs:14:34
+   |
+LL |     let _: Option<(i32,)> = Some(5_usize);
+   |                                  ^^^^^^^ expected tuple, found `usize`
+   |
+   = note: expected tuple `(i32,)`
+               found type `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/args-instead-of-tuple-errors.rs:17:34
+   |
+LL |     let _: Option<(i32,)> = Some((5_usize));
+   |                                  ^^^^^^^^^ expected tuple, found `usize`
+   |
+   = note: expected tuple `(i32,)`
+               found type `usize`
+
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0061`.
+Some errors have detailed explanations: E0061, E0308.
+For more information about an error, try `rustc --explain E0061`.
index c9b8a41d469b99ba384d62cd7622978eb8f41f28..66e53f9ce2c80bef49c642f16571fc521fb0f458 100644 (file)
@@ -11,6 +11,12 @@ fn main() {
     let _: Option<()> = Some(());
     //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
 
+    let _: Option<(i32,)> = Some((3,));
+    //~^ ERROR mismatched types
+
+    let _: Option<(i32,)> = Some((3,));
+    //~^ ERROR mismatched types
+
     two_ints((1, 2)); //~ ERROR this function takes 1 argument
 
     with_generic((3, 4)); //~ ERROR this function takes 1 argument
index d4cc3024dd0d228d20f879fb60f7ebbfeb46822d..a15bff07ebfe6766e2a99ea097f7d23ea7397215 100644 (file)
@@ -11,6 +11,12 @@ fn main() {
     let _: Option<()> = Some();
     //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
 
+    let _: Option<(i32,)> = Some(3);
+    //~^ ERROR mismatched types
+
+    let _: Option<(i32,)> = Some((3));
+    //~^ ERROR mismatched types
+
     two_ints(1, 2); //~ ERROR this function takes 1 argument
 
     with_generic(3, 4); //~ ERROR this function takes 1 argument
index 172db7ee3df38973b3ae976458a0c24d0005124e..6a7602c9d0f45cc3742ad56b50a52b0b5719e1c1 100644 (file)
@@ -31,14 +31,40 @@ help: expected the unit value `()`; create it with empty parentheses
 LL |     let _: Option<()> = Some(());
    |                              ++
 
+error[E0308]: mismatched types
+  --> $DIR/args-instead-of-tuple.rs:14:34
+   |
+LL |     let _: Option<(i32,)> = Some(3);
+   |                                  ^ expected tuple, found integer
+   |
+   = note: expected tuple `(i32,)`
+               found type `{integer}`
+help: use a trailing comma to create a tuple with one element
+   |
+LL |     let _: Option<(i32,)> = Some((3,));
+   |                                  + ++
+
+error[E0308]: mismatched types
+  --> $DIR/args-instead-of-tuple.rs:17:34
+   |
+LL |     let _: Option<(i32,)> = Some((3));
+   |                                  ^^^ expected tuple, found integer
+   |
+   = note: expected tuple `(i32,)`
+               found type `{integer}`
+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
-  --> $DIR/args-instead-of-tuple.rs:14:5
+  --> $DIR/args-instead-of-tuple.rs:20:5
    |
 LL |     two_ints(1, 2);
    |     ^^^^^^^^ -  - supplied 2 arguments
    |
 note: function defined here
-  --> $DIR/args-instead-of-tuple.rs:19:4
+  --> $DIR/args-instead-of-tuple.rs:25:4
    |
 LL | fn two_ints(_: (i32, i32)) {
    |    ^^^^^^^^ -------------
@@ -48,13 +74,13 @@ LL |     two_ints((1, 2));
    |              +    +
 
 error[E0061]: this function takes 1 argument but 2 arguments were supplied
-  --> $DIR/args-instead-of-tuple.rs:16:5
+  --> $DIR/args-instead-of-tuple.rs:22:5
    |
 LL |     with_generic(3, 4);
    |     ^^^^^^^^^^^^ -  - supplied 2 arguments
    |
 note: function defined here
-  --> $DIR/args-instead-of-tuple.rs:22:4
+  --> $DIR/args-instead-of-tuple.rs:28:4
    |
 LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
    |    ^^^^^^^^^^^^                 ----------------
@@ -64,13 +90,13 @@ LL |     with_generic((3, 4));
    |                  +    +
 
 error[E0061]: this function takes 1 argument but 2 arguments were supplied
-  --> $DIR/args-instead-of-tuple.rs:25:9
+  --> $DIR/args-instead-of-tuple.rs:31:9
    |
 LL |         with_generic(a, b);
    |         ^^^^^^^^^^^^ -  - supplied 2 arguments
    |
 note: function defined here
-  --> $DIR/args-instead-of-tuple.rs:22:4
+  --> $DIR/args-instead-of-tuple.rs:28:4
    |
 LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
    |    ^^^^^^^^^^^^                 ----------------
@@ -79,6 +105,7 @@ help: use parentheses to construct a tuple
 LL |         with_generic((a, b));
    |                      +    +
 
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
 
-For more information about this error, try `rustc --explain E0061`.
+Some errors have detailed explanations: E0061, E0308.
+For more information about an error, try `rustc --explain E0061`.
index 0d9ecc32e08cdd6c75b47cf425955da9ffed7ddc..470c0bfcf73e515e7f0c83bbd7e25528e5a08eeb 100644 (file)
@@ -7,6 +7,12 @@ LL |     foo(String::new());
    |     required by a bound introduced by this call
    |
    = note: to coerce a `String` into a `&str`, use `&*` as a prefix
+   = help: the following implementations were found:
+             <String as From<&String>>
+             <String as From<&mut str>>
+             <String as From<&str>>
+             <String as From<Box<str>>>
+           and 2 others
    = note: required because of the requirements on the impl of `Into<&str>` for `String`
 note: required by a bound in `foo`
   --> $DIR/into-str.rs:1:31
index 355f2038df889ebf4e8c410b41182ce8d7fdbc90..7972437771399f71f356ad3d222c0b7cb0921263 100644 (file)
@@ -4,6 +4,9 @@ error[E0277]: the trait bound `&[i8]: From<&[u8]>` is not satisfied
 LL |     let _: &[i8] = data.into();
    |                         ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]`
    |
+   = help: the following implementations were found:
+             <[T; LANES] as From<Simd<T, LANES>>>
+             <[bool; LANES] as From<Mask<T, LANES>>>
    = note: required because of the requirements on the impl of `Into<&[i8]>` for `&[u8]`
 
 error: aborting due to previous error
index 1f33374eb29dbf9c050c88e5fa4babd9c4a61a92..bacab64e2642c0e9ed554295cd25316bd9486a37 100644 (file)
@@ -6,6 +6,8 @@ LL |     bar(a);
    |     |
    |     required by a bound introduced by this call
    |
+   = help: the following implementations were found:
+             <&f32 as Tr>
 note: required by a bound in `bar`
   --> $DIR/issue-84973-negative.rs:5:11
    |
index 9c8356a528470b53cfb023c7ea79bae9611e2b05..0016f19284250eae33697601612bed322883c80c 100644 (file)
@@ -11,7 +11,7 @@ LL |     let _x: (i32,) = (5);
 help: use a trailing comma to create a tuple with one element
    |
 LL |     let _x: (i32,) = (5,);
-   |                      ~~~~
+   |                        +
 
 error[E0308]: mismatched types
   --> $DIR/issue-86100-tuple-paren-comma.rs:13:9
@@ -24,7 +24,7 @@ LL |     foo((Some(3)));
 help: use a trailing comma to create a tuple with one element
    |
 LL |     foo((Some(3),));
-   |         ~~~~~~~~~~
+   |                 +
 
 error[E0308]: mismatched types
   --> $DIR/issue-86100-tuple-paren-comma.rs:17:22
@@ -37,7 +37,7 @@ LL |     let _s = S { _s: ("abc".to_string()) };
 help: use a trailing comma to create a tuple with one element
    |
 LL |     let _s = S { _s: ("abc".to_string(),) };
-   |                      ~~~~~~~~~~~~~~~~~~~~
+   |                                        +
 
 error[E0308]: mismatched types
   --> $DIR/issue-86100-tuple-paren-comma.rs:23:22
diff --git a/src/test/ui/symbol-names/verbose.rs b/src/test/ui/symbol-names/verbose.rs
new file mode 100644 (file)
index 0000000..e00c592
--- /dev/null
@@ -0,0 +1,15 @@
+// Regression test for issue #57596, where -Zverbose flag unintentionally
+// affected produced symbols making it impossible to link between crates
+// with a different value of the flag (for symbols involving generic
+// arguments equal to defaults of their respective parameters).
+//
+// build-pass
+// compile-flags: -Zverbose
+
+pub fn error(msg: String) -> Box<dyn std::error::Error> {
+  msg.into()
+}
+
+fn main() {
+  error(String::new());
+}
diff --git a/src/test/ui/target-feature/tied-features-cli.one.stderr b/src/test/ui/target-feature/tied-features-cli.one.stderr
new file mode 100644 (file)
index 0000000..2bc64a7
--- /dev/null
@@ -0,0 +1,4 @@
+error: Target features paca, pacg must all be enabled or disabled together
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/target-feature/tied-features-cli.rs b/src/test/ui/target-feature/tied-features-cli.rs
new file mode 100644 (file)
index 0000000..ea09d4f
--- /dev/null
@@ -0,0 +1,9 @@
+// only-aarch64
+// revisions: one two three four
+//[one] compile-flags: -C target-feature=+paca
+//[two] compile-flags: -C target-feature=-pacg,+pacg
+//[three] compile-flags: -C target-feature=+paca,+pacg,-paca
+//[four] check-pass
+//[four] compile-flags: -C target-feature=-paca,+pacg -C target-feature=+paca
+
+fn main() {}
diff --git a/src/test/ui/target-feature/tied-features-cli.three.stderr b/src/test/ui/target-feature/tied-features-cli.three.stderr
new file mode 100644 (file)
index 0000000..2bc64a7
--- /dev/null
@@ -0,0 +1,4 @@
+error: Target features paca, pacg must all be enabled or disabled together
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/target-feature/tied-features-cli.two.stderr b/src/test/ui/target-feature/tied-features-cli.two.stderr
new file mode 100644 (file)
index 0000000..2bc64a7
--- /dev/null
@@ -0,0 +1,4 @@
+error: Target features paca, pacg must all be enabled or disabled together
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/target-feature/tied-features.rs b/src/test/ui/target-feature/tied-features.rs
new file mode 100644 (file)
index 0000000..8640036
--- /dev/null
@@ -0,0 +1,29 @@
+// only-aarch64
+// build-fail
+
+#![feature(aarch64_target_feature, target_feature_11)]
+
+fn main() {
+    #[target_feature(enable = "pacg")]
+    //~^ ERROR must all be either enabled or disabled together
+    unsafe fn inner() {}
+
+    unsafe {
+        foo();
+        bar();
+        baz();
+        inner();
+    }
+}
+
+#[target_feature(enable = "paca")]
+//~^ ERROR must all be either enabled or disabled together
+unsafe fn foo() {}
+
+
+#[target_feature(enable = "paca,pacg")]
+unsafe fn bar() {}
+
+#[target_feature(enable = "paca")]
+#[target_feature(enable = "pacg")]
+unsafe fn baz() {}
diff --git a/src/test/ui/target-feature/tied-features.stderr b/src/test/ui/target-feature/tied-features.stderr
new file mode 100644 (file)
index 0000000..0b1460e
--- /dev/null
@@ -0,0 +1,18 @@
+error: the target features paca, pacg must all be either enabled or disabled together
+  --> $DIR/tied-features.rs:7:5
+   |
+LL |     #[target_feature(enable = "pacg")]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add the missing features in a `target_feature` attribute
+
+error: the target features paca, pacg must all be either enabled or disabled together
+  --> $DIR/tied-features.rs:19:1
+   |
+LL | #[target_feature(enable = "paca")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add the missing features in a `target_feature` attribute
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/test-attrs/test-allow-fail-attr.rs b/src/test/ui/test-attrs/test-allow-fail-attr.rs
deleted file mode 100644 (file)
index 29ce9f7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-// run-pass
-// compile-flags: --test
-#![feature(allow_fail)]
-#![feature(cfg_panic)]
-
-#[test]
-#[allow_fail]
-fn test1() {
-    #[cfg(not(panic = "abort"))]
-    panic!();
-}
-
-#[test]
-#[allow_fail]
-fn test2() {
-    assert!(true);
-}
diff --git a/src/test/ui/test-attrs/test-on-macro.rs b/src/test/ui/test-attrs/test-on-macro.rs
deleted file mode 100644 (file)
index 0667364..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// check-pass
-// compile-flags:--test
-
-#![deny(warnings)]
-
-macro_rules! foo {
-    () => (fn foo(){})
-}
-
-#[test]
-foo!(); //~ WARNING `#[test]` attribute should not be used on macros
-
-fn main(){}
diff --git a/src/test/ui/test-attrs/test-on-macro.stderr b/src/test/ui/test-attrs/test-on-macro.stderr
deleted file mode 100644 (file)
index 98190b0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-warning: `#[test]` attribute should not be used on macros. Use `#[cfg(test)]` instead.
-  --> $DIR/test-on-macro.rs:11:1
-   |
-LL | foo!();
-   | ^^^^^^^
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/test-attrs/test-on-not-fn.rs b/src/test/ui/test-attrs/test-on-not-fn.rs
new file mode 100644 (file)
index 0000000..b2f681c
--- /dev/null
@@ -0,0 +1,80 @@
+// compile-flags: --test
+
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+mod test {}
+
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+mod loooooooooooooong_teeeeeeeeeest {
+    /*
+    this is a comment
+    this comment goes on for a very long time
+    this is to pad out the span for this module for a long time
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
+    labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
+    laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in
+    voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat
+    non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
+    */
+}
+
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+extern "C" {}
+
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+trait Foo {}
+
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+impl Foo for i32 {}
+
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+const FOO: i32 = -1_i32;
+
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+static BAR: u64 = 10_000_u64;
+
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+enum MyUnit {
+    Unit,
+}
+
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+struct NewI32(i32);
+
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+union Spooky {
+    x: i32,
+    y: u32,
+}
+
+#[repr(C, align(64))]
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+#[derive(Copy, Clone, Debug)]
+struct MoreAttrs {
+    a: i32,
+    b: u64,
+}
+
+macro_rules! foo {
+    () => {};
+}
+
+#[test] //~ ERROR: the `#[test]` attribute may only be used on a non-associated function
+foo!();
+
+// make sure it doesn't erroneously trigger on a real test
+#[test]
+fn real_test() {
+    assert_eq!(42_i32, 42_i32);
+}
+
+// make sure it works with cfg test
+#[cfg(test)]
+mod real_tests {
+    #[cfg(test)]
+    fn foo() {}
+
+    #[test]
+    fn bar() {
+        foo();
+    }
+}
diff --git a/src/test/ui/test-attrs/test-on-not-fn.stderr b/src/test/ui/test-attrs/test-on-not-fn.stderr
new file mode 100644 (file)
index 0000000..dd693cf
--- /dev/null
@@ -0,0 +1,185 @@
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:3:1
+   |
+LL | #[test]
+   | ^^^^^^^
+LL | mod test {}
+   | ----------- expected a non-associated function, found a module
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:6:1
+   |
+LL |   #[test]
+   |   ^^^^^^^
+LL | / mod loooooooooooooong_teeeeeeeeeest {
+LL | |     /*
+LL | |     this is a comment
+LL | |     this comment goes on for a very long time
+...  |
+LL | |     */
+LL | | }
+   | |_- expected a non-associated function, found a module
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:20:1
+   |
+LL | #[test]
+   | ^^^^^^^
+LL | extern "C" {}
+   | ------------- expected a non-associated function, found an extern block
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:23:1
+   |
+LL | #[test]
+   | ^^^^^^^
+LL | trait Foo {}
+   | ------------ expected a non-associated function, found a trait
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:26:1
+   |
+LL | #[test]
+   | ^^^^^^^
+LL | impl Foo for i32 {}
+   | ------------------- expected a non-associated function, found an implementation
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:29:1
+   |
+LL | #[test]
+   | ^^^^^^^
+LL | const FOO: i32 = -1_i32;
+   | ------------------------ expected a non-associated function, found a constant item
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:32:1
+   |
+LL | #[test]
+   | ^^^^^^^
+LL | static BAR: u64 = 10_000_u64;
+   | ----------------------------- expected a non-associated function, found a static item
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:35:1
+   |
+LL |   #[test]
+   |   ^^^^^^^
+LL | / enum MyUnit {
+LL | |     Unit,
+LL | | }
+   | |_- expected a non-associated function, found an enum
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:40:1
+   |
+LL | #[test]
+   | ^^^^^^^
+LL | struct NewI32(i32);
+   | ------------------- expected a non-associated function, found a struct
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:43:1
+   |
+LL |   #[test]
+   |   ^^^^^^^
+LL | / union Spooky {
+LL | |     x: i32,
+LL | |     y: u32,
+LL | | }
+   | |_- expected a non-associated function, found a union
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:50:1
+   |
+LL |   #[test]
+   |   ^^^^^^^
+LL |   #[derive(Copy, Clone, Debug)]
+LL | / struct MoreAttrs {
+LL | |     a: i32,
+LL | |     b: u64,
+LL | | }
+   | |_- expected a non-associated function, found a struct
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: the `#[test]` attribute may only be used on a non-associated function
+  --> $DIR/test-on-not-fn.rs:61:1
+   |
+LL | #[test]
+   | ^^^^^^^
+LL | foo!();
+   | ------- expected a non-associated function, found an item macro invocation
+   |
+   = note: the `#[test]` macro causes a a function to be run on a test and has no effect on non-functions
+help: replace with conditional compilation to make the item only exist when tests are being run
+   |
+LL | #[cfg(test)]
+   | ~~~~~~~~~~~~
+
+error: aborting due to 12 previous errors
+
diff --git a/src/test/ui/trait-bounds/issue-93008.rs b/src/test/ui/trait-bounds/issue-93008.rs
new file mode 100644 (file)
index 0000000..1b01056
--- /dev/null
@@ -0,0 +1,10 @@
+// compile-flags: -Zmir-opt-level=4
+
+pub fn bar<T>(s: &'static mut ())
+where
+    &'static mut (): Clone, //~ ERROR the trait bound
+{
+    <&'static mut () as Clone>::clone(&s);
+}
+
+fn main() {}
diff --git a/src/test/ui/trait-bounds/issue-93008.stderr b/src/test/ui/trait-bounds/issue-93008.stderr
new file mode 100644 (file)
index 0000000..10f80f8
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `&'static mut (): Clone` is not satisfied
+  --> $DIR/issue-93008.rs:5:5
+   |
+LL |     &'static mut (): Clone,
+   |     ^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `&'static mut ()`
+   |
+   = help: see issue #48214
+   = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index 6333b4eb08cd530643b677e926567b01b31e009a..907a1bd75a06448c81feff245bb30c5f5a2085bf 100644 (file)
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     f::<dyn X<Y = str>>();
    |     ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `f`
   --> $DIR/check-trait-object-bounds-1.rs:7:9
    |
index 9afae9a9638349ef123624e03352474c864ba1f5..b27f8d791a50f29d9ca246269e80cdf132b74d99 100644 (file)
@@ -4,6 +4,8 @@ error[E0277]: the trait bound `str: Clone` is not satisfied
 LL |     f::<dyn X<Y = str>>();
    |     ^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str`
    |
+   = help: the following implementations were found:
+             <String as Clone>
 note: required by a bound in `f`
   --> $DIR/check-trait-object-bounds-4.rs:10:9
    |
index 3c4a5d95c137ec6e9cdd752ca26ecef24f171c64..413225d45a62ce6d6cd8d24a7e97c0c3296afb0e 100644 (file)
@@ -44,6 +44,7 @@ LL |     opts.get(<String as AsRef<[u8]>>::as_ref(opt));
    |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 LL |     opts.get(<String as AsRef<str>>::as_ref(opt));
    |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+     and 4 other candidates
 
 error[E0283]: type annotations needed
   --> $DIR/issue-77982.rs:13:44
index 3e83db142e0871cbbd45983b825c8e25470aa539..b970012837313b2748dc245267da0a933300f4a7 100644 (file)
@@ -9,6 +9,8 @@ LL |     bar: &'a mut T
    |
    = help: the following implementations were found:
              <&T as Clone>
+             <*const T as Clone>
+             <*mut T as Clone>
    = note: `Clone` is implemented for `&T`, but not for `&mut T`
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
index 681f26438e69500be9f375070a3c48a91cacf8e5..0e17f089048f72b23cd4c75e2c24fe6b1426f5a9 100644 (file)
@@ -1,4 +1,5 @@
 #![feature(negative_impls)]
+#![feature(with_negative_coherence)]
 
 pub trait ForeignTrait {}
 
index 3e336933937d04dcd782adf318e3b3bc189737e9..1314f9cb0932d6b98ef0842b0f950dc9bc324350 100644 (file)
@@ -34,20 +34,20 @@ fn main() {
     Qux.clone();
     //~^ ERROR no method named `clone` found for struct `Qux`
     //~| NOTE method not found in `Qux`
-    //~| NOTE `Clone` defines an item `clone`, but is explicitely unimplemented
+    //~| NOTE `Clone` defines an item `clone`, but is explicitly unimplemented
 
     0_u32.bar();
     //~^ ERROR no method named `bar` found for type `u32`
     //~| NOTE method not found in `u32`
-    //~| NOTE `Bar` defines an item `bar`, but is explicitely unimplemented
+    //~| NOTE `Bar` defines an item `bar`, but is explicitly unimplemented
 
     Qux.foo();
     //~^ ERROR no method named `foo` found for struct `Qux`
     //~| NOTE method not found in `Qux`
-    //~| NOTE the following traits define an item `foo`, but are explicitely unimplemented
+    //~| NOTE the following traits define an item `foo`, but are explicitly unimplemented
 
     0_u32.foo();
     //~^ ERROR no method named `foo` found for type `u32`
     //~| NOTE method not found in `u32`
-    //~| NOTE `FooBar` defines an item `foo`, but is explicitely unimplemented
+    //~| NOTE `FooBar` defines an item `foo`, but is explicitly unimplemented
 }
index 01e36a4a62a1bcc01715166670471d9f3f1e6d38..c18abf95083da5feff467f8b1f5adb7ea63e060d 100644 (file)
@@ -8,7 +8,7 @@ LL |     Qux.clone();
    |         ^^^^^ method not found in `Qux`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
-   = note: the trait `Clone` defines an item `clone`, but is explicitely unimplemented
+   = note: the trait `Clone` defines an item `clone`, but is explicitly unimplemented
 
 error[E0599]: no method named `bar` found for type `u32` in the current scope
   --> $DIR/explicitly-unimplemented-error-message.rs:39:11
@@ -17,7 +17,7 @@ LL |     0_u32.bar();
    |           ^^^ method not found in `u32`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
-   = note: the trait `Bar` defines an item `bar`, but is explicitely unimplemented
+   = note: the trait `Bar` defines an item `bar`, but is explicitly unimplemented
 
 error[E0599]: no method named `foo` found for struct `Qux` in the current scope
   --> $DIR/explicitly-unimplemented-error-message.rs:44:9
@@ -29,7 +29,7 @@ LL |     Qux.foo();
    |         ^^^ method not found in `Qux`
    |
    = help: items from traits can only be used if the trait is implemented and in scope
-   = note: the following traits define an item `foo`, but are explicitely unimplemented:
+   = note: the following traits define an item `foo`, but are explicitly unimplemented:
            Foo
            FooBar
 
@@ -45,7 +45,7 @@ note: `Foo` defines an item `foo`, perhaps you need to implement it
    |
 LL | trait Foo {
    | ^^^^^^^^^
-   = note: the trait `FooBar` defines an item `foo`, but is explicitely unimplemented
+   = note: the trait `FooBar` defines an item `foo`, but is explicitly unimplemented
 
 error: aborting due to 4 previous errors
 
index 119ac05c33e4b4442ee9c47b0c2baedbd87af17d..c1f96ab8c149e37b0072d58504014761a5f4be24 100644 (file)
@@ -1,6 +1,7 @@
 // check-pass
 
 #![feature(negative_impls)]
+#![feature(with_negative_coherence)]
 
 // aux-build: foreign_trait.rs
 
@@ -16,8 +17,8 @@
 extern crate foreign_trait;
 use foreign_trait::ForeignTrait;
 
-trait LocalTrait { }
-impl<T: ForeignTrait> LocalTrait for T { }
-impl LocalTrait for String { }
+trait LocalTrait {}
+impl<T: ForeignTrait> LocalTrait for T {}
+impl LocalTrait for String {}
 
-fn main() { }
+fn main() {}
index b77af7ddf474628863341ce536372d48bbed572e..299219431ef113d13e17dd2124faad9b65cec510 100644 (file)
@@ -8,6 +8,8 @@ LL |     takes_type_parameter(&string);  // Error
    |     |                    help: consider adding dereference here: `&*string`
    |     required by a bound introduced by this call
    |
+   = help: the following implementations were found:
+             <&str as SomeTrait>
 note: required by a bound in `takes_type_parameter`
   --> $DIR/issue-62530.rs:4:44
    |
index 80c5e6f529cd671d459eac7bd7c4c027a42600cf..171051156b7f242e93a42406afd8761d3e2a5a0e 100644 (file)
@@ -10,6 +10,9 @@ LL |     Ok(Err(123_i32)?)
    = help: the following implementations were found:
              <u8 as From<NonZeroU8>>
              <u8 as From<bool>>
+             <f32 as From<i16>>
+             <f32 as From<i8>>
+           and 71 others
    = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, i32>>` for `Result<u64, u8>`
 
 error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result`
index 37b330ba4b8fc39620c1b612155a76968db5b36b..f936dc42f133d0af0fc012b06d855dd54b4be427 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-compare-mode-chalk
 #![feature(type_alias_impl_trait)]
 
 use std::fmt::Debug;
index 4c8144a2359309a5f19a7724d317b9f0e2c91ec1..9971c7e0e20ee16ee809ebb6318fb454f8233490 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-53598.rs:20:42
+  --> $DIR/issue-53598.rs:19:42
    |
 LL |       fn foo<T: Debug>(_: T) -> Self::Item {
    |  __________________________________________^
index f1db4d3291b40709ade965658f99167fefc8e654..13a6b7c2f7ceb1706a27be93e232c557bcb26d7f 100644 (file)
@@ -1,4 +1,3 @@
-// ignore-compare-mode-chalk
 #![feature(arbitrary_self_types)]
 #![feature(type_alias_impl_trait)]
 
index c701e3e74ef591cecee73607b7c2ca1df6cf8e52..b2e3f46f1f5823bebe23ad90879ee45f5c82c15d 100644 (file)
@@ -1,5 +1,5 @@
 error: type parameter `impl Deref<Target = Self>` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/issue-57700.rs:16:58
+  --> $DIR/issue-57700.rs:15:58
    |
 LL |       fn foo(self: impl Deref<Target = Self>) -> Self::Bar {
    |  __________________________________________________________^
index 9d2ba849c8667539ae6a40efbfb3505387ac0cbd..badf35484f3604c737c38b56a64c575f34b4d988 100644 (file)
@@ -1,5 +1,3 @@
-// ignore-compare-mode-chalk
-
 trait Bug {
     type Item: Bug;
 
index 62ab7eb456010c8d166c7640c89ec19b532b55c3..dc8a381aece9411300d61c334140986d94a65523 100644 (file)
@@ -1,5 +1,5 @@
 error[E0658]: `impl Trait` in type aliases is unstable
-  --> $DIR/issue-60371.rs:10:17
+  --> $DIR/issue-60371.rs:8:17
    |
 LL |     type Item = impl Bug;
    |                 ^^^^^^^^
@@ -8,7 +8,7 @@ LL |     type Item = impl Bug;
    = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
 
 error[E0277]: the trait bound `(): Bug` is not satisfied
-  --> $DIR/issue-60371.rs:12:40
+  --> $DIR/issue-60371.rs:10:40
    |
 LL |     const FUN: fn() -> Self::Item = || ();
    |                                        ^ the trait `Bug` is not implemented for `()`
@@ -17,7 +17,7 @@ LL |     const FUN: fn() -> Self::Item = || ();
              <&() as Bug>
 
 error: non-defining opaque type use in defining scope
-  --> $DIR/issue-60371.rs:12:37
+  --> $DIR/issue-60371.rs:10:37
    |
 LL | impl Bug for &() {
    |              - cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
index 81b6a996072156dd6e306c56c8286f7f41426ef4..c0384399a92e683f1fdc4e63528cd6482f0008ea 100644 (file)
@@ -34,4 +34,14 @@ fn baz(v: Vec<i32>) -> i32 {
     }
 }
 
+fn qux(a: &Option<Box<[i32; 2]>>) -> i32 {
+    match a.as_deref() {
+    //~^ HELP: consider using `as_deref` here
+        Some([a, b]) => a + b,
+        //~^ ERROR: expected an array or slice
+        //~| NOTE: pattern cannot match with input type
+        _ => 42,
+    }
+}
+
 fn main() {}
index e938d8f5c9f04b96d66bb93883dbd83b3eec4ad5..63602d26f970df5b77f43dd0341c61694944bca4 100644 (file)
@@ -34,4 +34,14 @@ fn baz(v: Vec<i32>) -> i32 {
     }
 }
 
+fn qux(a: &Option<Box<[i32; 2]>>) -> i32 {
+    match a {
+    //~^ HELP: consider using `as_deref` here
+        Some([a, b]) => a + b,
+        //~^ ERROR: expected an array or slice
+        //~| NOTE: pattern cannot match with input type
+        _ => 42,
+    }
+}
+
 fn main() {}
index 96ad00cde4f7b619f35219b956185e4e65bdda47..f2f407bcafff222acedc6040dd381bb6417acabc 100644 (file)
@@ -25,6 +25,15 @@ LL |
 LL |         [a, b] => a + b,
    |         ^^^^^^ pattern cannot match with input type `Vec<i32>`
 
-error: aborting due to 3 previous errors
+error[E0529]: expected an array or slice, found `Box<[i32; 2]>`
+  --> $DIR/issue-91328.rs:40:14
+   |
+LL |     match a {
+   |           - help: consider using `as_deref` here: `a.as_deref()`
+LL |
+LL |         Some([a, b]) => a + b,
+   |              ^^^^^^ pattern cannot match with input type `Box<[i32; 2]>`
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0529`.
index 91e9a0d0b659c7e7cbc1a496f2adfed56d97fd8e..80474b807e7f34105e198d9bf512998d9a8fa5f3 100644 (file)
@@ -1,7 +1,7 @@
 #![feature(untagged_unions)]
 
 union Test {
-    a: A, //~ ERROR unions may not contain fields that need dropping
+    a: A, //~ ERROR unions cannot contain fields that may need dropping
     b: B
 }
 
index 8edf4db441b9cf872a8b429367757277ed04ba4a..7d4208b10da808d7a30de02034bcf48762171c46 100644 (file)
@@ -1,10 +1,11 @@
-error[E0740]: unions may not contain fields that need dropping
+error[E0740]: unions cannot contain fields that may need dropping
   --> $DIR/issue-41073.rs:4:5
    |
 LL |     a: A,
    |     ^^^^
    |
-help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
    |
 LL |     a: std::mem::ManuallyDrop<A>,
    |        +++++++++++++++++++++++ +
index 8f816cc1b737c6c4822e80379c969ae6185337ba..4b333631ec0f7cc53439427f171f44c0cffbe6d4 100644 (file)
@@ -4,7 +4,7 @@
 #![feature(untagged_unions)]
 
 union Foo {
-    bar: Bar, //~ ERROR unions may not contain fields that need dropping
+    bar: Bar, //~ ERROR unions cannot contain fields that may need dropping
 }
 
 union Bar {
index 65ca5fd931d670417865d75e1393d812be9081ec..b5579eeef09777d587c271cf372a28e9ce264f27 100644 (file)
@@ -1,10 +1,11 @@
-error[E0740]: unions may not contain fields that need dropping
+error[E0740]: unions cannot contain fields that may need dropping
   --> $DIR/union-custom-drop.rs:7:5
    |
 LL |     bar: Bar,
    |     ^^^^^^^^
    |
-help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
    |
 LL |     bar: std::mem::ManuallyDrop<Bar>,
    |          +++++++++++++++++++++++   +
index 146a627bcdef7f160476cd730dd6bc69443debfd..e8e65fe5d1d1de2704faf9f1ff8821ab872849c3 100644 (file)
@@ -16,9 +16,9 @@ LL |     let w = u.clone();
    = note: the following trait bounds were not satisfied:
            `CloneNoCopy: Copy`
            which is required by `U5<CloneNoCopy>: Clone`
-help: consider annotating `CloneNoCopy` with `#[derive(Copy)]`
+help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]`
    |
-LL | #[derive(Copy)]
+LL | #[derive(Clone, Copy)]
    |
 
 error[E0277]: the trait bound `U1: Copy` is not satisfied
index 146a627bcdef7f160476cd730dd6bc69443debfd..e8e65fe5d1d1de2704faf9f1ff8821ab872849c3 100644 (file)
@@ -16,9 +16,9 @@ LL |     let w = u.clone();
    = note: the following trait bounds were not satisfied:
            `CloneNoCopy: Copy`
            which is required by `U5<CloneNoCopy>: Clone`
-help: consider annotating `CloneNoCopy` with `#[derive(Copy)]`
+help: consider annotating `CloneNoCopy` with `#[derive(Clone, Copy)]`
    |
-LL | #[derive(Copy)]
+LL | #[derive(Clone, Copy)]
    |
 
 error[E0277]: the trait bound `U1: Copy` is not satisfied
index f5e9681735c6f93272155b397e73b52b4a3ca570..93fe996d2a477deb3f95b537051a4cc0ebe7407e 100644 (file)
@@ -1,32 +1,35 @@
-error[E0740]: unions may not contain fields that need dropping
+error[E0740]: unions cannot contain fields that may need dropping
   --> $DIR/union-with-drop-fields.rs:11:5
    |
 LL |     a: String,
    |     ^^^^^^^^^
    |
-help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
    |
 LL |     a: std::mem::ManuallyDrop<String>,
    |        +++++++++++++++++++++++      +
 
-error[E0740]: unions may not contain fields that need dropping
+error[E0740]: unions cannot contain fields that may need dropping
   --> $DIR/union-with-drop-fields.rs:19:5
    |
 LL |     a: S,
    |     ^^^^
    |
-help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
    |
 LL |     a: std::mem::ManuallyDrop<S>,
    |        +++++++++++++++++++++++ +
 
-error[E0740]: unions may not contain fields that need dropping
+error[E0740]: unions cannot contain fields that may need dropping
   --> $DIR/union-with-drop-fields.rs:24:5
    |
 LL |     a: T,
    |     ^^^^
    |
-help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
    |
 LL |     a: std::mem::ManuallyDrop<T>,
    |        +++++++++++++++++++++++ +
index 96c293418b62951fc548d7ef00872fe8bb348e52..a7a8b69e784abc3a8af508a11841358aa4febb3a 100644 (file)
@@ -8,7 +8,7 @@ union U {
 }
 
 union W {
-    a: String, //~ ERROR unions may not contain fields that need dropping
+    a: String, //~ ERROR unions cannot contain fields that may need dropping
     b: String, // OK, only one field is reported
 }
 
@@ -16,12 +16,12 @@ union W {
 
 // `S` doesn't implement `Drop` trait, but still has non-trivial destructor
 union Y {
-    a: S, //~ ERROR unions may not contain fields that need dropping
+    a: S, //~ ERROR unions cannot contain fields that may need dropping
 }
 
 // We don't know if `T` is trivially-destructable or not until trans
 union J<T> {
-    a: T, //~ ERROR unions may not contain fields that need dropping
+    a: T, //~ ERROR unions cannot contain fields that may need dropping
 }
 
 union H<T: Copy> {
index f5e9681735c6f93272155b397e73b52b4a3ca570..93fe996d2a477deb3f95b537051a4cc0ebe7407e 100644 (file)
@@ -1,32 +1,35 @@
-error[E0740]: unions may not contain fields that need dropping
+error[E0740]: unions cannot contain fields that may need dropping
   --> $DIR/union-with-drop-fields.rs:11:5
    |
 LL |     a: String,
    |     ^^^^^^^^^
    |
-help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
    |
 LL |     a: std::mem::ManuallyDrop<String>,
    |        +++++++++++++++++++++++      +
 
-error[E0740]: unions may not contain fields that need dropping
+error[E0740]: unions cannot contain fields that may need dropping
   --> $DIR/union-with-drop-fields.rs:19:5
    |
 LL |     a: S,
    |     ^^^^
    |
-help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
    |
 LL |     a: std::mem::ManuallyDrop<S>,
    |        +++++++++++++++++++++++ +
 
-error[E0740]: unions may not contain fields that need dropping
+error[E0740]: unions cannot contain fields that may need dropping
   --> $DIR/union-with-drop-fields.rs:24:5
    |
 LL |     a: T,
    |     ^^^^
    |
-help: wrap the type with `std::mem::ManuallyDrop` and ensure it is manually dropped
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
    |
 LL |     a: std::mem::ManuallyDrop<T>,
    |        +++++++++++++++++++++++ +
index dedafd85cfd61d3d397f60d8caf2d59d527d0346..c022d3aa0acd7ca18c18add8b97507f9a7678f6e 100644 (file)
@@ -10,7 +10,7 @@ serde_json = "1.0"
 anyhow = "1.0.32"
 flate2 = "1.0.16"
 tar = "0.4.29"
-sha2 = "0.9.1"
+sha2 = "0.10.1"
 rayon = "1.5.1"
 hex = "0.4.2"
 num_cpus = "1.13.0"
index 6b56d6bc4adf068391105254d9e00539619fb004..8a62146abfc4e47e3a1d16cf91fc31e4bb0b3dfa 100644 (file)
@@ -386,7 +386,10 @@ fn add_profiles_to(&mut self, manifest: &mut Manifest) {
         // for users to install the additional component manually, if needed.
         if self.versions.channel() == "nightly" {
             self.extend_profile("complete", &mut manifest.profiles, &["rustc-dev"]);
-            self.extend_profile("complete", &mut manifest.profiles, &["rustc-docs"]);
+            // Do not include the rustc-docs component for now, as it causes
+            // conflicts with the rust-docs component when installed. See
+            // #75833.
+            // self.extend_profile("complete", &mut manifest.profiles, &["rustc-docs"]);
         }
     }
 
index 25fcb135d02ea897ce894b67ae021f48107d522b..ea2a21c994ca1e4d4c49412827b3cf4dcb158b1d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 25fcb135d02ea897ce894b67ae021f48107d522b
+Subproject commit ea2a21c994ca1e4d4c49412827b3cf4dcb158b1d
index d66e6cf7fb6596ad20f5cfb1bf9dfba0e409d624..c9adf77c0d639a0560073ea4889d32b06bb60344 100644 (file)
@@ -6,14 +6,185 @@ document.
 
 ## Unreleased / In Rust Nightly
 
-[e181011...master](https://github.com/rust-lang/rust-clippy/compare/e181011...master)
+[0eff589...master](https://github.com/rust-lang/rust-clippy/compare/0eff589...master)
 
-## Rust 1.58 (beta)
+## Rust 1.59 (beta)
 
-Current beta, release 2022-01-13
+Current beta, release 2022-02-24
+
+[e181011...0eff589](https://github.com/rust-lang/rust-clippy/compare/e181011...0eff589)
+
+### New Lints
+
+* [`index_refutable_slice`]
+  [#7643](https://github.com/rust-lang/rust-clippy/pull/7643)
+* [`needless_splitn`]
+  [#7896](https://github.com/rust-lang/rust-clippy/pull/7896)
+* [`unnecessary_to_owned`]
+  [#7978](https://github.com/rust-lang/rust-clippy/pull/7978)
+* [`needless_late_init`]
+  [#7995](https://github.com/rust-lang/rust-clippy/pull/7995)
+* [`octal_escapes`] [#8007](https://github.com/rust-lang/rust-clippy/pull/8007)
+* [`return_self_not_must_use`]
+  [#8071](https://github.com/rust-lang/rust-clippy/pull/8071)
+* [`init_numbered_fields`]
+  [#8170](https://github.com/rust-lang/rust-clippy/pull/8170)
+
+### Moves and Deprecations
+
+* Move `if_then_panic` to `pedantic` and rename to [`manual_assert`] (now
+  allow-by-default) [#7810](https://github.com/rust-lang/rust-clippy/pull/7810)
+* Rename `disallow_type` to [`disallowed_types`] and `disallowed_method` to
+  [`disallowed_methods`]
+  [#7984](https://github.com/rust-lang/rust-clippy/pull/7984)
+* Move [`map_flatten`] to `complexity` (now warn-by-default)
+  [#8054](https://github.com/rust-lang/rust-clippy/pull/8054)
+
+### Enhancements
+
+* [`match_overlapping_arm`]: Fix false negative where after included ranges,
+  overlapping ranges weren't linted anymore
+  [#7909](https://github.com/rust-lang/rust-clippy/pull/7909)
+* [`deprecated_cfg_attr`]: Now takes the specified MSRV into account
+  [#7944](https://github.com/rust-lang/rust-clippy/pull/7944)
+* [`cast_lossless`]: Now also lints for `bool` to integer casts
+  [#7948](https://github.com/rust-lang/rust-clippy/pull/7948)
+* [`let_underscore_lock`]: Also emit lints for the `parking_lot` crate
+  [#7957](https://github.com/rust-lang/rust-clippy/pull/7957)
+* [`needless_borrow`]
+  [#7977](https://github.com/rust-lang/rust-clippy/pull/7977)
+    * Lint when a borrow is auto-dereffed more than once
+    * Lint in the trailing expression of a block for a match arm
+* [`strlen_on_c_strings`]
+  [8001](https://github.com/rust-lang/rust-clippy/pull/8001)
+    * Lint when used without a fully-qualified path
+    * Suggest removing the surrounding unsafe block when possible
+* [`non_ascii_literal`]: Now also lints on `char`s, not just `string`s
+  [#8034](https://github.com/rust-lang/rust-clippy/pull/8034)
+* [`single_char_pattern`]: Now also lints on `split_inclusive`, `split_once`,
+  `rsplit_once`, `replace`, and `replacen`
+  [#8077](https://github.com/rust-lang/rust-clippy/pull/8077)
+* [`unwrap_or_else_default`]: Now also lints on `std` constructors like
+  `Vec::new`, `HashSet::new`, and `HashMap::new`
+  [#8163](https://github.com/rust-lang/rust-clippy/pull/8163)
+* [`shadow_reuse`]: Now also lints on shadowed `if let` bindings, instead of
+  [`shadow_unrelated`]
+  [#8165](https://github.com/rust-lang/rust-clippy/pull/8165)
+
+### False Positive Fixes
+
+* [`or_fun_call`], [`unnecessary_lazy_evaluations`]: Improve heuristics, so that
+  cheap functions (e.g. calling `.len()` on a `Vec`) won't get linted anymore
+  [#7639](https://github.com/rust-lang/rust-clippy/pull/7639)
+* [`manual_split_once`]: No longer suggests code changing the original behavior
+  [#7896](https://github.com/rust-lang/rust-clippy/pull/7896)
+* Don't show [`no_effect`] or [`unnecessary_operation`] warning for unit struct
+  implementing `FnOnce`
+  [#7898](https://github.com/rust-lang/rust-clippy/pull/7898)
+* [`semicolon_if_nothing_returned`]: Fixed a bug, where the lint wrongly
+  triggered on `let-else` statements
+  [#7955](https://github.com/rust-lang/rust-clippy/pull/7955)
+* [`if_then_some_else_none`]: No longer lints if there is an early return
+  [#7980](https://github.com/rust-lang/rust-clippy/pull/7980)
+* [`needless_collect`]: No longer suggests removal of `collect` when removal
+  would create code requiring mutably borrowing a value multiple times
+  [#7982](https://github.com/rust-lang/rust-clippy/pull/7982)
+* [`shadow_same`]: Fix false positive for `async` function's params
+  [#7997](https://github.com/rust-lang/rust-clippy/pull/7997)
+* [`suboptimal_flops`]: No longer triggers in constant functions
+  [#8009](https://github.com/rust-lang/rust-clippy/pull/8009)
+* [`type_complexity`]: No longer lints on associated types in traits
+  [#8030](https://github.com/rust-lang/rust-clippy/pull/8030)
+* [`question_mark`]: No longer lints if returned object is not local
+  [#8080](https://github.com/rust-lang/rust-clippy/pull/8080)
+* [`option_if_let_else`]: No longer lint on complex sub-patterns
+  [#8086](https://github.com/rust-lang/rust-clippy/pull/8086)
+* [`blocks_in_if_conditions`]: No longer lints on empty closures
+  [#8100](https://github.com/rust-lang/rust-clippy/pull/8100)
+* [`enum_variant_names`]: No longer lint when first prefix is only a substring
+  of a camel-case word
+  [#8127](https://github.com/rust-lang/rust-clippy/pull/8127)
+* [`identity_op`]: Only lint on integral operands
+  [#8183](https://github.com/rust-lang/rust-clippy/pull/8183)
+
+### Suggestion Fixes/Improvements
+
+* [`search_is_some`]: Fix suggestion for `any()` not taking item by reference
+  [#7463](https://github.com/rust-lang/rust-clippy/pull/7463)
+* [`almost_swapped`]: Now detects if there is a `no_std` or `no_core` attribute
+  and adapts the suggestion accordingly
+  [#7877](https://github.com/rust-lang/rust-clippy/pull/7877)
+* [`redundant_pattern_matching`]: Fix suggestion for deref expressions
+  [#7949](https://github.com/rust-lang/rust-clippy/pull/7949)
+* [`explicit_counter_loop`]: Now also produces a suggestion for non-`usize`
+  types [#7950](https://github.com/rust-lang/rust-clippy/pull/7950)
+* [`manual_map`]: Fix suggestion when used with unsafe functions and blocks
+  [#7968](https://github.com/rust-lang/rust-clippy/pull/7968)
+* [`option_map_or_none`]: Suggest `map` over `and_then` when possible
+  [#7971](https://github.com/rust-lang/rust-clippy/pull/7971)
+* [`option_if_let_else`]: No longer expands macros in the suggestion
+  [#7974](https://github.com/rust-lang/rust-clippy/pull/7974)
+* [`iter_cloned_collect`]: Suggest `copied` over `cloned` when possible
+  [#8006](https://github.com/rust-lang/rust-clippy/pull/8006)
+* [`doc_markdown`]: No longer uses inline hints to improve readability of
+  suggestion [#8011](https://github.com/rust-lang/rust-clippy/pull/8011)
+* [`needless_question_mark`]: Now better explains the suggestion
+  [#8028](https://github.com/rust-lang/rust-clippy/pull/8028)
+* [`single_char_pattern`]: Escape backslash `\` in suggestion
+  [#8067](https://github.com/rust-lang/rust-clippy/pull/8067)
+* [`needless_bool`]: Suggest `a != b` over `!(a == b)`
+  [#8117](https://github.com/rust-lang/rust-clippy/pull/8117)
+* [`iter_skip_next`]: Suggest to add a `mut` if it is necessary in order to
+  apply this lints suggestion
+  [#8133](https://github.com/rust-lang/rust-clippy/pull/8133)
+* [`neg_multiply`]: Now produces a suggestion
+  [#8144](https://github.com/rust-lang/rust-clippy/pull/8144)
+* [`needless_return`]: Now suggests the unit type `()` over an empty block `{}`
+  in match arms [#8185](https://github.com/rust-lang/rust-clippy/pull/8185)
+* [`suboptimal_flops`]: Now gives a syntactically correct suggestion for
+  `to_radians` and `to_degrees`
+  [#8187](https://github.com/rust-lang/rust-clippy/pull/8187)
+
+### ICE Fixes
+
+* [`undocumented_unsafe_blocks`]
+  [#7945](https://github.com/rust-lang/rust-clippy/pull/7945)
+  [#7988](https://github.com/rust-lang/rust-clippy/pull/7988)
+* [`unnecessary_cast`]
+  [#8167](https://github.com/rust-lang/rust-clippy/pull/8167)
+
+### Documentation Improvements
+
+* [`print_stdout`], [`print_stderr`], [`dbg_macro`]: Document how the lint level
+  can be changed crate-wide
+  [#8040](https://github.com/rust-lang/rust-clippy/pull/8040)
+* Added a note to the `README` that config changes don't apply to already
+  compiled code [#8175](https://github.com/rust-lang/rust-clippy/pull/8175)
+
+### Others
+
+* [Clippy's lint
+  list](https://rust-lang.github.io/rust-clippy/master/index.html) now displays
+  the version a lint was added. :tada:
+  [#7813](https://github.com/rust-lang/rust-clippy/pull/7813)
+* New and improved issue templates
+  [#8032](https://github.com/rust-lang/rust-clippy/pull/8032)
+* _Dev:_ Add `cargo dev lint` command, to run your modified Clippy version on a
+  file [#7917](https://github.com/rust-lang/rust-clippy/pull/7917)
+
+## Rust 1.58
+
+Current stable, released 2022-01-13
 
 [00e31fa...e181011](https://github.com/rust-lang/rust-clippy/compare/00e31fa...e181011)
 
+### Rust 1.58.1
+
+* Move [`non_send_fields_in_send_ty`] to `nursery` (now allow-by-default)
+  [#8075](https://github.com/rust-lang/rust-clippy/pull/8075)
+* [`useless_format`]: Handle implicit named arguments
+  [#8295](https://github.com/rust-lang/rust-clippy/pull/8295)
+
 ### New lints
 
 * [`transmute_num_to_bytes`]
@@ -124,7 +295,7 @@ Current beta, release 2022-01-13
 
 ## Rust 1.57
 
-Current stable, released 2021-12-02
+Released 2021-12-02
 
 [7bfc26e...00e31fa](https://github.com/rust-lang/rust-clippy/compare/7bfc26e...00e31fa)
 
@@ -2930,6 +3101,7 @@ Released 2018-09-13
 [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const
 [`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback
 [`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access
+[`default_union_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_union_representation
 [`deprecated_cfg_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_cfg_attr
 [`deprecated_semver`]: https://rust-lang.github.io/rust-clippy/master/index.html#deprecated_semver
 [`deref_addrof`]: https://rust-lang.github.io/rust-clippy/master/index.html#deref_addrof
@@ -3303,6 +3475,7 @@ Released 2018-09-13
 [`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
+[`transmute_undefined_repr`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmute_undefined_repr
 [`transmutes_expressible_as_ptr_casts`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmutes_expressible_as_ptr_casts
 [`transmuting_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#transmuting_null
 [`trivial_regex`]: https://rust-lang.github.io/rust-clippy/master/index.html#trivial_regex
index dcc2502e4c59a0f2cf4b01ac0f08669fe828c108..b0fb39e8169968aa57624a6d988879a11021b02c 100644 (file)
@@ -5,9 +5,7 @@
 use std::fs;
 use std::lazy::SyncLazy;
 use std::path::{Path, PathBuf};
-use walkdir::WalkDir;
-
-use crate::clippy_project_root;
+use walkdir::{DirEntry, WalkDir};
 
 #[cfg(not(windows))]
 static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
 ///
 /// Panics if the path to a test file is broken
 pub fn bless(ignore_timestamp: bool) {
-    let test_suite_dirs = [
-        clippy_project_root().join("tests").join("ui"),
-        clippy_project_root().join("tests").join("ui-internal"),
-        clippy_project_root().join("tests").join("ui-toml"),
-        clippy_project_root().join("tests").join("ui-cargo"),
-    ];
-    for test_suite_dir in &test_suite_dirs {
-        WalkDir::new(test_suite_dir)
-            .into_iter()
-            .filter_map(Result::ok)
-            .filter(|f| f.path().extension() == Some(OsStr::new("rs")))
-            .for_each(|f| {
-                let test_name = f.path().strip_prefix(test_suite_dir).unwrap();
-                for &ext in &["stdout", "stderr", "fixed"] {
-                    let test_name_ext = format!("stage-id.{}", ext);
-                    update_reference_file(
-                        f.path().with_extension(ext),
-                        test_name.with_extension(test_name_ext),
-                        ignore_timestamp,
-                    );
-                }
-            });
-    }
+    let extensions = ["stdout", "stderr", "fixed"].map(OsStr::new);
+
+    WalkDir::new(build_dir())
+        .into_iter()
+        .map(Result::unwrap)
+        .filter(|entry| entry.path().extension().map_or(false, |ext| extensions.contains(&ext)))
+        .for_each(|entry| update_reference_file(&entry, ignore_timestamp));
 }
 
-fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf, ignore_timestamp: bool) {
-    let test_output_path = build_dir().join(test_name);
-    let relative_reference_file_path = reference_file_path.strip_prefix(clippy_project_root()).unwrap();
+fn update_reference_file(test_output_entry: &DirEntry, ignore_timestamp: bool) {
+    let test_output_path = test_output_entry.path();
 
-    // If compiletest did not write any changes during the test run,
-    // we don't have to update anything
-    if !test_output_path.exists() {
-        return;
-    }
+    let reference_file_name = test_output_entry.file_name().to_str().unwrap().replace(".stage-id", "");
+    let reference_file_path = Path::new("tests")
+        .join(test_output_path.strip_prefix(build_dir()).unwrap())
+        .with_file_name(reference_file_name);
 
     // If the test output was not updated since the last clippy build, it may be outdated
-    if !ignore_timestamp && !updated_since_clippy_build(&test_output_path).unwrap_or(true) {
+    if !ignore_timestamp && !updated_since_clippy_build(test_output_entry).unwrap_or(true) {
         return;
     }
 
@@ -69,23 +49,14 @@ fn update_reference_file(reference_file_path: PathBuf, test_name: PathBuf, ignor
 
     if test_output_file != reference_file {
         // If a test run caused an output file to change, update the reference file
-        println!("updating {}", &relative_reference_file_path.display());
+        println!("updating {}", reference_file_path.display());
         fs::copy(test_output_path, &reference_file_path).expect("Could not update reference file");
-
-        // We need to re-read the file now because it was potentially updated from copying
-        let reference_file = fs::read(&reference_file_path).unwrap_or_default();
-
-        if reference_file.is_empty() {
-            // If we copied over an empty output file, we remove the now empty reference file
-            println!("removing {}", &relative_reference_file_path.display());
-            fs::remove_file(reference_file_path).expect("Could not remove reference file");
-        }
     }
 }
 
-fn updated_since_clippy_build(path: &Path) -> Option<bool> {
+fn updated_since_clippy_build(entry: &DirEntry) -> Option<bool> {
     let clippy_build_time = (*CLIPPY_BUILD_TIME)?;
-    let modified = fs::metadata(path).ok()?.modified().ok()?;
+    let modified = entry.metadata().ok()?.modified().ok()?;
     Some(modified >= clippy_build_time)
 }
 
index c4956bacf43617a3de0ed2a747e6d377af022430..4c4dd85d518a62ae9db0938d05f56f8fdfed47dc 100644 (file)
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
+use clippy_utils::get_parent_expr;
 use clippy_utils::higher;
 use clippy_utils::source::snippet_block_with_applicability;
 use clippy_utils::ty::implements_trait;
-use clippy_utils::{differing_macro_contexts, get_parent_expr};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, Visitor};
@@ -97,7 +97,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         if let Some(ex) = &block.expr {
                             // don't dig into the expression here, just suggest that they remove
                             // the block
-                            if expr.span.from_expansion() || differing_macro_contexts(expr.span, ex.span) {
+                            if expr.span.from_expansion() || ex.span.from_expansion() {
                                 return;
                             }
                             let mut applicability = Applicability::MachineApplicable;
@@ -122,7 +122,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         }
                     } else {
                         let span = block.expr.as_ref().map_or_else(|| block.stmts[0].span, |e| e.span);
-                        if span.from_expansion() || differing_macro_contexts(expr.span, span) {
+                        if span.from_expansion() || expr.span.from_expansion() {
                             return;
                         }
                         // move block higher
index e71f110820c0b83111e7ce23824e9f3fd98c4430..7637666d059ef319be896210e2e7e0c6cb0feca5 100644 (file)
@@ -47,7 +47,7 @@ fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &
         then {
             let mut ty = ctx.typeck_results().expr_ty(obj);
             ty = match ty.kind() {
-                ty::Ref(_, ty, ..) => ty,
+                ty::Ref(_, ty, ..) => *ty,
                 _ => ty
             };
 
index fb201d2c012b19f9927a8f371ad91cabaa886c96..b80d55dd192a10201dc0fa67c4c49fd7cbdbdbea 100644 (file)
@@ -123,7 +123,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 if let Some(fn_sig) = fn_sig_opt(self.cx, func.hir_id) {
                     for (expr, bound) in iter::zip(*args, fn_sig.skip_binder().inputs()) {
                         // Push found arg type, then visit arg.
-                        self.ty_bounds.push(TyBound::Ty(bound));
+                        self.ty_bounds.push(TyBound::Ty(*bound));
                         self.visit_expr(expr);
                         self.ty_bounds.pop();
                     }
@@ -135,7 +135,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 if let Some(def_id) = self.cx.typeck_results().type_dependent_def_id(expr.hir_id) {
                     let fn_sig = self.cx.tcx.fn_sig(def_id).skip_binder();
                     for (expr, bound) in iter::zip(*args, fn_sig.inputs()) {
-                        self.ty_bounds.push(TyBound::Ty(bound));
+                        self.ty_bounds.push(TyBound::Ty(*bound));
                         self.visit_expr(expr);
                         self.ty_bounds.pop();
                     }
@@ -210,7 +210,7 @@ fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
 
 fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'tcx>> {
     let node_ty = cx.typeck_results().node_type_opt(hir_id)?;
-    // We can't use `TyS::fn_sig` because it automatically performs substs, this may result in FNs.
+    // We can't use `Ty::fn_sig` because it automatically performs substs, this may result in FNs.
     match node_ty.kind() {
         ty::FnDef(def_id, _) => Some(cx.tcx.fn_sig(*def_id)),
         ty::FnPtr(fn_sig) => Some(*fn_sig),
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
new file mode 100644 (file)
index 0000000..9b5da0b
--- /dev/null
@@ -0,0 +1,105 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_hir::{self as hir, HirId, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+use rustc_typeck::hir_ty_to_ty;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Displays a warning when a union is declared with the default representation (without a `#[repr(C)]` attribute).
+    ///
+    /// ### Why is this bad?
+    /// Unions in Rust have unspecified layout by default, despite many people thinking that they
+    /// lay out each field at the start of the union (like C does). That is, there are no guarantees
+    /// about the offset of the fields for unions with multiple non-ZST fields without an explicitly
+    /// specified layout. These cases may lead to undefined behavior in unsafe blocks.
+    ///
+    /// ### Example
+    /// ```rust
+    /// union Foo {
+    ///     a: i32,
+    ///     b: u32,
+    /// }
+    ///
+    /// fn main() {
+    ///     let _x: u32 = unsafe {
+    ///         Foo { a: 0_i32 }.b // Undefined behaviour: `b` is allowed to be padding
+    ///     };
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// #[repr(C)]
+    /// union Foo {
+    ///     a: i32,
+    ///     b: u32,
+    /// }
+    ///
+    /// fn main() {
+    ///     let _x: u32 = unsafe {
+    ///         Foo { a: 0_i32 }.b // Now defined behaviour, this is just an i32 -> u32 transmute
+    ///     };
+    /// }
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub DEFAULT_UNION_REPRESENTATION,
+    restriction,
+    "unions without a `#[repr(C)]` attribute"
+}
+declare_lint_pass!(DefaultUnionRepresentation => [DEFAULT_UNION_REPRESENTATION]);
+
+impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if is_union_with_two_non_zst_fields(cx, item) && !has_c_repr_attr(cx, item.hir_id()) {
+            span_lint_and_help(
+                cx,
+                DEFAULT_UNION_REPRESENTATION,
+                item.span,
+                "this union has the default representation",
+                None,
+                &format!(
+                    "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
+                    cx.tcx.def_path_str(item.def_id.to_def_id())
+                ),
+            );
+        }
+    }
+}
+
+/// Returns true if the given item is a union with at least two non-ZST fields.
+fn is_union_with_two_non_zst_fields(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
+    if let ItemKind::Union(data, _) = &item.kind {
+        data.fields().iter().filter(|f| !is_zst(cx, f.ty)).count() >= 2
+    } else {
+        false
+    }
+}
+
+fn is_zst(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) -> bool {
+    if hir_ty.span.from_expansion() {
+        return false;
+    }
+    let ty = hir_ty_to_ty(cx.tcx, hir_ty);
+    if let Ok(layout) = cx.layout_of(ty) {
+        layout.is_zst()
+    } else {
+        false
+    }
+}
+
+fn has_c_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
+    cx.tcx.hir().attrs(hir_id).iter().any(|attr| {
+        if attr.has_name(sym::repr) {
+            if let Some(items) = attr.meta_item_list() {
+                for item in items {
+                    if item.is_word() && matches!(item.name_or_empty(), sym::C) {
+                        return true;
+                    }
+                }
+            }
+        }
+        false
+    })
+}
index 6d0851d804c26936e2fdb2c876a7f4ea370efac6..fe3911983421b34f383384c939e82c308cde86b6 100644 (file)
@@ -528,7 +528,7 @@ fn is_auto_reborrow_position(parent: Option<Node<'_>>) -> bool {
 fn is_auto_borrow_position(parent: Option<Node<'_>>, child_id: HirId) -> bool {
     if let Some(Node::Expr(parent)) = parent {
         match parent.kind {
-            ExprKind::MethodCall(_, [self_arg, ..], _) => self_arg.hir_id == child_id,
+            // ExprKind::MethodCall(_, [self_arg, ..], _) => self_arg.hir_id == child_id,
             ExprKind::Field(..) => true,
             ExprKind::Call(f, _) => f.hir_id == child_id,
             _ => false,
index 73c00d97020bedf2a6badb9b698b89a59ce9b4de..4c12202c84ab39da96a0c1a54e5b7cb78a43f19c 100644 (file)
@@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         for (index, conf) in self.conf_disallowed.iter().enumerate() {
             let segs: Vec<_> = conf.path().split("::").collect();
-            if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &segs) {
+            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &segs) {
                 self.disallowed.insert(id, index);
             }
         }
index ea4b49b46fe9f6d6e5ca9e6f7e8ee6d3e8f4112b..14f89edce615db9993d811d34e6e8d42d62f8b14 100644 (file)
@@ -96,7 +96,7 @@ fn check_crate(&mut self, cx: &LateContext<'_>) {
                 ),
             };
             let segs: Vec<_> = path.split("::").collect();
-            match clippy_utils::path_to_res(cx, &segs) {
+            match clippy_utils::def_path_res(cx, &segs) {
                 Res::Def(_, id) => {
                     self.def_ids.insert(id, reason);
                 },
index 24d7613e6f8ca6d2061d3d3c3c1e2c6958a9a983..ea547793b1ea2528a0a6662e972b68041d9c4174 100644 (file)
@@ -7,10 +7,10 @@
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{
-    def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, Ty, TyKind,
+    def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, TyS};
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -279,7 +279,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
     }
 }
 
-fn in_impl<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, bin_op: DefId) -> Option<(&'tcx Ty<'tcx>, &'tcx Ty<'tcx>)> {
+fn in_impl<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, bin_op: DefId) -> Option<(&'tcx rustc_hir::Ty<'tcx>, &'tcx rustc_hir::Ty<'tcx>)> {
     if_chain! {
         if let Some(block) = get_enclosing_block(cx, e.hir_id);
         if let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id());
@@ -301,7 +301,7 @@ fn in_impl<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, bin_op: DefId) -> Op
     }
 }
 
-fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: &TyS<'_>, hir_ty: &Ty<'_>) -> bool {
+fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: Ty<'_>, hir_ty: &rustc_hir::Ty<'_>) -> bool {
     if_chain! {
         if let ty::Adt(adt_def, _) = middle_ty.kind();
         if let Some(local_did) = adt_def.did.as_local();
index f326fd83d18e70a16c17de0a8ca5681f5562ee58..3e2217c28da3a0dee72c6d62b567fe6fb3014436 100644 (file)
@@ -1,5 +1,6 @@
-use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::FormatArgsExpn;
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_expn_of, match_function_call, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -79,28 +80,22 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                         "print".into(),
                     )
                 };
-                let msg = format!("use of `{}.unwrap()`", used);
-                if let [write_output] = *format_args.format_string_parts {
-                    let mut write_output = write_output.to_string();
-                    if write_output.ends_with('\n') {
-                        write_output.pop();
-                    }
-
-                    let sugg = format!("{}{}!(\"{}\")", prefix, sugg_mac, write_output.escape_default());
-                    span_lint_and_sugg(
-                        cx,
-                        EXPLICIT_WRITE,
-                        expr.span,
-                        &msg,
-                        "try this",
-                        sugg,
-                        Applicability::MachineApplicable
-                    );
-                } else {
-                    // We don't have a proper suggestion
-                    let help = format!("consider using `{}{}!` instead", prefix, sugg_mac);
-                    span_lint_and_help(cx, EXPLICIT_WRITE, expr.span, &msg, None, &help);
-                }
+                let mut applicability = Applicability::MachineApplicable;
+                let inputs_snippet = snippet_with_applicability(
+                    cx,
+                    format_args.inputs_span(),
+                    "..",
+                    &mut applicability,
+                );
+                span_lint_and_sugg(
+                    cx,
+                    EXPLICIT_WRITE,
+                    expr.span,
+                    &format!("use of `{}.unwrap()`", used),
+                    "try this",
+                    format!("{}{}!({})", prefix, sugg_mac, inputs_snippet),
+                    applicability,
+                )
             }
         }
     }
index 17b0749a4a990f91594d704f325ec5e25f16fcde..503aac8ccd02628a8702a8db7958e3b151896c0e 100644 (file)
@@ -211,7 +211,7 @@ fn count_needed_derefs<'tcx, I>(mut ty: Ty<'tcx>, mut iter: I) -> (usize, Ty<'tc
             if overloaded_deref.is_some() {
                 n_needed = n_total;
             }
-            ty = target;
+            ty = *target;
         } else {
             return (n_needed, ty);
         }
index ae18f8081bcc870d2b90f8a6e0f27a16f68176c5..57964b8d48ea9c4904282e191e097b044b140534 100644 (file)
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
-use clippy_utils::differing_macro_contexts;
 use clippy_utils::source::snippet_opt;
 use if_chain::if_chain;
 use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
@@ -135,7 +134,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
 /// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
 fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
     if let ExprKind::Assign(ref lhs, ref rhs, _) = expr.kind {
-        if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion() {
+        if !lhs.span.from_expansion() && !rhs.span.from_expansion() {
             let eq_span = lhs.span.between(rhs.span);
             if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind {
                 if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
@@ -165,7 +164,7 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
 fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) {
     if_chain! {
         if let ExprKind::Binary(ref binop, ref lhs, ref rhs) = expr.kind;
-        if !differing_macro_contexts(lhs.span, rhs.span) && !lhs.span.from_expansion();
+        if !lhs.span.from_expansion() && !rhs.span.from_expansion();
         // span between BinOp LHS and RHS
         let binop_span = lhs.span.between(rhs.span);
         // if RHS is an UnOp
@@ -206,8 +205,8 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
     if_chain! {
         if let ExprKind::If(_, then, Some(else_)) = &expr.kind;
         if is_block(else_) || is_if(else_);
-        if !differing_macro_contexts(then.span, else_.span);
-        if !then.span.from_expansion() && !in_external_macro(cx.sess(), expr.span);
+        if !then.span.from_expansion() && !else_.span.from_expansion();
+        if !in_external_macro(cx.sess(), expr.span);
 
         // workaround for rust-lang/rust#43081
         if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;
@@ -268,7 +267,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
         for element in array {
             if_chain! {
                 if let ExprKind::Binary(ref op, ref lhs, _) = element.kind;
-                if has_unary_equivalent(op.node) && !differing_macro_contexts(lhs.span, op.span);
+                if has_unary_equivalent(op.node) && lhs.span.ctxt() == op.span.ctxt();
                 let space_span = lhs.span.between(op.span);
                 if let Some(space_snippet) = snippet_opt(cx, space_span);
                 let lint_span = lhs.span.with_lo(lhs.span.hi());
@@ -291,8 +290,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
 
 fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
     if_chain! {
-        if !differing_macro_contexts(first.span, second.span);
-        if !first.span.from_expansion();
+        if !first.span.from_expansion() && !second.span.from_expansion();
         if let ExprKind::If(cond_expr, ..) = &first.kind;
         if is_block(second) || is_if(second);
 
index a2f943b03ef42c4f3f2e7518148e68d0ad615bec..5e4cde553b52e954a0bf7e30f2eed0ef0531e21c 100644 (file)
@@ -17,7 +17,6 @@
 use if_chain::if_chain;
 
 use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
-use clippy_utils::differing_macro_contexts;
 use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::ty::is_type_diagnostic_item;
 
@@ -123,7 +122,7 @@ fn suggestion<'tcx>(
                 vis.visit_ty(impl_.self_ty);
 
                 for target in &vis.found {
-                    if differing_macro_contexts(item.span, target.span()) {
+                    if item.span.ctxt() != target.span().ctxt() {
                         return;
                     }
 
index 2a4bcd773c684a508bcaff5c70c3405cf3ab9e47..6b62748ffef2e2812195961768e5d416197d6a26 100644 (file)
@@ -118,7 +118,7 @@ fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir
                 // The values need to use the `ref` keyword if they can't be copied.
                 // This will need to be adjusted if the lint want to support multable access in the future
                 let src_is_ref = bound_ty.is_ref() && binding != hir::BindingAnnotation::Ref;
-                let needs_ref = !(src_is_ref || is_copy(cx, inner_ty));
+                let needs_ref = !(src_is_ref || is_copy(cx, *inner_ty));
 
                 let slice_info = slices
                     .entry(value_hir_id)
index 3008e86ef8b296da25d2a4e5adc78c614ceed059..b6badef02f58a989e4fa23332fded3c3d3fa7a99 100644 (file)
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{get_trait_def_id, higher, is_qpath_def_path, paths};
+use clippy_utils::{get_trait_def_id, higher, match_def_path, path_def_id, paths};
 use rustc_hir::{BorrowKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -167,13 +167,9 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
         },
         ExprKind::Block(block, _) => block.expr.as_ref().map_or(Finite, |e| is_infinite(cx, e)),
         ExprKind::Box(e) | ExprKind::AddrOf(BorrowKind::Ref, _, e) => is_infinite(cx, e),
-        ExprKind::Call(path, _) => {
-            if let ExprKind::Path(ref qpath) = path.kind {
-                is_qpath_def_path(cx, qpath, path.hir_id, &paths::ITER_REPEAT).into()
-            } else {
-                Finite
-            }
-        },
+        ExprKind::Call(path, _) => path_def_id(cx, path)
+            .map_or(false, |id| match_def_path(cx, id, &paths::ITER_REPEAT))
+            .into(),
         ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(),
         _ => Finite,
     }
index 80260e4cd8315f3c42738bdd19cd0afccd2b1c1c..27db6388136139e1789e570826078a7ddaeba901 100644 (file)
@@ -53,9 +53,9 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
             if let ItemKind::Const(hir_ty, _) = &item.kind;
             let ty = hir_ty_to_ty(cx.tcx, hir_ty);
             if let ty::Array(element_type, cst) = ty.kind();
-            if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val;
+            if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val();
             if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
-            if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes());
+            if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes());
             if self.maximum_allowed_size < element_count * element_size;
 
             then {
index 1cc2c28c04ad4dfb0c351091ec550ed753cb0826..57b0d709acd4de9dcc4efef8062a037ddac23396 100644 (file)
@@ -43,9 +43,9 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
             if let ExprKind::Repeat(_, _) = expr.kind;
             if let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind();
-            if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val;
+            if let ConstKind::Value(ConstValue::Scalar(element_count)) = cst.val();
             if let Ok(element_count) = element_count.to_machine_usize(&cx.tcx);
-            if let Ok(element_size) = cx.layout_of(element_type).map(|l| l.size.bytes());
+            if let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes());
             if self.maximum_allowed_size < element_count * element_size;
             then {
                 span_lint_and_help(
index 3418d276c53549d1cd55fc0bbad490fd782d3b08..35d10d53112ec6c3591555833dcace76f3c9ed6c 100644 (file)
@@ -294,7 +294,7 @@ fn expected_sig(self, self_kind: ImplicitSelfKind) -> String {
 /// Checks if the given signature matches the expectations for `is_empty`
 fn check_is_empty_sig(sig: FnSig<'_>, self_kind: ImplicitSelfKind, len_output: LenOutput<'_>) -> bool {
     match &**sig.inputs_and_output {
-        [arg, res] if len_output.matches_is_empty_output(res) => {
+        [arg, res] if len_output.matches_is_empty_output(*res) => {
             matches!(
                 (arg.kind(), self_kind),
                 (ty::Ref(_, _, Mutability::Not), ImplicitSelfKind::ImmRef)
index 2d2693832e9716721feb10b87b1e9fba457e205a..a80320a578f0e7ba609c90fad800c08ab7c8b456 100644 (file)
@@ -92,6 +92,7 @@
     default::DEFAULT_TRAIT_ACCESS,
     default::FIELD_REASSIGN_WITH_DEFAULT,
     default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK,
+    default_union_representation::DEFAULT_UNION_REPRESENTATION,
     dereference::EXPLICIT_DEREF_METHODS,
     dereference::NEEDLESS_BORROW,
     dereference::REF_BINDING_TO_REFERENCE,
     transmute::TRANSMUTE_NUM_TO_BYTES,
     transmute::TRANSMUTE_PTR_TO_PTR,
     transmute::TRANSMUTE_PTR_TO_REF,
+    transmute::TRANSMUTE_UNDEFINED_REPR,
     transmute::UNSOUND_COLLECTION_TRANSMUTE,
     transmute::USELESS_TRANSMUTE,
     transmute::WRONG_TRANSMUTE,
index a7353790100267681b11ae92b234125b48571dfe..8d4dde42bbecad322b0d3ba28da5e24a8ac8d7f2 100644 (file)
@@ -26,6 +26,7 @@
     LintId::of(strings::STRING_LIT_AS_BYTES),
     LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS),
     LintId::of(trailing_empty_array::TRAILING_EMPTY_ARRAY),
+    LintId::of(transmute::TRANSMUTE_UNDEFINED_REPR),
     LintId::of(transmute::USELESS_TRANSMUTE),
     LintId::of(use_self::USE_SELF),
 ])
index e7e2798da7da99785f7b46c6410ee615f00c4bcd..5a89fdb05a9904ab1442fd73bada9b12c7be9a37 100644 (file)
@@ -12,6 +12,7 @@
     LintId::of(create_dir::CREATE_DIR),
     LintId::of(dbg_macro::DBG_MACRO),
     LintId::of(default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK),
+    LintId::of(default_union_representation::DEFAULT_UNION_REPRESENTATION),
     LintId::of(disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS),
     LintId::of(else_if_without_else::ELSE_IF_WITHOUT_ELSE),
     LintId::of(exhaustive_items::EXHAUSTIVE_ENUMS),
index f2a7e925dd3952e698461b003c7347330fc020f0..5c45012ef0686c12bc2e9b5bdbb38bab033b7184 100644 (file)
@@ -17,6 +17,8 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 // warn on rustc internal lints
 #![warn(rustc::internal)]
+// Disable this rustc lint for now, as it was also done in rustc
+#![cfg_attr(not(bootstrap), allow(rustc::potential_query_instability))]
 
 // FIXME: switch to something more ergonomic here, once available.
 // (Currently there is no way to opt into sysroot crates without `extern crate`.)
@@ -189,6 +191,7 @@ macro_rules! declare_clippy_lint {
 mod dbg_macro;
 mod default;
 mod default_numeric_fallback;
+mod default_union_representation;
 mod dereference;
 mod derivable_impls;
 mod derive;
@@ -859,6 +862,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| Box::new(single_char_lifetime_names::SingleCharLifetimeNames));
     store.register_late_pass(move || Box::new(borrow_as_ptr::BorrowAsPtr::new(msrv)));
     store.register_late_pass(move || Box::new(manual_bits::ManualBits::new(msrv)));
+    store.register_late_pass(|| Box::new(default_union_representation::DefaultUnionRepresentation));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
index e0150990cfe5fb42ee247f996df71f33d101893b..fc50e8addccec8f84e87c03fffedd10a92daa3dd 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_hir::intravisit::{walk_block, walk_expr};
 use rustc_hir::{Expr, Pat};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, UintTy};
+use rustc_middle::ty::{self, Ty, UintTy};
 
 // To trigger the EXPLICIT_COUNTER_LOOP lint, a variable must be
 // incremented exactly once in the loop body, and initialized to zero
@@ -36,7 +36,7 @@ pub(super) fn check<'tcx>(
                 then {
                     let mut applicability = Applicability::MachineApplicable;
 
-                    let int_name = match ty.map(ty::TyS::kind) {
+                    let int_name = match ty.map(Ty::kind) {
                         // usize or inferred
                         Some(ty::Uint(UintTy::Usize)) | None => {
                             span_lint_and_sugg(
index ef0221639aa940414ea29f146b3c53f9511d8067..f6ef87264c0a6f3b8f2a70cf3f3e3a44164c3f85 100644 (file)
@@ -335,8 +335,8 @@ struct Start<'hir> {
 fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     match ty.kind() {
         ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Vec, adt.did) => Some(subs.type_at(0)),
-        ty::Ref(_, subty, _) => get_slice_like_element_ty(cx, subty),
-        ty::Slice(ty) | ty::Array(ty, _) => Some(ty),
+        ty::Ref(_, subty, _) => get_slice_like_element_ty(cx, *subty),
+        ty::Slice(ty) | ty::Array(ty, _) => Some(*ty),
         _ => None,
     }
 }
index f57dcc2f5c453ead3d76b1d2f31e23678bb36dad..06190850bb003ebe1ef2d772e462dd35289e7a12 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::{self, TyS};
+use rustc_middle::ty::{self, Ty};
 use rustc_span::sym;
 use rustc_span::{MultiSpan, Span};
 
@@ -334,8 +334,8 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>(
     }
 }
 
-fn get_captured_ids(cx: &LateContext<'_>, ty: &'_ TyS<'_>) -> HirIdSet {
-    fn get_captured_ids_recursive(cx: &LateContext<'_>, ty: &'_ TyS<'_>, set: &mut HirIdSet) {
+fn get_captured_ids(cx: &LateContext<'_>, ty: Ty<'_>) -> HirIdSet {
+    fn get_captured_ids_recursive(cx: &LateContext<'_>, ty: Ty<'_>, set: &mut HirIdSet) {
         match ty.kind() {
             ty::Adt(_, generics) => {
                 for generic in *generics {
index 15f419e4410ca86ccdf83c2843c58b63625122bb..36ecd83f7d643734e0f0f2df0977cd63f3c5ea70 100644 (file)
@@ -1,10 +1,9 @@
 use super::SINGLE_ELEMENT_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::single_segment_path;
-use clippy_utils::source::{indent_of, snippet};
+use clippy_utils::source::{indent_of, snippet_with_applicability};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, Pat, PatKind};
+use rustc_hir::{BorrowKind, Expr, ExprKind, Pat};
 use rustc_lint::LateContext;
 
 pub(super) fn check<'tcx>(
@@ -16,24 +15,21 @@ pub(super) fn check<'tcx>(
 ) {
     let arg_expr = match arg.kind {
         ExprKind::AddrOf(BorrowKind::Ref, _, ref_arg) => ref_arg,
-        ExprKind::MethodCall(method, args, _) if args.len() == 1 && method.ident.name == rustc_span::sym::iter => {
-            &args[0]
-        },
+        ExprKind::MethodCall(method, [arg], _) if method.ident.name == rustc_span::sym::iter => arg,
         _ => return,
     };
     if_chain! {
-        if let PatKind::Binding(.., target, _) = pat.kind;
         if let ExprKind::Array([arg_expression]) = arg_expr.kind;
-        if let ExprKind::Path(ref list_item) = arg_expression.kind;
-        if let Some(list_item_name) = single_segment_path(list_item).map(|ps| ps.ident.name);
         if let ExprKind::Block(block, _) = body.kind;
         if !block.stmts.is_empty();
-
         then {
-            let mut block_str = snippet(cx, block.span, "..").into_owned();
+            let mut applicability = Applicability::MachineApplicable;
+            let pat_snip = snippet_with_applicability(cx, pat.span, "..", &mut applicability);
+            let arg_snip = snippet_with_applicability(cx, arg_expression.span, "..", &mut applicability);
+            let mut block_str = snippet_with_applicability(cx, block.span, "..", &mut applicability).into_owned();
             block_str.remove(0);
             block_str.pop();
-
+            let indent = " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0));
 
             span_lint_and_sugg(
                 cx,
@@ -41,8 +37,8 @@ pub(super) fn check<'tcx>(
                 expr.span,
                 "for loop over a single element",
                 "try",
-                format!("{{\n{}let {} = &{};{}}}", " ".repeat(indent_of(cx, block.stmts[0].span).unwrap_or(0)), target.name, list_item_name, block_str),
-                Applicability::MachineApplicable
+                format!("{{\n{}let {} = &{};{}}}", indent, pat_snip, arg_snip, block_str),
+                applicability,
             )
         }
     }
index eac0f03b142a821c56ade84d17f2ea5fe8264f04..772d251b620a80f45a96ef89b3972a2f16572727 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, Pat, PatKind, Stmt};
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_typeck::hir_ty_to_ty;
@@ -332,18 +332,21 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
     } else {
         // (&x).into_iter() ==> x.iter()
         // (&mut x).into_iter() ==> x.iter_mut()
-        match &arg.kind {
-            ExprKind::AddrOf(BorrowKind::Ref, mutability, arg_inner)
-                if has_iter_method(cx, cx.typeck_results().expr_ty(arg_inner)).is_some() =>
-            {
-                let meth_name = match mutability {
+        let arg_ty = cx.typeck_results().expr_ty_adjusted(arg);
+        match &arg_ty.kind() {
+            ty::Ref(_, inner_ty, mutbl) if has_iter_method(cx, *inner_ty).is_some() => {
+                let method_name = match mutbl {
                     Mutability::Mut => "iter_mut",
                     Mutability::Not => "iter",
                 };
+                let caller = match &arg.kind {
+                    ExprKind::AddrOf(BorrowKind::Ref, _, arg_inner) => arg_inner,
+                    _ => arg,
+                };
                 format!(
                     "{}.{}()",
-                    sugg::Sugg::hir_with_applicability(cx, arg_inner, "_", applic_ref).maybe_par(),
-                    meth_name,
+                    sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_par(),
+                    method_name,
                 )
             },
             _ => format!(
index 3f8eeb736fbd2e5c155054c7176c04dc0abe8bc4..e233300e26ab898e94efcdbd13b5bee37b6dbcf7 100644 (file)
@@ -100,7 +100,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
                                     let obj_ty = cx.typeck_results().expr_ty(obj);
                                     if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
                                         if matches!(mutability, Mutability::Not) {
-                                            let copy = is_copy(cx, ty);
+                                            let copy = is_copy(cx, *ty);
                                             self.lint_explicit_closure(cx, e.span, args[0].span, copy);
                                         }
                                     } else {
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
deleted file mode 100644 (file)
index e61cb4d..0000000
+++ /dev/null
@@ -1,2342 +0,0 @@
-use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
-use clippy_utils::diagnostics::{
-    multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then,
-};
-use clippy_utils::macros::{is_panic, root_macro_call};
-use clippy_utils::source::{expr_block, indent_of, snippet, snippet_block, snippet_opt, snippet_with_applicability};
-use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, match_type, peel_mid_ty_refs};
-use clippy_utils::visitors::is_local_used;
-use clippy_utils::{
-    get_parent_expr, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs,
-    path_to_local, path_to_local_id, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs, recurse_or_patterns,
-    strip_pat_refs,
-};
-use clippy_utils::{higher, peel_blocks_with_stmt};
-use clippy_utils::{paths, search_same, SpanlessEq, SpanlessHash};
-use core::iter::{once, ExactSizeIterator};
-use if_chain::if_chain;
-use rustc_ast::ast::{Attribute, LitKind};
-use rustc_errors::Applicability;
-use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::LangItem::{OptionNone, OptionSome};
-use rustc_hir::{
-    self as hir, Arm, BindingAnnotation, Block, BorrowKind, Expr, ExprKind, Guard, HirId, Local, MatchSource,
-    Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind,
-};
-use rustc_hir::{HirIdMap, HirIdSet};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, Ty, VariantDef};
-use rustc_semver::RustcVersion;
-use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::{Span, Spanned};
-use rustc_span::{sym, symbol::kw};
-use std::cmp::Ordering;
-use std::collections::hash_map::Entry;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for matches with a single arm where an `if let`
-    /// will usually suffice.
-    ///
-    /// ### Why is this bad?
-    /// Just readability – `if let` nests less than a `match`.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # fn bar(stool: &str) {}
-    /// # let x = Some("abc");
-    /// // Bad
-    /// match x {
-    ///     Some(ref foo) => bar(foo),
-    ///     _ => (),
-    /// }
-    ///
-    /// // Good
-    /// if let Some(ref foo) = x {
-    ///     bar(foo);
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub SINGLE_MATCH,
-    style,
-    "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for matches with two arms where an `if let else` will
-    /// usually suffice.
-    ///
-    /// ### Why is this bad?
-    /// Just readability – `if let` nests less than a `match`.
-    ///
-    /// ### Known problems
-    /// Personal style preferences may differ.
-    ///
-    /// ### Example
-    /// Using `match`:
-    ///
-    /// ```rust
-    /// # fn bar(foo: &usize) {}
-    /// # let other_ref: usize = 1;
-    /// # let x: Option<&usize> = Some(&1);
-    /// match x {
-    ///     Some(ref foo) => bar(foo),
-    ///     _ => bar(&other_ref),
-    /// }
-    /// ```
-    ///
-    /// Using `if let` with `else`:
-    ///
-    /// ```rust
-    /// # fn bar(foo: &usize) {}
-    /// # let other_ref: usize = 1;
-    /// # let x: Option<&usize> = Some(&1);
-    /// if let Some(ref foo) = x {
-    ///     bar(foo);
-    /// } else {
-    ///     bar(&other_ref);
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub SINGLE_MATCH_ELSE,
-    pedantic,
-    "a `match` statement with two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for matches where all arms match a reference,
-    /// suggesting to remove the reference and deref the matched expression
-    /// instead. It also checks for `if let &foo = bar` blocks.
-    ///
-    /// ### Why is this bad?
-    /// It just makes the code less readable. That reference
-    /// destructuring adds nothing to the code.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// // Bad
-    /// match x {
-    ///     &A(ref y) => foo(y),
-    ///     &B => bar(),
-    ///     _ => frob(&x),
-    /// }
-    ///
-    /// // Good
-    /// match *x {
-    ///     A(ref y) => foo(y),
-    ///     B => bar(),
-    ///     _ => frob(x),
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub MATCH_REF_PATS,
-    style,
-    "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for matches where match expression is a `bool`. It
-    /// suggests to replace the expression with an `if...else` block.
-    ///
-    /// ### Why is this bad?
-    /// It makes the code less readable.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # fn foo() {}
-    /// # fn bar() {}
-    /// let condition: bool = true;
-    /// match condition {
-    ///     true => foo(),
-    ///     false => bar(),
-    /// }
-    /// ```
-    /// Use if/else instead:
-    /// ```rust
-    /// # fn foo() {}
-    /// # fn bar() {}
-    /// let condition: bool = true;
-    /// if condition {
-    ///     foo();
-    /// } else {
-    ///     bar();
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub MATCH_BOOL,
-    pedantic,
-    "a `match` on a boolean expression instead of an `if..else` block"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for overlapping match arms.
-    ///
-    /// ### Why is this bad?
-    /// It is likely to be an error and if not, makes the code
-    /// less obvious.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let x = 5;
-    /// match x {
-    ///     1..=10 => println!("1 ... 10"),
-    ///     5..=15 => println!("5 ... 15"),
-    ///     _ => (),
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub MATCH_OVERLAPPING_ARM,
-    style,
-    "a `match` with overlapping arms"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for arm which matches all errors with `Err(_)`
-    /// and take drastic actions like `panic!`.
-    ///
-    /// ### Why is this bad?
-    /// It is generally a bad practice, similar to
-    /// catching all exceptions in java with `catch(Exception)`
-    ///
-    /// ### Example
-    /// ```rust
-    /// let x: Result<i32, &str> = Ok(3);
-    /// match x {
-    ///     Ok(_) => println!("ok"),
-    ///     Err(_) => panic!("err"),
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub MATCH_WILD_ERR_ARM,
-    pedantic,
-    "a `match` with `Err(_)` arm and take drastic actions"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for match which is used to add a reference to an
-    /// `Option` value.
-    ///
-    /// ### Why is this bad?
-    /// Using `as_ref()` or `as_mut()` instead is shorter.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let x: Option<()> = None;
-    ///
-    /// // Bad
-    /// let r: Option<&()> = match x {
-    ///     None => None,
-    ///     Some(ref v) => Some(v),
-    /// };
-    ///
-    /// // Good
-    /// let r: Option<&()> = x.as_ref();
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub MATCH_AS_REF,
-    complexity,
-    "a `match` on an Option value instead of using `as_ref()` or `as_mut`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for wildcard enum matches using `_`.
-    ///
-    /// ### Why is this bad?
-    /// New enum variants added by library updates can be missed.
-    ///
-    /// ### Known problems
-    /// Suggested replacements may be incorrect if guards exhaustively cover some
-    /// variants, and also may not use correct path to enum if it's not present in the current scope.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # enum Foo { A(usize), B(usize) }
-    /// # let x = Foo::B(1);
-    /// // Bad
-    /// match x {
-    ///     Foo::A(_) => {},
-    ///     _ => {},
-    /// }
-    ///
-    /// // Good
-    /// match x {
-    ///     Foo::A(_) => {},
-    ///     Foo::B(_) => {},
-    /// }
-    /// ```
-    #[clippy::version = "1.34.0"]
-    pub WILDCARD_ENUM_MATCH_ARM,
-    restriction,
-    "a wildcard enum match arm using `_`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for wildcard enum matches for a single variant.
-    ///
-    /// ### Why is this bad?
-    /// New enum variants added by library updates can be missed.
-    ///
-    /// ### Known problems
-    /// Suggested replacements may not use correct path to enum
-    /// if it's not present in the current scope.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # enum Foo { A, B, C }
-    /// # let x = Foo::B;
-    /// // Bad
-    /// match x {
-    ///     Foo::A => {},
-    ///     Foo::B => {},
-    ///     _ => {},
-    /// }
-    ///
-    /// // Good
-    /// match x {
-    ///     Foo::A => {},
-    ///     Foo::B => {},
-    ///     Foo::C => {},
-    /// }
-    /// ```
-    #[clippy::version = "1.45.0"]
-    pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
-    pedantic,
-    "a wildcard enum match for a single variant"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for wildcard pattern used with others patterns in same match arm.
-    ///
-    /// ### Why is this bad?
-    /// Wildcard pattern already covers any other pattern as it will match anyway.
-    /// It makes the code less readable, especially to spot wildcard pattern use in match arm.
-    ///
-    /// ### Example
-    /// ```rust
-    /// // Bad
-    /// match "foo" {
-    ///     "a" => {},
-    ///     "bar" | _ => {},
-    /// }
-    ///
-    /// // Good
-    /// match "foo" {
-    ///     "a" => {},
-    ///     _ => {},
-    /// }
-    /// ```
-    #[clippy::version = "1.42.0"]
-    pub WILDCARD_IN_OR_PATTERNS,
-    complexity,
-    "a wildcard pattern used with others patterns in same match arm"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for matches being used to destructure a single-variant enum
-    /// or tuple struct where a `let` will suffice.
-    ///
-    /// ### Why is this bad?
-    /// Just readability – `let` doesn't nest, whereas a `match` does.
-    ///
-    /// ### Example
-    /// ```rust
-    /// enum Wrapper {
-    ///     Data(i32),
-    /// }
-    ///
-    /// let wrapper = Wrapper::Data(42);
-    ///
-    /// let data = match wrapper {
-    ///     Wrapper::Data(i) => i,
-    /// };
-    /// ```
-    ///
-    /// The correct use would be:
-    /// ```rust
-    /// enum Wrapper {
-    ///     Data(i32),
-    /// }
-    ///
-    /// let wrapper = Wrapper::Data(42);
-    /// let Wrapper::Data(data) = wrapper;
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub INFALLIBLE_DESTRUCTURING_MATCH,
-    style,
-    "a `match` statement with a single infallible arm instead of a `let`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for useless match that binds to only one value.
-    ///
-    /// ### Why is this bad?
-    /// Readability and needless complexity.
-    ///
-    /// ### Known problems
-    ///  Suggested replacements may be incorrect when `match`
-    /// is actually binding temporary value, bringing a 'dropped while borrowed' error.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # let a = 1;
-    /// # let b = 2;
-    ///
-    /// // Bad
-    /// match (a, b) {
-    ///     (c, d) => {
-    ///         // useless match
-    ///     }
-    /// }
-    ///
-    /// // Good
-    /// let (c, d) = (a, b);
-    /// ```
-    #[clippy::version = "1.43.0"]
-    pub MATCH_SINGLE_BINDING,
-    complexity,
-    "a match with a single binding instead of using `let` statement"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched.
-    ///
-    /// ### Why is this bad?
-    /// Correctness and readability. It's like having a wildcard pattern after
-    /// matching all enum variants explicitly.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # struct A { a: i32 }
-    /// let a = A { a: 5 };
-    ///
-    /// // Bad
-    /// match a {
-    ///     A { a: 5, .. } => {},
-    ///     _ => {},
-    /// }
-    ///
-    /// // Good
-    /// match a {
-    ///     A { a: 5 } => {},
-    ///     _ => {},
-    /// }
-    /// ```
-    #[clippy::version = "1.43.0"]
-    pub REST_PAT_IN_FULLY_BOUND_STRUCTS,
-    restriction,
-    "a match on a struct that binds all fields but still uses the wildcard pattern"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Lint for redundant pattern matching over `Result`, `Option`,
-    /// `std::task::Poll` or `std::net::IpAddr`
-    ///
-    /// ### Why is this bad?
-    /// It's more concise and clear to just use the proper
-    /// utility function
-    ///
-    /// ### Known problems
-    /// This will change the drop order for the matched type. Both `if let` and
-    /// `while let` will drop the value at the end of the block, both `if` and `while` will drop the
-    /// value before entering the block. For most types this change will not matter, but for a few
-    /// types this will not be an acceptable change (e.g. locks). See the
-    /// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
-    /// drop order.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # use std::task::Poll;
-    /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    /// if let Ok(_) = Ok::<i32, i32>(42) {}
-    /// if let Err(_) = Err::<i32, i32>(42) {}
-    /// if let None = None::<()> {}
-    /// if let Some(_) = Some(42) {}
-    /// if let Poll::Pending = Poll::Pending::<()> {}
-    /// if let Poll::Ready(_) = Poll::Ready(42) {}
-    /// if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {}
-    /// if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {}
-    /// match Ok::<i32, i32>(42) {
-    ///     Ok(_) => true,
-    ///     Err(_) => false,
-    /// };
-    /// ```
-    ///
-    /// The more idiomatic use would be:
-    ///
-    /// ```rust
-    /// # use std::task::Poll;
-    /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
-    /// if Ok::<i32, i32>(42).is_ok() {}
-    /// if Err::<i32, i32>(42).is_err() {}
-    /// if None::<()>.is_none() {}
-    /// if Some(42).is_some() {}
-    /// if Poll::Pending::<()>.is_pending() {}
-    /// if Poll::Ready(42).is_ready() {}
-    /// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
-    /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
-    /// Ok::<i32, i32>(42).is_ok();
-    /// ```
-    #[clippy::version = "1.31.0"]
-    pub REDUNDANT_PATTERN_MATCHING,
-    style,
-    "use the proper utility function avoiding an `if let`"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for `match`  or `if let` expressions producing a
-    /// `bool` that could be written using `matches!`
-    ///
-    /// ### Why is this bad?
-    /// Readability and needless complexity.
-    ///
-    /// ### Known problems
-    /// This lint falsely triggers, if there are arms with
-    /// `cfg` attributes that remove an arm evaluating to `false`.
-    ///
-    /// ### Example
-    /// ```rust
-    /// let x = Some(5);
-    ///
-    /// // Bad
-    /// let a = match x {
-    ///     Some(0) => true,
-    ///     _ => false,
-    /// };
-    ///
-    /// let a = if let Some(0) = x {
-    ///     true
-    /// } else {
-    ///     false
-    /// };
-    ///
-    /// // Good
-    /// let a = matches!(x, Some(0));
-    /// ```
-    #[clippy::version = "1.47.0"]
-    pub MATCH_LIKE_MATCHES_MACRO,
-    style,
-    "a match that could be written with the matches! macro"
-}
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for `match` with identical arm bodies.
-    ///
-    /// ### Why is this bad?
-    /// This is probably a copy & paste error. If arm bodies
-    /// are the same on purpose, you can factor them
-    /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
-    ///
-    /// ### Known problems
-    /// False positive possible with order dependent `match`
-    /// (see issue
-    /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// match foo {
-    ///     Bar => bar(),
-    ///     Quz => quz(),
-    ///     Baz => bar(), // <= oops
-    /// }
-    /// ```
-    ///
-    /// This should probably be
-    /// ```rust,ignore
-    /// match foo {
-    ///     Bar => bar(),
-    ///     Quz => quz(),
-    ///     Baz => baz(), // <= fixed
-    /// }
-    /// ```
-    ///
-    /// or if the original code was not a typo:
-    /// ```rust,ignore
-    /// match foo {
-    ///     Bar | Baz => bar(), // <= shows the intent better
-    ///     Quz => quz(),
-    /// }
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub MATCH_SAME_ARMS,
-    pedantic,
-    "`match` with identical arm bodies"
-}
-
-#[derive(Default)]
-pub struct Matches {
-    msrv: Option<RustcVersion>,
-    infallible_destructuring_match_linted: bool,
-}
-
-impl Matches {
-    #[must_use]
-    pub fn new(msrv: Option<RustcVersion>) -> Self {
-        Self {
-            msrv,
-            ..Matches::default()
-        }
-    }
-}
-
-impl_lint_pass!(Matches => [
-    SINGLE_MATCH,
-    MATCH_REF_PATS,
-    MATCH_BOOL,
-    SINGLE_MATCH_ELSE,
-    MATCH_OVERLAPPING_ARM,
-    MATCH_WILD_ERR_ARM,
-    MATCH_AS_REF,
-    WILDCARD_ENUM_MATCH_ARM,
-    MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
-    WILDCARD_IN_OR_PATTERNS,
-    MATCH_SINGLE_BINDING,
-    INFALLIBLE_DESTRUCTURING_MATCH,
-    REST_PAT_IN_FULLY_BOUND_STRUCTS,
-    REDUNDANT_PATTERN_MATCHING,
-    MATCH_LIKE_MATCHES_MACRO,
-    MATCH_SAME_ARMS,
-]);
-
-impl<'tcx> LateLintPass<'tcx> for Matches {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if expr.span.from_expansion() {
-            return;
-        }
-
-        redundant_pattern_match::check(cx, expr);
-
-        if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) {
-            if !check_match_like_matches(cx, expr) {
-                lint_match_arms(cx, expr);
-            }
-        } else {
-            lint_match_arms(cx, expr);
-        }
-
-        if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
-            check_single_match(cx, ex, arms, expr);
-            check_match_bool(cx, ex, arms, expr);
-            check_overlapping_arms(cx, ex, arms);
-            check_wild_err_arm(cx, ex, arms);
-            check_wild_enum_match(cx, ex, arms);
-            check_match_as_ref(cx, ex, arms, expr);
-            check_wild_in_or_pats(cx, arms);
-
-            if self.infallible_destructuring_match_linted {
-                self.infallible_destructuring_match_linted = false;
-            } else {
-                check_match_single_binding(cx, ex, arms, expr);
-            }
-        }
-        if let ExprKind::Match(ex, arms, _) = expr.kind {
-            check_match_ref_pats(cx, ex, arms.iter().map(|el| el.pat), expr);
-        }
-    }
-
-    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
-        if_chain! {
-            if !local.span.from_expansion();
-            if let Some(expr) = local.init;
-            if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind;
-            if arms.len() == 1 && arms[0].guard.is_none();
-            if let PatKind::TupleStruct(
-                QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
-            if args.len() == 1;
-            if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
-            let body = peel_blocks(arms[0].body);
-            if path_to_local_id(body, arg);
-
-            then {
-                let mut applicability = Applicability::MachineApplicable;
-                self.infallible_destructuring_match_linted = true;
-                span_lint_and_sugg(
-                    cx,
-                    INFALLIBLE_DESTRUCTURING_MATCH,
-                    local.span,
-                    "you seem to be trying to use `match` to destructure a single infallible pattern. \
-                    Consider using `let`",
-                    "try this",
-                    format!(
-                        "let {}({}) = {};",
-                        snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
-                        snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
-                        snippet_with_applicability(cx, target.span, "..", &mut applicability),
-                    ),
-                    applicability,
-                );
-            }
-        }
-    }
-
-    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        if_chain! {
-            if !pat.span.from_expansion();
-            if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
-            if let Some(def_id) = path.res.opt_def_id();
-            let ty = cx.tcx.type_of(def_id);
-            if let ty::Adt(def, _) = ty.kind();
-            if def.is_struct() || def.is_union();
-            if fields.len() == def.non_enum_variant().fields.len();
-
-            then {
-                span_lint_and_help(
-                    cx,
-                    REST_PAT_IN_FULLY_BOUND_STRUCTS,
-                    pat.span,
-                    "unnecessary use of `..` pattern in struct binding. All fields were already bound",
-                    None,
-                    "consider removing `..` from this binding",
-                );
-            }
-        }
-    }
-
-    extract_msrv_attr!(LateContext);
-}
-
-#[rustfmt::skip]
-fn check_single_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
-    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
-        if expr.span.from_expansion() {
-            // Don't lint match expressions present in
-            // macro_rules! block
-            return;
-        }
-        if let PatKind::Or(..) = arms[0].pat.kind {
-            // don't lint for or patterns for now, this makes
-            // the lint noisy in unnecessary situations
-            return;
-        }
-        let els = arms[1].body;
-        let els = if is_unit_expr(peel_blocks(els)) {
-            None
-        } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
-            if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
-                // single statement/expr "else" block, don't lint
-                return;
-            }
-            // block with 2+ statements or 1 expr and 1+ statement
-            Some(els)
-        } else {
-            // not a block, don't lint
-            return;
-        };
-
-        let ty = cx.typeck_results().expr_ty(ex);
-        if *ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id) {
-            check_single_match_single_pattern(cx, ex, arms, expr, els);
-            check_single_match_opt_like(cx, ex, arms, expr, ty, els);
-        }
-    }
-}
-
-fn check_single_match_single_pattern(
-    cx: &LateContext<'_>,
-    ex: &Expr<'_>,
-    arms: &[Arm<'_>],
-    expr: &Expr<'_>,
-    els: Option<&Expr<'_>>,
-) {
-    if is_wild(arms[1].pat) {
-        report_single_match_single_pattern(cx, ex, arms, expr, els);
-    }
-}
-
-fn report_single_match_single_pattern(
-    cx: &LateContext<'_>,
-    ex: &Expr<'_>,
-    arms: &[Arm<'_>],
-    expr: &Expr<'_>,
-    els: Option<&Expr<'_>>,
-) {
-    let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
-    let els_str = els.map_or(String::new(), |els| {
-        format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
-    });
-
-    let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
-    let (msg, sugg) = if_chain! {
-        if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind;
-        let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex));
-        if let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait();
-        if let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait();
-        if ty.is_integral() || ty.is_char() || ty.is_str()
-            || (implements_trait(cx, ty, spe_trait_id, &[])
-                && implements_trait(cx, ty, pe_trait_id, &[ty.into()]));
-        then {
-            // scrutinee derives PartialEq and the pattern is a constant.
-            let pat_ref_count = match pat.kind {
-                // string literals are already a reference.
-                PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1,
-                _ => pat_ref_count,
-            };
-            // References are only implicitly added to the pattern, so no overflow here.
-            // e.g. will work: match &Some(_) { Some(_) => () }
-            // will not: match Some(_) { &Some(_) => () }
-            let ref_count_diff = ty_ref_count - pat_ref_count;
-
-            // Try to remove address of expressions first.
-            let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
-            let ref_count_diff = ref_count_diff - removed;
-
-            let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
-            let sugg = format!(
-                "if {} == {}{} {}{}",
-                snippet(cx, ex.span, ".."),
-                // PartialEq for different reference counts may not exist.
-                "&".repeat(ref_count_diff),
-                snippet(cx, arms[0].pat.span, ".."),
-                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
-                els_str,
-            );
-            (msg, sugg)
-        } else {
-            let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
-            let sugg = format!(
-                "if let {} = {} {}{}",
-                snippet(cx, arms[0].pat.span, ".."),
-                snippet(cx, ex.span, ".."),
-                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
-                els_str,
-            );
-            (msg, sugg)
-        }
-    };
-
-    span_lint_and_sugg(
-        cx,
-        lint,
-        expr.span,
-        msg,
-        "try this",
-        sugg,
-        Applicability::HasPlaceholders,
-    );
-}
-
-fn check_single_match_opt_like(
-    cx: &LateContext<'_>,
-    ex: &Expr<'_>,
-    arms: &[Arm<'_>],
-    expr: &Expr<'_>,
-    ty: Ty<'_>,
-    els: Option<&Expr<'_>>,
-) {
-    // list of candidate `Enum`s we know will never get any more members
-    let candidates = &[
-        (&paths::COW, "Borrowed"),
-        (&paths::COW, "Cow::Borrowed"),
-        (&paths::COW, "Cow::Owned"),
-        (&paths::COW, "Owned"),
-        (&paths::OPTION, "None"),
-        (&paths::RESULT, "Err"),
-        (&paths::RESULT, "Ok"),
-    ];
-
-    let path = match arms[1].pat.kind {
-        PatKind::TupleStruct(ref path, inner, _) => {
-            // Contains any non wildcard patterns (e.g., `Err(err)`)?
-            if !inner.iter().all(is_wild) {
-                return;
-            }
-            rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
-        },
-        PatKind::Binding(BindingAnnotation::Unannotated, .., ident, None) => ident.to_string(),
-        PatKind::Path(ref path) => {
-            rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false))
-        },
-        _ => return,
-    };
-
-    for &(ty_path, pat_path) in candidates {
-        if path == *pat_path && match_type(cx, ty, ty_path) {
-            report_single_match_single_pattern(cx, ex, arms, expr, els);
-        }
-    }
-}
-
-fn check_match_bool(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
-    // Type of expression is `bool`.
-    if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool {
-        span_lint_and_then(
-            cx,
-            MATCH_BOOL,
-            expr.span,
-            "you seem to be trying to match on a boolean expression",
-            move |diag| {
-                if arms.len() == 2 {
-                    // no guards
-                    let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
-                        if let ExprKind::Lit(ref lit) = arm_bool.kind {
-                            match lit.node {
-                                LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)),
-                                LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)),
-                                _ => None,
-                            }
-                        } else {
-                            None
-                        }
-                    } else {
-                        None
-                    };
-
-                    if let Some((true_expr, false_expr)) = exprs {
-                        let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) {
-                            (false, false) => Some(format!(
-                                "if {} {} else {}",
-                                snippet(cx, ex.span, "b"),
-                                expr_block(cx, true_expr, None, "..", Some(expr.span)),
-                                expr_block(cx, false_expr, None, "..", Some(expr.span))
-                            )),
-                            (false, true) => Some(format!(
-                                "if {} {}",
-                                snippet(cx, ex.span, "b"),
-                                expr_block(cx, true_expr, None, "..", Some(expr.span))
-                            )),
-                            (true, false) => {
-                                let test = Sugg::hir(cx, ex, "..");
-                                Some(format!(
-                                    "if {} {}",
-                                    !test,
-                                    expr_block(cx, false_expr, None, "..", Some(expr.span))
-                                ))
-                            },
-                            (true, true) => None,
-                        };
-
-                        if let Some(sugg) = sugg {
-                            diag.span_suggestion(
-                                expr.span,
-                                "consider using an `if`/`else` expression",
-                                sugg,
-                                Applicability::HasPlaceholders,
-                            );
-                        }
-                    }
-                }
-            },
-        );
-    }
-}
-
-fn check_overlapping_arms<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
-    if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
-        let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
-        if !ranges.is_empty() {
-            if let Some((start, end)) = overlapping(&ranges) {
-                span_lint_and_note(
-                    cx,
-                    MATCH_OVERLAPPING_ARM,
-                    start.span,
-                    "some ranges overlap",
-                    Some(end.span),
-                    "overlaps with this",
-                );
-            }
-        }
-    }
-}
-
-fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
-    let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
-    if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
-        for arm in arms {
-            if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
-                let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
-                if path_str == "Err" {
-                    let mut matching_wild = inner.iter().any(is_wild);
-                    let mut ident_bind_name = kw::Underscore;
-                    if !matching_wild {
-                        // Looking for unused bindings (i.e.: `_e`)
-                        for pat in inner.iter() {
-                            if let PatKind::Binding(_, id, ident, None) = pat.kind {
-                                if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) {
-                                    ident_bind_name = ident.name;
-                                    matching_wild = true;
-                                }
-                            }
-                        }
-                    }
-                    if_chain! {
-                        if matching_wild;
-                        if let Some(macro_call) = root_macro_call(peel_blocks_with_stmt(arm.body).span);
-                        if is_panic(cx, macro_call.def_id);
-                        then {
-                            // `Err(_)` or `Err(_e)` arm with `panic!` found
-                            span_lint_and_note(cx,
-                                MATCH_WILD_ERR_ARM,
-                                arm.pat.span,
-                                &format!("`Err({})` matches all errors", ident_bind_name),
-                                None,
-                                "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
-                            );
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
-
-enum CommonPrefixSearcher<'a> {
-    None,
-    Path(&'a [PathSegment<'a>]),
-    Mixed,
-}
-impl<'a> CommonPrefixSearcher<'a> {
-    fn with_path(&mut self, path: &'a [PathSegment<'a>]) {
-        match path {
-            [path @ .., _] => self.with_prefix(path),
-            [] => (),
-        }
-    }
-
-    fn with_prefix(&mut self, path: &'a [PathSegment<'a>]) {
-        match self {
-            Self::None => *self = Self::Path(path),
-            Self::Path(self_path)
-                if path
-                    .iter()
-                    .map(|p| p.ident.name)
-                    .eq(self_path.iter().map(|p| p.ident.name)) => {},
-            Self::Path(_) => *self = Self::Mixed,
-            Self::Mixed => (),
-        }
-    }
-}
-
-fn is_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool {
-    let attrs = cx.tcx.get_attrs(variant_def.def_id);
-    clippy_utils::attrs::is_doc_hidden(attrs) || clippy_utils::attrs::is_unstable(attrs)
-}
-
-#[allow(clippy::too_many_lines)]
-fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
-    let ty = cx.typeck_results().expr_ty(ex).peel_refs();
-    let adt_def = match ty.kind() {
-        ty::Adt(adt_def, _)
-            if adt_def.is_enum()
-                && !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) =>
-        {
-            adt_def
-        },
-        _ => return,
-    };
-
-    // First pass - check for violation, but don't do much book-keeping because this is hopefully
-    // the uncommon case, and the book-keeping is slightly expensive.
-    let mut wildcard_span = None;
-    let mut wildcard_ident = None;
-    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::Binding(_, _, ident, None) => {
-                wildcard_span = Some(arm.pat.span);
-                wildcard_ident = Some(ident);
-            },
-            _ => has_non_wild = true,
-        }
-    }
-    let wildcard_span = match wildcard_span {
-        Some(x) if has_non_wild => x,
-        _ => return,
-    };
-
-    // Accumulate the variants which should be put in place of the wildcard because they're not
-    // already covered.
-    let has_hidden = adt_def.variants.iter().any(|x| is_hidden(cx, x));
-    let mut missing_variants: Vec<_> = adt_def.variants.iter().filter(|x| !is_hidden(cx, x)).collect();
-
-    let mut path_prefix = CommonPrefixSearcher::None;
-    for arm in arms {
-        // Guards mean that this case probably isn't exhaustively covered. Technically
-        // this is incorrect, as we should really check whether each variant is exhaustively
-        // covered by the set of guards that cover it, but that's really hard to do.
-        recurse_or_patterns(arm.pat, |pat| {
-            let path = match &peel_hir_pat_refs(pat).0.kind {
-                PatKind::Path(path) => {
-                    #[allow(clippy::match_same_arms)]
-                    let id = match cx.qpath_res(path, pat.hir_id) {
-                        Res::Def(
-                            DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
-                            _,
-                        ) => return,
-                        Res::Def(_, id) => id,
-                        _ => return,
-                    };
-                    if arm.guard.is_none() {
-                        missing_variants.retain(|e| e.ctor_def_id != Some(id));
-                    }
-                    path
-                },
-                PatKind::TupleStruct(path, patterns, ..) => {
-                    if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
-                        if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) {
-                            missing_variants.retain(|e| e.ctor_def_id != Some(id));
-                        }
-                    }
-                    path
-                },
-                PatKind::Struct(path, patterns, ..) => {
-                    if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
-                        if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p.pat)) {
-                            missing_variants.retain(|e| e.def_id != id);
-                        }
-                    }
-                    path
-                },
-                _ => return,
-            };
-            match path {
-                QPath::Resolved(_, path) => path_prefix.with_path(path.segments),
-                QPath::TypeRelative(
-                    hir::Ty {
-                        kind: TyKind::Path(QPath::Resolved(_, path)),
-                        ..
-                    },
-                    _,
-                ) => path_prefix.with_prefix(path.segments),
-                _ => (),
-            }
-        });
-    }
-
-    let format_suggestion = |variant: &VariantDef| {
-        format!(
-            "{}{}{}{}",
-            if let Some(ident) = wildcard_ident {
-                format!("{} @ ", ident.name)
-            } else {
-                String::new()
-            },
-            if let CommonPrefixSearcher::Path(path_prefix) = path_prefix {
-                let mut s = String::new();
-                for seg in path_prefix {
-                    s.push_str(seg.ident.as_str());
-                    s.push_str("::");
-                }
-                s
-            } else {
-                let mut s = cx.tcx.def_path_str(adt_def.did);
-                s.push_str("::");
-                s
-            },
-            variant.name,
-            match variant.ctor_kind {
-                CtorKind::Fn if variant.fields.len() == 1 => "(_)",
-                CtorKind::Fn => "(..)",
-                CtorKind::Const => "",
-                CtorKind::Fictive => "{ .. }",
-            }
-        )
-    };
-
-    match missing_variants.as_slice() {
-        [] => (),
-        [x] if !adt_def.is_variant_list_non_exhaustive() && !has_hidden => span_lint_and_sugg(
-            cx,
-            MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
-            wildcard_span,
-            "wildcard matches only a single variant and will also match any future added variants",
-            "try this",
-            format_suggestion(x),
-            Applicability::MaybeIncorrect,
-        ),
-        variants => {
-            let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect();
-            let message = if adt_def.is_variant_list_non_exhaustive() || has_hidden {
-                suggestions.push("_".into());
-                "wildcard matches known variants and will also match future added variants"
-            } else {
-                "wildcard match will also match any future added variants"
-            };
-
-            span_lint_and_sugg(
-                cx,
-                WILDCARD_ENUM_MATCH_ARM,
-                wildcard_span,
-                message,
-                "try this",
-                suggestions.join(" | "),
-                Applicability::MaybeIncorrect,
-            );
-        },
-    };
-}
-
-fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
-where
-    'b: 'a,
-    I: Clone + Iterator<Item = &'a Pat<'b>>,
-{
-    if !has_multiple_ref_pats(pats.clone()) {
-        return;
-    }
-
-    let (first_sugg, msg, title);
-    let span = ex.span.source_callsite();
-    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
-        first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
-        msg = "try";
-        title = "you don't need to add `&` to both the expression and the patterns";
-    } else {
-        first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
-        msg = "instead of prefixing all patterns with `&`, you can dereference the expression";
-        title = "you don't need to add `&` to all patterns";
-    }
-
-    let remaining_suggs = pats.filter_map(|pat| {
-        if let PatKind::Ref(refp, _) = pat.kind {
-            Some((pat.span, snippet(cx, refp.span, "..").to_string()))
-        } else {
-            None
-        }
-    });
-
-    span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
-        if !expr.span.from_expansion() {
-            multispan_sugg(diag, msg, first_sugg.chain(remaining_suggs));
-        }
-    });
-}
-
-fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
-    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
-        let arm_ref: Option<BindingAnnotation> = if is_none_arm(cx, &arms[0]) {
-            is_ref_some_arm(cx, &arms[1])
-        } else if is_none_arm(cx, &arms[1]) {
-            is_ref_some_arm(cx, &arms[0])
-        } else {
-            None
-        };
-        if let Some(rb) = arm_ref {
-            let suggestion = if rb == BindingAnnotation::Ref {
-                "as_ref"
-            } else {
-                "as_mut"
-            };
-
-            let output_ty = cx.typeck_results().expr_ty(expr);
-            let input_ty = cx.typeck_results().expr_ty(ex);
-
-            let cast = if_chain! {
-                if let ty::Adt(_, substs) = input_ty.kind();
-                let input_ty = substs.type_at(0);
-                if let ty::Adt(_, substs) = output_ty.kind();
-                let output_ty = substs.type_at(0);
-                if let ty::Ref(_, output_ty, _) = *output_ty.kind();
-                if input_ty != output_ty;
-                then {
-                    ".map(|x| x as _)"
-                } else {
-                    ""
-                }
-            };
-
-            let mut applicability = Applicability::MachineApplicable;
-            span_lint_and_sugg(
-                cx,
-                MATCH_AS_REF,
-                expr.span,
-                &format!("use `{}()` instead", suggestion),
-                "try this",
-                format!(
-                    "{}.{}(){}",
-                    snippet_with_applicability(cx, ex.span, "_", &mut applicability),
-                    suggestion,
-                    cast,
-                ),
-                applicability,
-            );
-        }
-    }
-}
-
-fn check_wild_in_or_pats(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
-    for arm in arms {
-        if let PatKind::Or(fields) = arm.pat.kind {
-            // look for multiple fields in this arm that contains at least one Wild pattern
-            if fields.len() > 1 && fields.iter().any(is_wild) {
-                span_lint_and_help(
-                    cx,
-                    WILDCARD_IN_OR_PATTERNS,
-                    arm.pat.span,
-                    "wildcard pattern covers any other pattern as it will match anyway",
-                    None,
-                    "consider handling `_` separately",
-                );
-            }
-        }
-    }
-}
-
-/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
-fn check_match_like_matches<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
-    if let Some(higher::IfLet {
-        let_pat,
-        let_expr,
-        if_then,
-        if_else: Some(if_else),
-    }) = higher::IfLet::hir(cx, expr)
-    {
-        return find_matches_sugg(
-            cx,
-            let_expr,
-            IntoIterator::into_iter([(&[][..], Some(let_pat), if_then, None), (&[][..], None, if_else, None)]),
-            expr,
-            true,
-        );
-    }
-
-    if let ExprKind::Match(scrut, arms, MatchSource::Normal) = expr.kind {
-        return find_matches_sugg(
-            cx,
-            scrut,
-            arms.iter().map(|arm| {
-                (
-                    cx.tcx.hir().attrs(arm.hir_id),
-                    Some(arm.pat),
-                    arm.body,
-                    arm.guard.as_ref(),
-                )
-            }),
-            expr,
-            false,
-        );
-    }
-
-    false
-}
-
-/// Lint a `match` or `if let` for replacement by `matches!`
-fn find_matches_sugg<'a, 'b, I>(
-    cx: &LateContext<'_>,
-    ex: &Expr<'_>,
-    mut iter: I,
-    expr: &Expr<'_>,
-    is_if_let: bool,
-) -> bool
-where
-    'b: 'a,
-    I: Clone
-        + DoubleEndedIterator
-        + ExactSizeIterator
-        + Iterator<
-            Item = (
-                &'a [Attribute],
-                Option<&'a Pat<'b>>,
-                &'a Expr<'b>,
-                Option<&'a Guard<'b>>,
-            ),
-        >,
-{
-    if_chain! {
-        if iter.len() >= 2;
-        if cx.typeck_results().expr_ty(expr).is_bool();
-        if let Some((_, last_pat_opt, last_expr, _)) = iter.next_back();
-        let iter_without_last = iter.clone();
-        if let Some((first_attrs, _, first_expr, first_guard)) = iter.next();
-        if let Some(b0) = find_bool_lit(&first_expr.kind, is_if_let);
-        if let Some(b1) = find_bool_lit(&last_expr.kind, is_if_let);
-        if b0 != b1;
-        if first_guard.is_none() || iter.len() == 0;
-        if first_attrs.is_empty();
-        if iter
-            .all(|arm| {
-                find_bool_lit(&arm.2.kind, is_if_let).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty()
-            });
-        then {
-            if let Some(last_pat) = last_pat_opt {
-                if !is_wild(last_pat) {
-                    return false;
-                }
-            }
-
-            // The suggestion may be incorrect, because some arms can have `cfg` attributes
-            // evaluated into `false` and so such arms will be stripped before.
-            let mut applicability = Applicability::MaybeIncorrect;
-            let pat = {
-                use itertools::Itertools as _;
-                iter_without_last
-                    .filter_map(|arm| {
-                        let pat_span = arm.1?.span;
-                        Some(snippet_with_applicability(cx, pat_span, "..", &mut applicability))
-                    })
-                    .join(" | ")
-            };
-            let pat_and_guard = if let Some(Guard::If(g)) = first_guard {
-                format!("{} if {}", pat, snippet_with_applicability(cx, g.span, "..", &mut applicability))
-            } else {
-                pat
-            };
-
-            // strip potential borrows (#6503), but only if the type is a reference
-            let mut ex_new = ex;
-            if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
-                if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() {
-                    ex_new = ex_inner;
-                }
-            };
-            span_lint_and_sugg(
-                cx,
-                MATCH_LIKE_MATCHES_MACRO,
-                expr.span,
-                &format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }),
-                "try this",
-                format!(
-                    "{}matches!({}, {})",
-                    if b0 { "" } else { "!" },
-                    snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
-                    pat_and_guard,
-                ),
-                applicability,
-            );
-            true
-        } else {
-            false
-        }
-    }
-}
-
-/// Extract a `bool` or `{ bool }`
-fn find_bool_lit(ex: &ExprKind<'_>, is_if_let: bool) -> Option<bool> {
-    match ex {
-        ExprKind::Lit(Spanned {
-            node: LitKind::Bool(b), ..
-        }) => Some(*b),
-        ExprKind::Block(
-            rustc_hir::Block {
-                stmts: &[],
-                expr: Some(exp),
-                ..
-            },
-            _,
-        ) if is_if_let => {
-            if let ExprKind::Lit(Spanned {
-                node: LitKind::Bool(b), ..
-            }) = exp.kind
-            {
-                Some(b)
-            } else {
-                None
-            }
-        },
-        _ => None,
-    }
-}
-
-#[allow(clippy::too_many_lines)]
-fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
-    if expr.span.from_expansion() || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
-        return;
-    }
-
-    // HACK:
-    // This is a hack to deal with arms that are excluded by macros like `#[cfg]`. It is only used here
-    // to prevent false positives as there is currently no better way to detect if code was excluded by
-    // a macro. See PR #6435
-    if_chain! {
-        if let Some(match_snippet) = snippet_opt(cx, expr.span);
-        if let Some(arm_snippet) = snippet_opt(cx, arms[0].span);
-        if let Some(ex_snippet) = snippet_opt(cx, ex.span);
-        let rest_snippet = match_snippet.replace(&arm_snippet, "").replace(&ex_snippet, "");
-        if rest_snippet.contains("=>");
-        then {
-            // The code it self contains another thick arrow "=>"
-            // -> Either another arm or a comment
-            return;
-        }
-    }
-
-    let matched_vars = ex.span;
-    let bind_names = arms[0].pat.span;
-    let match_body = peel_blocks(arms[0].body);
-    let mut snippet_body = if match_body.span.from_expansion() {
-        Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
-    } else {
-        snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string()
-    };
-
-    // 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(';');
-            }
-        },
-    }
-
-    let mut applicability = Applicability::MaybeIncorrect;
-    match arms[0].pat.kind {
-        PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
-            // If this match is in a local (`let`) stmt
-            let (target_span, sugg) = if let Some(parent_let_node) = opt_parent_let(cx, ex) {
-                (
-                    parent_let_node.span,
-                    format!(
-                        "let {} = {};\n{}let {} = {};",
-                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
-                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
-                        " ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
-                        snippet_with_applicability(cx, parent_let_node.pat.span, "..", &mut applicability),
-                        snippet_body
-                    ),
-                )
-            } else {
-                // If we are in closure, we need curly braces around suggestion
-                let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
-                let (mut cbrace_start, mut cbrace_end) = ("".to_string(), "".to_string());
-                if let Some(parent_expr) = get_parent_expr(cx, expr) {
-                    if let ExprKind::Closure(..) = parent_expr.kind {
-                        cbrace_end = format!("\n{}}}", indent);
-                        // Fix body indent due to the closure
-                        indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
-                        cbrace_start = format!("{{\n{}", indent);
-                    }
-                }
-                // 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(expr.hir_id);
-                if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
-                    if let ExprKind::Match(..) = arm.body.kind {
-                        cbrace_end = format!("\n{}}}", indent);
-                        // Fix body indent due to the match
-                        indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
-                        cbrace_start = format!("{{\n{}", indent);
-                    }
-                }
-                (
-                    expr.span,
-                    format!(
-                        "{}let {} = {};\n{}{}{}",
-                        cbrace_start,
-                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
-                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
-                        indent,
-                        snippet_body,
-                        cbrace_end
-                    ),
-                )
-            };
-            span_lint_and_sugg(
-                cx,
-                MATCH_SINGLE_BINDING,
-                target_span,
-                "this match could be written as a `let` statement",
-                "consider using `let` statement",
-                sugg,
-                applicability,
-            );
-        },
-        PatKind::Wild => {
-            if ex.can_have_side_effects() {
-                let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0));
-                let sugg = format!(
-                    "{};\n{}{}",
-                    snippet_with_applicability(cx, ex.span, "..", &mut applicability),
-                    indent,
-                    snippet_body
-                );
-                span_lint_and_sugg(
-                    cx,
-                    MATCH_SINGLE_BINDING,
-                    expr.span,
-                    "this match could be replaced by its scrutinee and body",
-                    "consider using the scrutinee and body instead",
-                    sugg,
-                    applicability,
-                );
-            } else {
-                span_lint_and_sugg(
-                    cx,
-                    MATCH_SINGLE_BINDING,
-                    expr.span,
-                    "this match could be replaced by its body itself",
-                    "consider using the match body instead",
-                    snippet_body,
-                    Applicability::MachineApplicable,
-                );
-            }
-        },
-        _ => (),
-    }
-}
-
-/// Returns true if the `ex` match expression is in a local (`let`) statement
-fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> {
-    let map = &cx.tcx.hir();
-    if_chain! {
-        if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id));
-        if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id));
-        then {
-            return Some(parent_let_expr);
-        }
-    }
-    None
-}
-
-/// Gets the ranges for each range pattern arm. Applies `ty` bounds for open ranges.
-fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<FullInt>> {
-    arms.iter()
-        .filter_map(|arm| {
-            if let Arm { pat, guard: None, .. } = *arm {
-                if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
-                    let lhs_const = match lhs {
-                        Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
-                        None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
-                    };
-                    let rhs_const = match rhs {
-                        Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
-                        None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
-                    };
-
-                    let lhs_val = lhs_const.int_value(cx, ty)?;
-                    let rhs_val = rhs_const.int_value(cx, ty)?;
-
-                    let rhs_bound = match range_end {
-                        RangeEnd::Included => EndBound::Included(rhs_val),
-                        RangeEnd::Excluded => EndBound::Excluded(rhs_val),
-                    };
-                    return Some(SpannedRange {
-                        span: pat.span,
-                        node: (lhs_val, rhs_bound),
-                    });
-                }
-
-                if let PatKind::Lit(value) = pat.kind {
-                    let value = constant_full_int(cx, cx.typeck_results(), value)?;
-                    return Some(SpannedRange {
-                        span: pat.span,
-                        node: (value, EndBound::Included(value)),
-                    });
-                }
-            }
-            None
-        })
-        .collect()
-}
-
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub enum EndBound<T> {
-    Included(T),
-    Excluded(T),
-}
-
-#[derive(Debug, Eq, PartialEq)]
-struct SpannedRange<T> {
-    pub span: Span,
-    pub node: (T, EndBound<T>),
-}
-
-// Checks if arm has the form `None => None`
-fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
-    matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
-}
-
-// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
-fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotation> {
-    if_chain! {
-        if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
-        if is_lang_ctor(cx, qpath, OptionSome);
-        if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
-        if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
-        if let ExprKind::Call(e, args) = peel_blocks(arm.body).kind;
-        if let ExprKind::Path(ref some_path) = e.kind;
-        if is_lang_ctor(cx, some_path, OptionSome) && args.len() == 1;
-        if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
-        if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
-        then {
-            return Some(rb)
-        }
-    }
-    None
-}
-
-fn has_multiple_ref_pats<'a, 'b, I>(pats: I) -> bool
-where
-    'b: 'a,
-    I: Iterator<Item = &'a Pat<'b>>,
-{
-    let mut ref_count = 0;
-    for opt in pats.map(|pat| match pat.kind {
-        PatKind::Ref(..) => Some(true), // &-patterns
-        PatKind::Wild => Some(false),   // an "anything" wildcard is also fine
-        _ => None,                      // any other pattern is not fine
-    }) {
-        if let Some(inner) = opt {
-            if inner {
-                ref_count += 1;
-            }
-        } else {
-            return false;
-        }
-    }
-    ref_count > 1
-}
-
-fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
-where
-    T: Copy + Ord,
-{
-    #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
-    enum BoundKind {
-        EndExcluded,
-        Start,
-        EndIncluded,
-    }
-
-    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
-    struct RangeBound<'a, T>(T, BoundKind, &'a SpannedRange<T>);
-
-    impl<'a, T: Copy + Ord> PartialOrd for RangeBound<'a, T> {
-        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
-            Some(self.cmp(other))
-        }
-    }
-
-    impl<'a, T: Copy + Ord> Ord for RangeBound<'a, T> {
-        fn cmp(&self, RangeBound(other_value, other_kind, _): &Self) -> Ordering {
-            let RangeBound(self_value, self_kind, _) = *self;
-            (self_value, self_kind).cmp(&(*other_value, *other_kind))
-        }
-    }
-
-    let mut values = Vec::with_capacity(2 * ranges.len());
-
-    for r @ SpannedRange { node: (start, end), .. } in ranges {
-        values.push(RangeBound(*start, BoundKind::Start, r));
-        values.push(match end {
-            EndBound::Excluded(val) => RangeBound(*val, BoundKind::EndExcluded, r),
-            EndBound::Included(val) => RangeBound(*val, BoundKind::EndIncluded, r),
-        });
-    }
-
-    values.sort();
-
-    let mut started = vec![];
-
-    for RangeBound(_, kind, range) in values {
-        match kind {
-            BoundKind::Start => started.push(range),
-            BoundKind::EndExcluded | BoundKind::EndIncluded => {
-                let mut overlap = None;
-
-                while let Some(last_started) = started.pop() {
-                    if last_started == range {
-                        break;
-                    }
-                    overlap = Some(last_started);
-                }
-
-                if let Some(first_overlapping) = overlap {
-                    return Some((range, first_overlapping));
-                }
-            },
-        }
-    }
-
-    None
-}
-
-mod redundant_pattern_match {
-    use super::REDUNDANT_PATTERN_MATCHING;
-    use clippy_utils::diagnostics::span_lint_and_then;
-    use clippy_utils::higher;
-    use clippy_utils::source::snippet;
-    use clippy_utils::sugg::Sugg;
-    use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
-    use clippy_utils::{is_lang_ctor, is_qpath_def_path, is_trait_method, paths};
-    use if_chain::if_chain;
-    use rustc_ast::ast::LitKind;
-    use rustc_data_structures::fx::FxHashSet;
-    use rustc_errors::Applicability;
-    use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
-    use rustc_hir::{
-        intravisit::{walk_expr, Visitor},
-        Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath, UnOp,
-    };
-    use rustc_lint::LateContext;
-    use rustc_middle::ty::{self, subst::GenericArgKind, Ty};
-    use rustc_span::sym;
-
-    pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let Some(higher::IfLet {
-            if_else,
-            let_pat,
-            let_expr,
-            ..
-        }) = higher::IfLet::hir(cx, expr)
-        {
-            find_sugg_for_if_let(cx, expr, let_pat, let_expr, "if", if_else.is_some());
-        }
-        if let ExprKind::Match(op, arms, MatchSource::Normal) = &expr.kind {
-            find_sugg_for_match(cx, expr, op, arms);
-        }
-        if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
-            find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
-        }
-    }
-
-    /// Checks if the drop order for a type matters. Some std types implement drop solely to
-    /// deallocate memory. For these types, and composites containing them, changing the drop order
-    /// won't result in any observable side effects.
-    fn type_needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
-        type_needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
-    }
-
-    fn type_needs_ordered_drop_inner<'tcx>(
-        cx: &LateContext<'tcx>,
-        ty: Ty<'tcx>,
-        seen: &mut FxHashSet<Ty<'tcx>>,
-    ) -> bool {
-        if !seen.insert(ty) {
-            return false;
-        }
-        if !ty.needs_drop(cx.tcx, cx.param_env) {
-            false
-        } else if !cx
-            .tcx
-            .lang_items()
-            .drop_trait()
-            .map_or(false, |id| implements_trait(cx, ty, id, &[]))
-        {
-            // This type doesn't implement drop, so no side effects here.
-            // Check if any component type has any.
-            match ty.kind() {
-                ty::Tuple(_) => ty.tuple_fields().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
-                ty::Array(ty, _) => type_needs_ordered_drop_inner(cx, ty, seen),
-                ty::Adt(adt, subs) => adt
-                    .all_fields()
-                    .map(|f| f.ty(cx.tcx, subs))
-                    .any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
-                _ => true,
-            }
-        }
-        // Check for std types which implement drop, but only for memory allocation.
-        else if is_type_diagnostic_item(cx, ty, sym::Vec)
-            || is_type_lang_item(cx, ty, LangItem::OwnedBox)
-            || is_type_diagnostic_item(cx, ty, sym::Rc)
-            || is_type_diagnostic_item(cx, ty, sym::Arc)
-            || is_type_diagnostic_item(cx, ty, sym::cstring_type)
-            || is_type_diagnostic_item(cx, ty, sym::BTreeMap)
-            || is_type_diagnostic_item(cx, ty, sym::LinkedList)
-            || match_type(cx, ty, &paths::WEAK_RC)
-            || match_type(cx, ty, &paths::WEAK_ARC)
-        {
-            // Check all of the generic arguments.
-            if let ty::Adt(_, subs) = ty.kind() {
-                subs.types().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen))
-            } else {
-                true
-            }
-        } else {
-            true
-        }
-    }
-
-    // Extract the generic arguments out of a type
-    fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
-        if_chain! {
-            if let ty::Adt(_, subs) = ty.kind();
-            if let Some(sub) = subs.get(index);
-            if let GenericArgKind::Type(sub_ty) = sub.unpack();
-            then {
-                Some(sub_ty)
-            } else {
-                None
-            }
-        }
-    }
-
-    // Checks if there are any temporaries created in the given expression for which drop order
-    // matters.
-    fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
-        struct V<'a, 'tcx> {
-            cx: &'a LateContext<'tcx>,
-            res: bool,
-        }
-        impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
-            fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
-                match expr.kind {
-                    // Taking the reference of a value leaves a temporary
-                    // e.g. In `&String::new()` the string is a temporary value.
-                    // Remaining fields are temporary values
-                    // e.g. In `(String::new(), 0).1` the string is a temporary value.
-                    ExprKind::AddrOf(_, _, expr) | ExprKind::Field(expr, _) => {
-                        if !matches!(expr.kind, ExprKind::Path(_)) {
-                            if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(expr)) {
-                                self.res = true;
-                            } else {
-                                self.visit_expr(expr);
-                            }
-                        }
-                    },
-                    // the base type is alway taken by reference.
-                    // e.g. In `(vec![0])[0]` the vector is a temporary value.
-                    ExprKind::Index(base, index) => {
-                        if !matches!(base.kind, ExprKind::Path(_)) {
-                            if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(base)) {
-                                self.res = true;
-                            } else {
-                                self.visit_expr(base);
-                            }
-                        }
-                        self.visit_expr(index);
-                    },
-                    // Method calls can take self by reference.
-                    // e.g. In `String::new().len()` the string is a temporary value.
-                    ExprKind::MethodCall(_, [self_arg, args @ ..], _) => {
-                        if !matches!(self_arg.kind, ExprKind::Path(_)) {
-                            let self_by_ref = self
-                                .cx
-                                .typeck_results()
-                                .type_dependent_def_id(expr.hir_id)
-                                .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref());
-                            if self_by_ref
-                                && type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(self_arg))
-                            {
-                                self.res = true;
-                            } else {
-                                self.visit_expr(self_arg);
-                            }
-                        }
-                        args.iter().for_each(|arg| self.visit_expr(arg));
-                    },
-                    // Either explicitly drops values, or changes control flow.
-                    ExprKind::DropTemps(_)
-                    | ExprKind::Ret(_)
-                    | ExprKind::Break(..)
-                    | ExprKind::Yield(..)
-                    | ExprKind::Block(Block { expr: None, .. }, _)
-                    | ExprKind::Loop(..) => (),
-
-                    // Only consider the final expression.
-                    ExprKind::Block(Block { expr: Some(expr), .. }, _) => self.visit_expr(expr),
-
-                    _ => walk_expr(self, expr),
-                }
-            }
-        }
-
-        let mut v = V { cx, res: false };
-        v.visit_expr(expr);
-        v.res
-    }
-
-    fn find_sugg_for_if_let<'tcx>(
-        cx: &LateContext<'tcx>,
-        expr: &'tcx Expr<'_>,
-        let_pat: &Pat<'_>,
-        let_expr: &'tcx Expr<'_>,
-        keyword: &'static str,
-        has_else: bool,
-    ) {
-        // also look inside refs
-        let mut kind = &let_pat.kind;
-        // if we have &None for example, peel it so we can detect "if let None = x"
-        if let PatKind::Ref(inner, _mutability) = kind {
-            kind = &inner.kind;
-        }
-        let op_ty = cx.typeck_results().expr_ty(let_expr);
-        // Determine which function should be used, and the type contained by the corresponding
-        // variant.
-        let (good_method, inner_ty) = match kind {
-            PatKind::TupleStruct(ref path, [sub_pat], _) => {
-                if let PatKind::Wild = sub_pat.kind {
-                    if is_lang_ctor(cx, path, ResultOk) {
-                        ("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
-                    } else if is_lang_ctor(cx, path, ResultErr) {
-                        ("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty))
-                    } else if is_lang_ctor(cx, path, OptionSome) {
-                        ("is_some()", op_ty)
-                    } else if is_lang_ctor(cx, path, PollReady) {
-                        ("is_ready()", op_ty)
-                    } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V4) {
-                        ("is_ipv4()", op_ty)
-                    } else if is_qpath_def_path(cx, path, sub_pat.hir_id, &paths::IPADDR_V6) {
-                        ("is_ipv6()", op_ty)
-                    } else {
-                        return;
-                    }
-                } else {
-                    return;
-                }
-            },
-            PatKind::Path(ref path) => {
-                let method = if is_lang_ctor(cx, path, OptionNone) {
-                    "is_none()"
-                } else if is_lang_ctor(cx, path, PollPending) {
-                    "is_pending()"
-                } else {
-                    return;
-                };
-                // `None` and `Pending` don't have an inner type.
-                (method, cx.tcx.types.unit)
-            },
-            _ => return,
-        };
-
-        // If this is the last expression in a block or there is an else clause then the whole
-        // type needs to be considered, not just the inner type of the branch being matched on.
-        // Note the last expression in a block is dropped after all local bindings.
-        let check_ty = if has_else
-            || (keyword == "if" && matches!(cx.tcx.hir().parent_iter(expr.hir_id).next(), Some((_, Node::Block(..)))))
-        {
-            op_ty
-        } else {
-            inner_ty
-        };
-
-        // All temporaries created in the scrutinee expression are dropped at the same time as the
-        // scrutinee would be, so they have to be considered as well.
-        // e.g. in `if let Some(x) = foo.lock().unwrap().baz.as_ref() { .. }` the lock will be held
-        // for the duration if body.
-        let needs_drop = type_needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, let_expr);
-
-        // check that `while_let_on_iterator` lint does not trigger
-        if_chain! {
-            if keyword == "while";
-            if let ExprKind::MethodCall(method_path, _, _) = let_expr.kind;
-            if method_path.ident.name == sym::next;
-            if is_trait_method(cx, let_expr, sym::Iterator);
-            then {
-                return;
-            }
-        }
-
-        let result_expr = match &let_expr.kind {
-            ExprKind::AddrOf(_, _, borrowed) => borrowed,
-            ExprKind::Unary(UnOp::Deref, deref) => deref,
-            _ => let_expr,
-        };
-
-        span_lint_and_then(
-            cx,
-            REDUNDANT_PATTERN_MATCHING,
-            let_pat.span,
-            &format!("redundant pattern matching, consider using `{}`", good_method),
-            |diag| {
-                // if/while let ... = ... { ... }
-                // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-                let expr_span = expr.span;
-
-                // if/while let ... = ... { ... }
-                //                 ^^^
-                let op_span = result_expr.span.source_callsite();
-
-                // if/while let ... = ... { ... }
-                // ^^^^^^^^^^^^^^^^^^^
-                let span = expr_span.until(op_span.shrink_to_hi());
-
-                let app = if needs_drop {
-                    Applicability::MaybeIncorrect
-                } else {
-                    Applicability::MachineApplicable
-                };
-
-                let sugg = Sugg::hir_with_macro_callsite(cx, result_expr, "_")
-                    .maybe_par()
-                    .to_string();
-
-                diag.span_suggestion(span, "try this", format!("{} {}.{}", keyword, sugg, good_method), app);
-
-                if needs_drop {
-                    diag.note("this will change drop order of the result, as well as all temporaries");
-                    diag.note("add `#[allow(clippy::redundant_pattern_matching)]` if this is important");
-                }
-            },
-        );
-    }
-
-    fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
-        if arms.len() == 2 {
-            let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
-
-            let found_good_method = match node_pair {
-                (
-                    PatKind::TupleStruct(ref path_left, patterns_left, _),
-                    PatKind::TupleStruct(ref path_right, patterns_right, _),
-                ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
-                    if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
-                        find_good_method_for_match(
-                            cx,
-                            arms,
-                            path_left,
-                            path_right,
-                            &paths::RESULT_OK,
-                            &paths::RESULT_ERR,
-                            "is_ok()",
-                            "is_err()",
-                        )
-                        .or_else(|| {
-                            find_good_method_for_match(
-                                cx,
-                                arms,
-                                path_left,
-                                path_right,
-                                &paths::IPADDR_V4,
-                                &paths::IPADDR_V6,
-                                "is_ipv4()",
-                                "is_ipv6()",
-                            )
-                        })
-                    } else {
-                        None
-                    }
-                },
-                (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right))
-                | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _))
-                    if patterns.len() == 1 =>
-                {
-                    if let PatKind::Wild = patterns[0].kind {
-                        find_good_method_for_match(
-                            cx,
-                            arms,
-                            path_left,
-                            path_right,
-                            &paths::OPTION_SOME,
-                            &paths::OPTION_NONE,
-                            "is_some()",
-                            "is_none()",
-                        )
-                        .or_else(|| {
-                            find_good_method_for_match(
-                                cx,
-                                arms,
-                                path_left,
-                                path_right,
-                                &paths::POLL_READY,
-                                &paths::POLL_PENDING,
-                                "is_ready()",
-                                "is_pending()",
-                            )
-                        })
-                    } else {
-                        None
-                    }
-                },
-                _ => None,
-            };
-
-            if let Some(good_method) = found_good_method {
-                let span = expr.span.to(op.span);
-                let result_expr = match &op.kind {
-                    ExprKind::AddrOf(_, _, borrowed) => borrowed,
-                    _ => op,
-                };
-                span_lint_and_then(
-                    cx,
-                    REDUNDANT_PATTERN_MATCHING,
-                    expr.span,
-                    &format!("redundant pattern matching, consider using `{}`", good_method),
-                    |diag| {
-                        diag.span_suggestion(
-                            span,
-                            "try this",
-                            format!("{}.{}", snippet(cx, result_expr.span, "_"), good_method),
-                            Applicability::MaybeIncorrect, // snippet
-                        );
-                    },
-                );
-            }
-        }
-    }
-
-    #[allow(clippy::too_many_arguments)]
-    fn find_good_method_for_match<'a>(
-        cx: &LateContext<'_>,
-        arms: &[Arm<'_>],
-        path_left: &QPath<'_>,
-        path_right: &QPath<'_>,
-        expected_left: &[&str],
-        expected_right: &[&str],
-        should_be_left: &'a str,
-        should_be_right: &'a str,
-    ) -> Option<&'a str> {
-        let body_node_pair = if is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_left)
-            && is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_right)
-        {
-            (&(*arms[0].body).kind, &(*arms[1].body).kind)
-        } else if is_qpath_def_path(cx, path_right, arms[1].pat.hir_id, expected_left)
-            && is_qpath_def_path(cx, path_left, arms[0].pat.hir_id, expected_right)
-        {
-            (&(*arms[1].body).kind, &(*arms[0].body).kind)
-        } else {
-            return None;
-        };
-
-        match body_node_pair {
-            (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
-                (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
-                (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
-                _ => None,
-            },
-            _ => None,
-        }
-    }
-}
-
-#[test]
-fn test_overlapping() {
-    use rustc_span::source_map::DUMMY_SP;
-
-    let sp = |s, e| SpannedRange {
-        span: DUMMY_SP,
-        node: (s, e),
-    };
-
-    assert_eq!(None, overlapping::<u8>(&[]));
-    assert_eq!(None, overlapping(&[sp(1, EndBound::Included(4))]));
-    assert_eq!(
-        None,
-        overlapping(&[sp(1, EndBound::Included(4)), sp(5, EndBound::Included(6))])
-    );
-    assert_eq!(
-        None,
-        overlapping(&[
-            sp(1, EndBound::Included(4)),
-            sp(5, EndBound::Included(6)),
-            sp(10, EndBound::Included(11))
-        ],)
-    );
-    assert_eq!(
-        Some((&sp(1, EndBound::Included(4)), &sp(3, EndBound::Included(6)))),
-        overlapping(&[sp(1, EndBound::Included(4)), sp(3, EndBound::Included(6))])
-    );
-    assert_eq!(
-        Some((&sp(5, EndBound::Included(6)), &sp(6, EndBound::Included(11)))),
-        overlapping(&[
-            sp(1, EndBound::Included(4)),
-            sp(5, EndBound::Included(6)),
-            sp(6, EndBound::Included(11))
-        ],)
-    );
-}
-
-/// Implementation of `MATCH_SAME_ARMS`.
-fn lint_match_arms<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
-    if let ExprKind::Match(_, arms, MatchSource::Normal) = expr.kind {
-        let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
-            let mut h = SpanlessHash::new(cx);
-            h.hash_expr(arm.body);
-            h.finish()
-        };
-
-        let eq = |&(lindex, lhs): &(usize, &Arm<'_>), &(rindex, rhs): &(usize, &Arm<'_>)| -> bool {
-            let min_index = usize::min(lindex, rindex);
-            let max_index = usize::max(lindex, rindex);
-
-            let mut local_map: HirIdMap<HirId> = HirIdMap::default();
-            let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
-                if_chain! {
-                    if let Some(a_id) = path_to_local(a);
-                    if let Some(b_id) = path_to_local(b);
-                    let entry = match local_map.entry(a_id) {
-                        Entry::Vacant(entry) => entry,
-                        // check if using the same bindings as before
-                        Entry::Occupied(entry) => return *entry.get() == b_id,
-                    };
-                    // the names technically don't have to match; this makes the lint more conservative
-                    if cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id);
-                    if cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b);
-                    if pat_contains_local(lhs.pat, a_id);
-                    if pat_contains_local(rhs.pat, b_id);
-                    then {
-                        entry.insert(b_id);
-                        true
-                    } else {
-                        false
-                    }
-                }
-            };
-            // Arms with a guard are ignored, those can’t always be merged together
-            // This is also the case for arms in-between each there is an arm with a guard
-            (min_index..=max_index).all(|index| arms[index].guard.is_none())
-                && SpanlessEq::new(cx)
-                    .expr_fallback(eq_fallback)
-                    .eq_expr(lhs.body, rhs.body)
-                // these checks could be removed to allow unused bindings
-                && bindings_eq(lhs.pat, local_map.keys().copied().collect())
-                && bindings_eq(rhs.pat, local_map.values().copied().collect())
-        };
-
-        let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
-        for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) {
-            span_lint_and_then(
-                cx,
-                MATCH_SAME_ARMS,
-                j.body.span,
-                "this `match` has identical arm bodies",
-                |diag| {
-                    diag.span_note(i.body.span, "same as this");
-
-                    // Note: this does not use `span_suggestion` on purpose:
-                    // there is no clean way
-                    // to remove the other arm. Building a span and suggest to replace it to ""
-                    // makes an even more confusing error message. Also in order not to make up a
-                    // span for the whole pattern, the suggestion is only shown when there is only
-                    // one pattern. The user should know about `|` if they are already using it…
-
-                    let lhs = snippet(cx, i.pat.span, "<pat1>");
-                    let rhs = snippet(cx, j.pat.span, "<pat2>");
-
-                    if let PatKind::Wild = j.pat.kind {
-                        // if the last arm is _, then i could be integrated into _
-                        // note that i.pat cannot be _, because that would mean that we're
-                        // hiding all the subsequent arms, and rust won't compile
-                        diag.span_note(
-                            i.body.span,
-                            &format!(
-                                "`{}` has the same arm body as the `_` wildcard, consider removing it",
-                                lhs
-                            ),
-                        );
-                    } else {
-                        diag.span_help(i.pat.span, &format!("consider refactoring into `{} | {}`", lhs, rhs,))
-                            .help("...or consider changing the match arm bodies");
-                    }
-                },
-            );
-        }
-    }
-}
-
-fn pat_contains_local(pat: &Pat<'_>, id: HirId) -> bool {
-    let mut result = false;
-    pat.walk_short(|p| {
-        result |= matches!(p.kind, PatKind::Binding(_, binding_id, ..) if binding_id == id);
-        !result
-    });
-    result
-}
-
-/// Returns true if all the bindings in the `Pat` are in `ids` and vice versa
-fn bindings_eq(pat: &Pat<'_>, mut ids: HirIdSet) -> bool {
-    let mut result = true;
-    pat.each_binding_or_first(&mut |_, id, _, _| result &= ids.remove(&id));
-    result && ids.is_empty()
-}
diff --git a/src/tools/clippy/clippy_lints/src/matches/infalliable_detructuring_match.rs b/src/tools/clippy/clippy_lints/src/matches/infalliable_detructuring_match.rs
new file mode 100644 (file)
index 0000000..2472acb
--- /dev/null
@@ -0,0 +1,44 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{path_to_local_id, peel_blocks, strip_pat_refs};
+use rustc_errors::Applicability;
+use rustc_hir::{ExprKind, Local, MatchSource, PatKind, QPath};
+use rustc_lint::LateContext;
+
+use super::INFALLIBLE_DESTRUCTURING_MATCH;
+
+pub(crate) fn check(cx: &LateContext<'_>, local: &Local<'_>) -> bool {
+    if_chain! {
+        if !local.span.from_expansion();
+        if let Some(expr) = local.init;
+        if let ExprKind::Match(target, arms, MatchSource::Normal) = expr.kind;
+        if arms.len() == 1 && arms[0].guard.is_none();
+        if let PatKind::TupleStruct(
+            QPath::Resolved(None, variant_name), args, _) = arms[0].pat.kind;
+        if args.len() == 1;
+        if let PatKind::Binding(_, arg, ..) = strip_pat_refs(&args[0]).kind;
+        let body = peel_blocks(arms[0].body);
+        if path_to_local_id(body, arg);
+
+        then {
+            let mut applicability = Applicability::MachineApplicable;
+            span_lint_and_sugg(
+                cx,
+                INFALLIBLE_DESTRUCTURING_MATCH,
+                local.span,
+                "you seem to be trying to use `match` to destructure a single infallible pattern. \
+                Consider using `let`",
+                "try this",
+                format!(
+                    "let {}({}) = {};",
+                    snippet_with_applicability(cx, variant_name.span, "..", &mut applicability),
+                    snippet_with_applicability(cx, local.pat.span, "..", &mut applicability),
+                    snippet_with_applicability(cx, target.span, "..", &mut applicability),
+                ),
+                applicability,
+            );
+            return true;
+        }
+    }
+    false
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
new file mode 100644 (file)
index 0000000..d914eba
--- /dev/null
@@ -0,0 +1,85 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{is_lang_ctor, peel_blocks};
+use rustc_errors::Applicability;
+use rustc_hir::{Arm, BindingAnnotation, Expr, ExprKind, LangItem, PatKind, QPath};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+
+use super::MATCH_AS_REF;
+
+pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
+    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
+        let arm_ref: Option<BindingAnnotation> = if is_none_arm(cx, &arms[0]) {
+            is_ref_some_arm(cx, &arms[1])
+        } else if is_none_arm(cx, &arms[1]) {
+            is_ref_some_arm(cx, &arms[0])
+        } else {
+            None
+        };
+        if let Some(rb) = arm_ref {
+            let suggestion = if rb == BindingAnnotation::Ref {
+                "as_ref"
+            } else {
+                "as_mut"
+            };
+
+            let output_ty = cx.typeck_results().expr_ty(expr);
+            let input_ty = cx.typeck_results().expr_ty(ex);
+
+            let cast = if_chain! {
+                if let ty::Adt(_, substs) = input_ty.kind();
+                let input_ty = substs.type_at(0);
+                if let ty::Adt(_, substs) = output_ty.kind();
+                let output_ty = substs.type_at(0);
+                if let ty::Ref(_, output_ty, _) = *output_ty.kind();
+                if input_ty != output_ty;
+                then {
+                    ".map(|x| x as _)"
+                } else {
+                    ""
+                }
+            };
+
+            let mut applicability = Applicability::MachineApplicable;
+            span_lint_and_sugg(
+                cx,
+                MATCH_AS_REF,
+                expr.span,
+                &format!("use `{}()` instead", suggestion),
+                "try this",
+                format!(
+                    "{}.{}(){}",
+                    snippet_with_applicability(cx, ex.span, "_", &mut applicability),
+                    suggestion,
+                    cast,
+                ),
+                applicability,
+            );
+        }
+    }
+}
+
+// Checks if arm has the form `None => None`
+fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
+    matches!(arm.pat.kind, PatKind::Path(ref qpath) if is_lang_ctor(cx, qpath, LangItem::OptionNone))
+}
+
+// Checks if arm has the form `Some(ref v) => Some(v)` (checks for `ref` and `ref mut`)
+fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotation> {
+    if_chain! {
+        if let PatKind::TupleStruct(ref qpath, [first_pat, ..], _) = arm.pat.kind;
+        if is_lang_ctor(cx, qpath, LangItem::OptionSome);
+        if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
+        if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
+        if let ExprKind::Call(e, args) = peel_blocks(arm.body).kind;
+        if let ExprKind::Path(ref some_path) = e.kind;
+        if is_lang_ctor(cx, some_path, LangItem::OptionSome) && args.len() == 1;
+        if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
+        if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
+        then {
+            return Some(rb)
+        }
+    }
+    None
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs
new file mode 100644 (file)
index 0000000..90c50b9
--- /dev/null
@@ -0,0 +1,75 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_unit_expr;
+use clippy_utils::source::{expr_block, snippet};
+use clippy_utils::sugg::Sugg;
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Arm, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+
+use super::MATCH_BOOL;
+
+pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
+    // Type of expression is `bool`.
+    if *cx.typeck_results().expr_ty(ex).kind() == ty::Bool {
+        span_lint_and_then(
+            cx,
+            MATCH_BOOL,
+            expr.span,
+            "you seem to be trying to match on a boolean expression",
+            move |diag| {
+                if arms.len() == 2 {
+                    // no guards
+                    let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind {
+                        if let ExprKind::Lit(ref lit) = arm_bool.kind {
+                            match lit.node {
+                                LitKind::Bool(true) => Some((&*arms[0].body, &*arms[1].body)),
+                                LitKind::Bool(false) => Some((&*arms[1].body, &*arms[0].body)),
+                                _ => None,
+                            }
+                        } else {
+                            None
+                        }
+                    } else {
+                        None
+                    };
+
+                    if let Some((true_expr, false_expr)) = exprs {
+                        let sugg = match (is_unit_expr(true_expr), is_unit_expr(false_expr)) {
+                            (false, false) => Some(format!(
+                                "if {} {} else {}",
+                                snippet(cx, ex.span, "b"),
+                                expr_block(cx, true_expr, None, "..", Some(expr.span)),
+                                expr_block(cx, false_expr, None, "..", Some(expr.span))
+                            )),
+                            (false, true) => Some(format!(
+                                "if {} {}",
+                                snippet(cx, ex.span, "b"),
+                                expr_block(cx, true_expr, None, "..", Some(expr.span))
+                            )),
+                            (true, false) => {
+                                let test = Sugg::hir(cx, ex, "..");
+                                Some(format!(
+                                    "if {} {}",
+                                    !test,
+                                    expr_block(cx, false_expr, None, "..", Some(expr.span))
+                                ))
+                            },
+                            (true, true) => None,
+                        };
+
+                        if let Some(sugg) = sugg {
+                            diag.span_suggestion(
+                                expr.span,
+                                "consider using an `if`/`else` expression",
+                                sugg,
+                                Applicability::HasPlaceholders,
+                            );
+                        }
+                    }
+                }
+            },
+        );
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
new file mode 100644 (file)
index 0000000..d605b6d
--- /dev/null
@@ -0,0 +1,166 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{higher, is_wild};
+use rustc_ast::{Attribute, LitKind};
+use rustc_errors::Applicability;
+use rustc_hir::{BorrowKind, Expr, ExprKind, Guard, MatchSource, Pat};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::source_map::Spanned;
+
+use super::MATCH_LIKE_MATCHES_MACRO;
+
+/// Lint a `match` or `if let .. { .. } else { .. }` expr that could be replaced by `matches!`
+pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
+    if let Some(higher::IfLet {
+        let_pat,
+        let_expr,
+        if_then,
+        if_else: Some(if_else),
+    }) = higher::IfLet::hir(cx, expr)
+    {
+        return find_matches_sugg(
+            cx,
+            let_expr,
+            IntoIterator::into_iter([(&[][..], Some(let_pat), if_then, None), (&[][..], None, if_else, None)]),
+            expr,
+            true,
+        );
+    }
+
+    if let ExprKind::Match(scrut, arms, MatchSource::Normal) = expr.kind {
+        return find_matches_sugg(
+            cx,
+            scrut,
+            arms.iter().map(|arm| {
+                (
+                    cx.tcx.hir().attrs(arm.hir_id),
+                    Some(arm.pat),
+                    arm.body,
+                    arm.guard.as_ref(),
+                )
+            }),
+            expr,
+            false,
+        );
+    }
+
+    false
+}
+
+/// Lint a `match` or `if let` for replacement by `matches!`
+fn find_matches_sugg<'a, 'b, I>(
+    cx: &LateContext<'_>,
+    ex: &Expr<'_>,
+    mut iter: I,
+    expr: &Expr<'_>,
+    is_if_let: bool,
+) -> bool
+where
+    'b: 'a,
+    I: Clone
+        + DoubleEndedIterator
+        + ExactSizeIterator
+        + Iterator<
+            Item = (
+                &'a [Attribute],
+                Option<&'a Pat<'b>>,
+                &'a Expr<'b>,
+                Option<&'a Guard<'b>>,
+            ),
+        >,
+{
+    if_chain! {
+        if iter.len() >= 2;
+        if cx.typeck_results().expr_ty(expr).is_bool();
+        if let Some((_, last_pat_opt, last_expr, _)) = iter.next_back();
+        let iter_without_last = iter.clone();
+        if let Some((first_attrs, _, first_expr, first_guard)) = iter.next();
+        if let Some(b0) = find_bool_lit(&first_expr.kind, is_if_let);
+        if let Some(b1) = find_bool_lit(&last_expr.kind, is_if_let);
+        if b0 != b1;
+        if first_guard.is_none() || iter.len() == 0;
+        if first_attrs.is_empty();
+        if iter
+            .all(|arm| {
+                find_bool_lit(&arm.2.kind, is_if_let).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty()
+            });
+        then {
+            if let Some(last_pat) = last_pat_opt {
+                if !is_wild(last_pat) {
+                    return false;
+                }
+            }
+
+            // The suggestion may be incorrect, because some arms can have `cfg` attributes
+            // evaluated into `false` and so such arms will be stripped before.
+            let mut applicability = Applicability::MaybeIncorrect;
+            let pat = {
+                use itertools::Itertools as _;
+                iter_without_last
+                    .filter_map(|arm| {
+                        let pat_span = arm.1?.span;
+                        Some(snippet_with_applicability(cx, pat_span, "..", &mut applicability))
+                    })
+                    .join(" | ")
+            };
+            let pat_and_guard = if let Some(Guard::If(g)) = first_guard {
+                format!("{} if {}", pat, snippet_with_applicability(cx, g.span, "..", &mut applicability))
+            } else {
+                pat
+            };
+
+            // strip potential borrows (#6503), but only if the type is a reference
+            let mut ex_new = ex;
+            if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
+                if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() {
+                    ex_new = ex_inner;
+                }
+            };
+            span_lint_and_sugg(
+                cx,
+                MATCH_LIKE_MATCHES_MACRO,
+                expr.span,
+                &format!("{} expression looks like `matches!` macro", if is_if_let { "if let .. else" } else { "match" }),
+                "try this",
+                format!(
+                    "{}matches!({}, {})",
+                    if b0 { "" } else { "!" },
+                    snippet_with_applicability(cx, ex_new.span, "..", &mut applicability),
+                    pat_and_guard,
+                ),
+                applicability,
+            );
+            true
+        } else {
+            false
+        }
+    }
+}
+
+/// Extract a `bool` or `{ bool }`
+fn find_bool_lit(ex: &ExprKind<'_>, is_if_let: bool) -> Option<bool> {
+    match ex {
+        ExprKind::Lit(Spanned {
+            node: LitKind::Bool(b), ..
+        }) => Some(*b),
+        ExprKind::Block(
+            rustc_hir::Block {
+                stmts: &[],
+                expr: Some(exp),
+                ..
+            },
+            _,
+        ) if is_if_let => {
+            if let ExprKind::Lit(Spanned {
+                node: LitKind::Bool(b), ..
+            }) = exp.kind
+            {
+                Some(b)
+            } else {
+                None
+            }
+        },
+        _ => None,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs b/src/tools/clippy/clippy_lints/src/matches/match_ref_pats.rs
new file mode 100644 (file)
index 0000000..80f964b
--- /dev/null
@@ -0,0 +1,66 @@
+use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::source::snippet;
+use clippy_utils::sugg::Sugg;
+use core::iter::once;
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
+use rustc_lint::LateContext;
+
+use super::MATCH_REF_PATS;
+
+pub(crate) fn check<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
+where
+    'b: 'a,
+    I: Clone + Iterator<Item = &'a Pat<'b>>,
+{
+    if !has_multiple_ref_pats(pats.clone()) {
+        return;
+    }
+
+    let (first_sugg, msg, title);
+    let span = ex.span.source_callsite();
+    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = ex.kind {
+        first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, inner, "..").to_string()));
+        msg = "try";
+        title = "you don't need to add `&` to both the expression and the patterns";
+    } else {
+        first_sugg = once((span, Sugg::hir_with_macro_callsite(cx, ex, "..").deref().to_string()));
+        msg = "instead of prefixing all patterns with `&`, you can dereference the expression";
+        title = "you don't need to add `&` to all patterns";
+    }
+
+    let remaining_suggs = pats.filter_map(|pat| {
+        if let PatKind::Ref(refp, _) = pat.kind {
+            Some((pat.span, snippet(cx, refp.span, "..").to_string()))
+        } else {
+            None
+        }
+    });
+
+    span_lint_and_then(cx, MATCH_REF_PATS, expr.span, title, |diag| {
+        if !expr.span.from_expansion() {
+            multispan_sugg(diag, msg, first_sugg.chain(remaining_suggs));
+        }
+    });
+}
+
+fn has_multiple_ref_pats<'a, 'b, I>(pats: I) -> bool
+where
+    'b: 'a,
+    I: Iterator<Item = &'a Pat<'b>>,
+{
+    let mut ref_count = 0;
+    for opt in pats.map(|pat| match pat.kind {
+        PatKind::Ref(..) => Some(true), // &-patterns
+        PatKind::Wild => Some(false),   // an "anything" wildcard is also fine
+        _ => None,                      // any other pattern is not fine
+    }) {
+        if let Some(inner) = opt {
+            if inner {
+                ref_count += 1;
+            }
+        } else {
+            return false;
+        }
+    }
+    ref_count > 1
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
new file mode 100644 (file)
index 0000000..271a386
--- /dev/null
@@ -0,0 +1,111 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet;
+use clippy_utils::{path_to_local, search_same, SpanlessEq, SpanlessHash};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdSet, MatchSource, Pat, PatKind};
+use rustc_lint::LateContext;
+use std::collections::hash_map::Entry;
+
+use super::MATCH_SAME_ARMS;
+
+pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+    if let ExprKind::Match(_, arms, MatchSource::Normal) = expr.kind {
+        let hash = |&(_, arm): &(usize, &Arm<'_>)| -> u64 {
+            let mut h = SpanlessHash::new(cx);
+            h.hash_expr(arm.body);
+            h.finish()
+        };
+
+        let eq = |&(lindex, lhs): &(usize, &Arm<'_>), &(rindex, rhs): &(usize, &Arm<'_>)| -> bool {
+            let min_index = usize::min(lindex, rindex);
+            let max_index = usize::max(lindex, rindex);
+
+            let mut local_map: HirIdMap<HirId> = HirIdMap::default();
+            let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
+                if_chain! {
+                    if let Some(a_id) = path_to_local(a);
+                    if let Some(b_id) = path_to_local(b);
+                    let entry = match local_map.entry(a_id) {
+                        Entry::Vacant(entry) => entry,
+                        // check if using the same bindings as before
+                        Entry::Occupied(entry) => return *entry.get() == b_id,
+                    };
+                    // the names technically don't have to match; this makes the lint more conservative
+                    if cx.tcx.hir().name(a_id) == cx.tcx.hir().name(b_id);
+                    if cx.typeck_results().expr_ty(a) == cx.typeck_results().expr_ty(b);
+                    if pat_contains_local(lhs.pat, a_id);
+                    if pat_contains_local(rhs.pat, b_id);
+                    then {
+                        entry.insert(b_id);
+                        true
+                    } else {
+                        false
+                    }
+                }
+            };
+            // Arms with a guard are ignored, those can’t always be merged together
+            // This is also the case for arms in-between each there is an arm with a guard
+            (min_index..=max_index).all(|index| arms[index].guard.is_none())
+                && SpanlessEq::new(cx)
+                    .expr_fallback(eq_fallback)
+                    .eq_expr(lhs.body, rhs.body)
+                // these checks could be removed to allow unused bindings
+                && bindings_eq(lhs.pat, local_map.keys().copied().collect())
+                && bindings_eq(rhs.pat, local_map.values().copied().collect())
+        };
+
+        let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
+        for (&(_, i), &(_, j)) in search_same(&indexed_arms, hash, eq) {
+            span_lint_and_then(
+                cx,
+                MATCH_SAME_ARMS,
+                j.body.span,
+                "this `match` has identical arm bodies",
+                |diag| {
+                    diag.span_note(i.body.span, "same as this");
+
+                    // Note: this does not use `span_suggestion` on purpose:
+                    // there is no clean way
+                    // to remove the other arm. Building a span and suggest to replace it to ""
+                    // makes an even more confusing error message. Also in order not to make up a
+                    // span for the whole pattern, the suggestion is only shown when there is only
+                    // one pattern. The user should know about `|` if they are already using it…
+
+                    let lhs = snippet(cx, i.pat.span, "<pat1>");
+                    let rhs = snippet(cx, j.pat.span, "<pat2>");
+
+                    if let PatKind::Wild = j.pat.kind {
+                        // if the last arm is _, then i could be integrated into _
+                        // note that i.pat cannot be _, because that would mean that we're
+                        // hiding all the subsequent arms, and rust won't compile
+                        diag.span_note(
+                            i.body.span,
+                            &format!(
+                                "`{}` has the same arm body as the `_` wildcard, consider removing it",
+                                lhs
+                            ),
+                        );
+                    } else {
+                        diag.span_help(i.pat.span, &format!("consider refactoring into `{} | {}`", lhs, rhs,))
+                            .help("...or consider changing the match arm bodies");
+                    }
+                },
+            );
+        }
+    }
+}
+
+fn pat_contains_local(pat: &Pat<'_>, id: HirId) -> bool {
+    let mut result = false;
+    pat.walk_short(|p| {
+        result |= matches!(p.kind, PatKind::Binding(_, binding_id, ..) if binding_id == id);
+        !result
+    });
+    result
+}
+
+/// Returns true if all the bindings in the `Pat` are in `ids` and vice versa
+fn bindings_eq(pat: &Pat<'_>, mut ids: HirIdSet) -> bool {
+    let mut result = true;
+    pat.each_binding_or_first(&mut |_, id, _, _| result &= ids.remove(&id));
+    result && ids.is_empty()
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
new file mode 100644 (file)
index 0000000..8ae19e0
--- /dev/null
@@ -0,0 +1,166 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{indent_of, snippet_block, snippet_opt, snippet_with_applicability};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::{get_parent_expr, is_refutable, peel_blocks};
+use rustc_errors::Applicability;
+use rustc_hir::{Arm, Expr, ExprKind, Local, Node, PatKind};
+use rustc_lint::LateContext;
+
+use super::MATCH_SINGLE_BINDING;
+
+#[allow(clippy::too_many_lines)]
+pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], expr: &Expr<'_>) {
+    if expr.span.from_expansion() || arms.len() != 1 || is_refutable(cx, arms[0].pat) {
+        return;
+    }
+
+    // HACK:
+    // This is a hack to deal with arms that are excluded by macros like `#[cfg]`. It is only used here
+    // to prevent false positives as there is currently no better way to detect if code was excluded by
+    // a macro. See PR #6435
+    if_chain! {
+        if let Some(match_snippet) = snippet_opt(cx, expr.span);
+        if let Some(arm_snippet) = snippet_opt(cx, arms[0].span);
+        if let Some(ex_snippet) = snippet_opt(cx, ex.span);
+        let rest_snippet = match_snippet.replace(&arm_snippet, "").replace(&ex_snippet, "");
+        if rest_snippet.contains("=>");
+        then {
+            // The code it self contains another thick arrow "=>"
+            // -> Either another arm or a comment
+            return;
+        }
+    }
+
+    let matched_vars = ex.span;
+    let bind_names = arms[0].pat.span;
+    let match_body = peel_blocks(arms[0].body);
+    let mut snippet_body = if match_body.span.from_expansion() {
+        Sugg::hir_with_macro_callsite(cx, match_body, "..").to_string()
+    } else {
+        snippet_block(cx, match_body.span, "..", Some(expr.span)).to_string()
+    };
+
+    // 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(';');
+            }
+        },
+    }
+
+    let mut applicability = Applicability::MaybeIncorrect;
+    match arms[0].pat.kind {
+        PatKind::Binding(..) | PatKind::Tuple(_, _) | PatKind::Struct(..) => {
+            // If this match is in a local (`let`) stmt
+            let (target_span, sugg) = if let Some(parent_let_node) = opt_parent_let(cx, ex) {
+                (
+                    parent_let_node.span,
+                    format!(
+                        "let {} = {};\n{}let {} = {};",
+                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
+                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
+                        " ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
+                        snippet_with_applicability(cx, parent_let_node.pat.span, "..", &mut applicability),
+                        snippet_body
+                    ),
+                )
+            } else {
+                // If we are in closure, we need curly braces around suggestion
+                let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
+                let (mut cbrace_start, mut cbrace_end) = ("".to_string(), "".to_string());
+                if let Some(parent_expr) = get_parent_expr(cx, expr) {
+                    if let ExprKind::Closure(..) = parent_expr.kind {
+                        cbrace_end = format!("\n{}}}", indent);
+                        // Fix body indent due to the closure
+                        indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
+                        cbrace_start = format!("{{\n{}", indent);
+                    }
+                }
+                // 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(expr.hir_id);
+                if let Node::Arm(arm) = &cx.tcx.hir().get(parent_node_id) {
+                    if let ExprKind::Match(..) = arm.body.kind {
+                        cbrace_end = format!("\n{}}}", indent);
+                        // Fix body indent due to the match
+                        indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
+                        cbrace_start = format!("{{\n{}", indent);
+                    }
+                }
+                (
+                    expr.span,
+                    format!(
+                        "{}let {} = {};\n{}{}{}",
+                        cbrace_start,
+                        snippet_with_applicability(cx, bind_names, "..", &mut applicability),
+                        snippet_with_applicability(cx, matched_vars, "..", &mut applicability),
+                        indent,
+                        snippet_body,
+                        cbrace_end
+                    ),
+                )
+            };
+            span_lint_and_sugg(
+                cx,
+                MATCH_SINGLE_BINDING,
+                target_span,
+                "this match could be written as a `let` statement",
+                "consider using `let` statement",
+                sugg,
+                applicability,
+            );
+        },
+        PatKind::Wild => {
+            if ex.can_have_side_effects() {
+                let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0));
+                let sugg = format!(
+                    "{};\n{}{}",
+                    snippet_with_applicability(cx, ex.span, "..", &mut applicability),
+                    indent,
+                    snippet_body
+                );
+                span_lint_and_sugg(
+                    cx,
+                    MATCH_SINGLE_BINDING,
+                    expr.span,
+                    "this match could be replaced by its scrutinee and body",
+                    "consider using the scrutinee and body instead",
+                    sugg,
+                    applicability,
+                );
+            } else {
+                span_lint_and_sugg(
+                    cx,
+                    MATCH_SINGLE_BINDING,
+                    expr.span,
+                    "this match could be replaced by its body itself",
+                    "consider using the match body instead",
+                    snippet_body,
+                    Applicability::MachineApplicable,
+                );
+            }
+        },
+        _ => (),
+    }
+}
+
+/// Returns true if the `ex` match expression is in a local (`let`) statement
+fn opt_parent_let<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<&'a Local<'a>> {
+    let map = &cx.tcx.hir();
+    if_chain! {
+        if let Some(Node::Expr(parent_arm_expr)) = map.find(map.get_parent_node(ex.hir_id));
+        if let Some(Node::Local(parent_let_expr)) = map.find(map.get_parent_node(parent_arm_expr.hir_id));
+        then {
+            return Some(parent_let_expr);
+        }
+    }
+    None
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
new file mode 100644 (file)
index 0000000..3515286
--- /dev/null
@@ -0,0 +1,198 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns};
+use rustc_errors::Applicability;
+use rustc_hir::def::{CtorKind, DefKind, Res};
+use rustc_hir::{Arm, Expr, PatKind, PathSegment, QPath, Ty, TyKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, VariantDef};
+use rustc_span::sym;
+
+use super::{MATCH_WILDCARD_FOR_SINGLE_VARIANTS, WILDCARD_ENUM_MATCH_ARM};
+
+#[allow(clippy::too_many_lines)]
+pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
+    let ty = cx.typeck_results().expr_ty(ex).peel_refs();
+    let adt_def = match ty.kind() {
+        ty::Adt(adt_def, _)
+            if adt_def.is_enum()
+                && !(is_type_diagnostic_item(cx, ty, sym::Option) || is_type_diagnostic_item(cx, ty, sym::Result)) =>
+        {
+            adt_def
+        },
+        _ => return,
+    };
+
+    // First pass - check for violation, but don't do much book-keeping because this is hopefully
+    // the uncommon case, and the book-keeping is slightly expensive.
+    let mut wildcard_span = None;
+    let mut wildcard_ident = None;
+    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::Binding(_, _, ident, None) => {
+                wildcard_span = Some(arm.pat.span);
+                wildcard_ident = Some(ident);
+            },
+            _ => has_non_wild = true,
+        }
+    }
+    let wildcard_span = match wildcard_span {
+        Some(x) if has_non_wild => x,
+        _ => return,
+    };
+
+    // Accumulate the variants which should be put in place of the wildcard because they're not
+    // already covered.
+    let has_hidden = adt_def.variants.iter().any(|x| is_hidden(cx, x));
+    let mut missing_variants: Vec<_> = adt_def.variants.iter().filter(|x| !is_hidden(cx, x)).collect();
+
+    let mut path_prefix = CommonPrefixSearcher::None;
+    for arm in arms {
+        // Guards mean that this case probably isn't exhaustively covered. Technically
+        // this is incorrect, as we should really check whether each variant is exhaustively
+        // covered by the set of guards that cover it, but that's really hard to do.
+        recurse_or_patterns(arm.pat, |pat| {
+            let path = match &peel_hir_pat_refs(pat).0.kind {
+                PatKind::Path(path) => {
+                    #[allow(clippy::match_same_arms)]
+                    let id = match cx.qpath_res(path, pat.hir_id) {
+                        Res::Def(
+                            DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
+                            _,
+                        ) => return,
+                        Res::Def(_, id) => id,
+                        _ => return,
+                    };
+                    if arm.guard.is_none() {
+                        missing_variants.retain(|e| e.ctor_def_id != Some(id));
+                    }
+                    path
+                },
+                PatKind::TupleStruct(path, patterns, ..) => {
+                    if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
+                        if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) {
+                            missing_variants.retain(|e| e.ctor_def_id != Some(id));
+                        }
+                    }
+                    path
+                },
+                PatKind::Struct(path, patterns, ..) => {
+                    if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
+                        if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p.pat)) {
+                            missing_variants.retain(|e| e.def_id != id);
+                        }
+                    }
+                    path
+                },
+                _ => return,
+            };
+            match path {
+                QPath::Resolved(_, path) => path_prefix.with_path(path.segments),
+                QPath::TypeRelative(
+                    Ty {
+                        kind: TyKind::Path(QPath::Resolved(_, path)),
+                        ..
+                    },
+                    _,
+                ) => path_prefix.with_prefix(path.segments),
+                _ => (),
+            }
+        });
+    }
+
+    let format_suggestion = |variant: &VariantDef| {
+        format!(
+            "{}{}{}{}",
+            if let Some(ident) = wildcard_ident {
+                format!("{} @ ", ident.name)
+            } else {
+                String::new()
+            },
+            if let CommonPrefixSearcher::Path(path_prefix) = path_prefix {
+                let mut s = String::new();
+                for seg in path_prefix {
+                    s.push_str(seg.ident.as_str());
+                    s.push_str("::");
+                }
+                s
+            } else {
+                let mut s = cx.tcx.def_path_str(adt_def.did);
+                s.push_str("::");
+                s
+            },
+            variant.name,
+            match variant.ctor_kind {
+                CtorKind::Fn if variant.fields.len() == 1 => "(_)",
+                CtorKind::Fn => "(..)",
+                CtorKind::Const => "",
+                CtorKind::Fictive => "{ .. }",
+            }
+        )
+    };
+
+    match missing_variants.as_slice() {
+        [] => (),
+        [x] if !adt_def.is_variant_list_non_exhaustive() && !has_hidden => span_lint_and_sugg(
+            cx,
+            MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
+            wildcard_span,
+            "wildcard matches only a single variant and will also match any future added variants",
+            "try this",
+            format_suggestion(x),
+            Applicability::MaybeIncorrect,
+        ),
+        variants => {
+            let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect();
+            let message = if adt_def.is_variant_list_non_exhaustive() || has_hidden {
+                suggestions.push("_".into());
+                "wildcard matches known variants and will also match future added variants"
+            } else {
+                "wildcard match will also match any future added variants"
+            };
+
+            span_lint_and_sugg(
+                cx,
+                WILDCARD_ENUM_MATCH_ARM,
+                wildcard_span,
+                message,
+                "try this",
+                suggestions.join(" | "),
+                Applicability::MaybeIncorrect,
+            );
+        },
+    };
+}
+
+enum CommonPrefixSearcher<'a> {
+    None,
+    Path(&'a [PathSegment<'a>]),
+    Mixed,
+}
+impl<'a> CommonPrefixSearcher<'a> {
+    fn with_path(&mut self, path: &'a [PathSegment<'a>]) {
+        match path {
+            [path @ .., _] => self.with_prefix(path),
+            [] => (),
+        }
+    }
+
+    fn with_prefix(&mut self, path: &'a [PathSegment<'a>]) {
+        match self {
+            Self::None => *self = Self::Path(path),
+            Self::Path(self_path)
+                if path
+                    .iter()
+                    .map(|p| p.ident.name)
+                    .eq(self_path.iter().map(|p| p.ident.name)) => {},
+            Self::Path(_) => *self = Self::Mixed,
+            Self::Mixed => (),
+        }
+    }
+}
+
+fn is_hidden(cx: &LateContext<'_>, variant_def: &VariantDef) -> bool {
+    let attrs = cx.tcx.get_attrs(variant_def.def_id);
+    clippy_utils::attrs::is_doc_hidden(attrs) || clippy_utils::attrs::is_unstable(attrs)
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
new file mode 100644 (file)
index 0000000..bc16f17
--- /dev/null
@@ -0,0 +1,51 @@
+use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::macros::{is_panic, root_macro_call};
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::is_local_used;
+use clippy_utils::{is_wild, peel_blocks_with_stmt};
+use rustc_hir::{Arm, Expr, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::symbol::{kw, sym};
+
+use super::MATCH_WILD_ERR_ARM;
+
+pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'tcx>]) {
+    let ex_ty = cx.typeck_results().expr_ty(ex).peel_refs();
+    if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
+        for arm in arms {
+            if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
+                let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
+                if path_str == "Err" {
+                    let mut matching_wild = inner.iter().any(is_wild);
+                    let mut ident_bind_name = kw::Underscore;
+                    if !matching_wild {
+                        // Looking for unused bindings (i.e.: `_e`)
+                        for pat in inner.iter() {
+                            if let PatKind::Binding(_, id, ident, None) = pat.kind {
+                                if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) {
+                                    ident_bind_name = ident.name;
+                                    matching_wild = true;
+                                }
+                            }
+                        }
+                    }
+                    if_chain! {
+                        if matching_wild;
+                        if let Some(macro_call) = root_macro_call(peel_blocks_with_stmt(arm.body).span);
+                        if is_panic(cx, macro_call.def_id);
+                        then {
+                            // `Err(_)` or `Err(_e)` arm with `panic!` found
+                            span_lint_and_note(cx,
+                                MATCH_WILD_ERR_ARM,
+                                arm.pat.span,
+                                &format!("`Err({})` matches all errors", ident_bind_name),
+                                None,
+                                "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
+                            );
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
new file mode 100644 (file)
index 0000000..b5ee456
--- /dev/null
@@ -0,0 +1,646 @@
+use clippy_utils::{meets_msrv, msrvs};
+use rustc_hir::{Expr, ExprKind, Local, MatchSource, Pat};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+mod infalliable_detructuring_match;
+mod match_as_ref;
+mod match_bool;
+mod match_like_matches;
+mod match_ref_pats;
+mod match_same_arms;
+mod match_single_binding;
+mod match_wild_enum;
+mod match_wild_err_arm;
+mod overlapping_arms;
+mod redundant_pattern_match;
+mod rest_pat_in_fully_bound_struct;
+mod single_match;
+mod wild_in_or_pats;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for matches with a single arm where an `if let`
+    /// will usually suffice.
+    ///
+    /// ### Why is this bad?
+    /// Just readability – `if let` nests less than a `match`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # fn bar(stool: &str) {}
+    /// # let x = Some("abc");
+    /// // Bad
+    /// match x {
+    ///     Some(ref foo) => bar(foo),
+    ///     _ => (),
+    /// }
+    ///
+    /// // Good
+    /// if let Some(ref foo) = x {
+    ///     bar(foo);
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub SINGLE_MATCH,
+    style,
+    "a `match` statement with a single nontrivial arm (i.e., where the other arm is `_ => {}`) instead of `if let`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for matches with two arms where an `if let else` will
+    /// usually suffice.
+    ///
+    /// ### Why is this bad?
+    /// Just readability – `if let` nests less than a `match`.
+    ///
+    /// ### Known problems
+    /// Personal style preferences may differ.
+    ///
+    /// ### Example
+    /// Using `match`:
+    ///
+    /// ```rust
+    /// # fn bar(foo: &usize) {}
+    /// # let other_ref: usize = 1;
+    /// # let x: Option<&usize> = Some(&1);
+    /// match x {
+    ///     Some(ref foo) => bar(foo),
+    ///     _ => bar(&other_ref),
+    /// }
+    /// ```
+    ///
+    /// Using `if let` with `else`:
+    ///
+    /// ```rust
+    /// # fn bar(foo: &usize) {}
+    /// # let other_ref: usize = 1;
+    /// # let x: Option<&usize> = Some(&1);
+    /// if let Some(ref foo) = x {
+    ///     bar(foo);
+    /// } else {
+    ///     bar(&other_ref);
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub SINGLE_MATCH_ELSE,
+    pedantic,
+    "a `match` statement with two arms where the second arm's pattern is a placeholder instead of a specific match pattern"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for matches where all arms match a reference,
+    /// suggesting to remove the reference and deref the matched expression
+    /// instead. It also checks for `if let &foo = bar` blocks.
+    ///
+    /// ### Why is this bad?
+    /// It just makes the code less readable. That reference
+    /// destructuring adds nothing to the code.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// // Bad
+    /// match x {
+    ///     &A(ref y) => foo(y),
+    ///     &B => bar(),
+    ///     _ => frob(&x),
+    /// }
+    ///
+    /// // Good
+    /// match *x {
+    ///     A(ref y) => foo(y),
+    ///     B => bar(),
+    ///     _ => frob(x),
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub MATCH_REF_PATS,
+    style,
+    "a `match` or `if let` with all arms prefixed with `&` instead of deref-ing the match expression"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for matches where match expression is a `bool`. It
+    /// suggests to replace the expression with an `if...else` block.
+    ///
+    /// ### Why is this bad?
+    /// It makes the code less readable.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # fn foo() {}
+    /// # fn bar() {}
+    /// let condition: bool = true;
+    /// match condition {
+    ///     true => foo(),
+    ///     false => bar(),
+    /// }
+    /// ```
+    /// Use if/else instead:
+    /// ```rust
+    /// # fn foo() {}
+    /// # fn bar() {}
+    /// let condition: bool = true;
+    /// if condition {
+    ///     foo();
+    /// } else {
+    ///     bar();
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub MATCH_BOOL,
+    pedantic,
+    "a `match` on a boolean expression instead of an `if..else` block"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for overlapping match arms.
+    ///
+    /// ### Why is this bad?
+    /// It is likely to be an error and if not, makes the code
+    /// less obvious.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x = 5;
+    /// match x {
+    ///     1..=10 => println!("1 ... 10"),
+    ///     5..=15 => println!("5 ... 15"),
+    ///     _ => (),
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub MATCH_OVERLAPPING_ARM,
+    style,
+    "a `match` with overlapping arms"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for arm which matches all errors with `Err(_)`
+    /// and take drastic actions like `panic!`.
+    ///
+    /// ### Why is this bad?
+    /// It is generally a bad practice, similar to
+    /// catching all exceptions in java with `catch(Exception)`
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x: Result<i32, &str> = Ok(3);
+    /// match x {
+    ///     Ok(_) => println!("ok"),
+    ///     Err(_) => panic!("err"),
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub MATCH_WILD_ERR_ARM,
+    pedantic,
+    "a `match` with `Err(_)` arm and take drastic actions"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for match which is used to add a reference to an
+    /// `Option` value.
+    ///
+    /// ### Why is this bad?
+    /// Using `as_ref()` or `as_mut()` instead is shorter.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x: Option<()> = None;
+    ///
+    /// // Bad
+    /// let r: Option<&()> = match x {
+    ///     None => None,
+    ///     Some(ref v) => Some(v),
+    /// };
+    ///
+    /// // Good
+    /// let r: Option<&()> = x.as_ref();
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub MATCH_AS_REF,
+    complexity,
+    "a `match` on an Option value instead of using `as_ref()` or `as_mut`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for wildcard enum matches using `_`.
+    ///
+    /// ### Why is this bad?
+    /// New enum variants added by library updates can be missed.
+    ///
+    /// ### Known problems
+    /// Suggested replacements may be incorrect if guards exhaustively cover some
+    /// variants, and also may not use correct path to enum if it's not present in the current scope.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # enum Foo { A(usize), B(usize) }
+    /// # let x = Foo::B(1);
+    /// // Bad
+    /// match x {
+    ///     Foo::A(_) => {},
+    ///     _ => {},
+    /// }
+    ///
+    /// // Good
+    /// match x {
+    ///     Foo::A(_) => {},
+    ///     Foo::B(_) => {},
+    /// }
+    /// ```
+    #[clippy::version = "1.34.0"]
+    pub WILDCARD_ENUM_MATCH_ARM,
+    restriction,
+    "a wildcard enum match arm using `_`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for wildcard enum matches for a single variant.
+    ///
+    /// ### Why is this bad?
+    /// New enum variants added by library updates can be missed.
+    ///
+    /// ### Known problems
+    /// Suggested replacements may not use correct path to enum
+    /// if it's not present in the current scope.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # enum Foo { A, B, C }
+    /// # let x = Foo::B;
+    /// // Bad
+    /// match x {
+    ///     Foo::A => {},
+    ///     Foo::B => {},
+    ///     _ => {},
+    /// }
+    ///
+    /// // Good
+    /// match x {
+    ///     Foo::A => {},
+    ///     Foo::B => {},
+    ///     Foo::C => {},
+    /// }
+    /// ```
+    #[clippy::version = "1.45.0"]
+    pub MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
+    pedantic,
+    "a wildcard enum match for a single variant"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for wildcard pattern used with others patterns in same match arm.
+    ///
+    /// ### Why is this bad?
+    /// Wildcard pattern already covers any other pattern as it will match anyway.
+    /// It makes the code less readable, especially to spot wildcard pattern use in match arm.
+    ///
+    /// ### Example
+    /// ```rust
+    /// // Bad
+    /// match "foo" {
+    ///     "a" => {},
+    ///     "bar" | _ => {},
+    /// }
+    ///
+    /// // Good
+    /// match "foo" {
+    ///     "a" => {},
+    ///     _ => {},
+    /// }
+    /// ```
+    #[clippy::version = "1.42.0"]
+    pub WILDCARD_IN_OR_PATTERNS,
+    complexity,
+    "a wildcard pattern used with others patterns in same match arm"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for matches being used to destructure a single-variant enum
+    /// or tuple struct where a `let` will suffice.
+    ///
+    /// ### Why is this bad?
+    /// Just readability – `let` doesn't nest, whereas a `match` does.
+    ///
+    /// ### Example
+    /// ```rust
+    /// enum Wrapper {
+    ///     Data(i32),
+    /// }
+    ///
+    /// let wrapper = Wrapper::Data(42);
+    ///
+    /// let data = match wrapper {
+    ///     Wrapper::Data(i) => i,
+    /// };
+    /// ```
+    ///
+    /// The correct use would be:
+    /// ```rust
+    /// enum Wrapper {
+    ///     Data(i32),
+    /// }
+    ///
+    /// let wrapper = Wrapper::Data(42);
+    /// let Wrapper::Data(data) = wrapper;
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub INFALLIBLE_DESTRUCTURING_MATCH,
+    style,
+    "a `match` statement with a single infallible arm instead of a `let`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for useless match that binds to only one value.
+    ///
+    /// ### Why is this bad?
+    /// Readability and needless complexity.
+    ///
+    /// ### Known problems
+    ///  Suggested replacements may be incorrect when `match`
+    /// is actually binding temporary value, bringing a 'dropped while borrowed' error.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # let a = 1;
+    /// # let b = 2;
+    ///
+    /// // Bad
+    /// match (a, b) {
+    ///     (c, d) => {
+    ///         // useless match
+    ///     }
+    /// }
+    ///
+    /// // Good
+    /// let (c, d) = (a, b);
+    /// ```
+    #[clippy::version = "1.43.0"]
+    pub MATCH_SINGLE_BINDING,
+    complexity,
+    "a match with a single binding instead of using `let` statement"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for unnecessary '..' pattern binding on struct when all fields are explicitly matched.
+    ///
+    /// ### Why is this bad?
+    /// Correctness and readability. It's like having a wildcard pattern after
+    /// matching all enum variants explicitly.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # struct A { a: i32 }
+    /// let a = A { a: 5 };
+    ///
+    /// // Bad
+    /// match a {
+    ///     A { a: 5, .. } => {},
+    ///     _ => {},
+    /// }
+    ///
+    /// // Good
+    /// match a {
+    ///     A { a: 5 } => {},
+    ///     _ => {},
+    /// }
+    /// ```
+    #[clippy::version = "1.43.0"]
+    pub REST_PAT_IN_FULLY_BOUND_STRUCTS,
+    restriction,
+    "a match on a struct that binds all fields but still uses the wildcard pattern"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Lint for redundant pattern matching over `Result`, `Option`,
+    /// `std::task::Poll` or `std::net::IpAddr`
+    ///
+    /// ### Why is this bad?
+    /// It's more concise and clear to just use the proper
+    /// utility function
+    ///
+    /// ### Known problems
+    /// This will change the drop order for the matched type. Both `if let` and
+    /// `while let` will drop the value at the end of the block, both `if` and `while` will drop the
+    /// value before entering the block. For most types this change will not matter, but for a few
+    /// types this will not be an acceptable change (e.g. locks). See the
+    /// [reference](https://doc.rust-lang.org/reference/destructors.html#drop-scopes) for more about
+    /// drop order.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::task::Poll;
+    /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    /// if let Ok(_) = Ok::<i32, i32>(42) {}
+    /// if let Err(_) = Err::<i32, i32>(42) {}
+    /// if let None = None::<()> {}
+    /// if let Some(_) = Some(42) {}
+    /// if let Poll::Pending = Poll::Pending::<()> {}
+    /// if let Poll::Ready(_) = Poll::Ready(42) {}
+    /// if let IpAddr::V4(_) = IpAddr::V4(Ipv4Addr::LOCALHOST) {}
+    /// if let IpAddr::V6(_) = IpAddr::V6(Ipv6Addr::LOCALHOST) {}
+    /// match Ok::<i32, i32>(42) {
+    ///     Ok(_) => true,
+    ///     Err(_) => false,
+    /// };
+    /// ```
+    ///
+    /// The more idiomatic use would be:
+    ///
+    /// ```rust
+    /// # use std::task::Poll;
+    /// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
+    /// if Ok::<i32, i32>(42).is_ok() {}
+    /// if Err::<i32, i32>(42).is_err() {}
+    /// if None::<()>.is_none() {}
+    /// if Some(42).is_some() {}
+    /// if Poll::Pending::<()>.is_pending() {}
+    /// if Poll::Ready(42).is_ready() {}
+    /// if IpAddr::V4(Ipv4Addr::LOCALHOST).is_ipv4() {}
+    /// if IpAddr::V6(Ipv6Addr::LOCALHOST).is_ipv6() {}
+    /// Ok::<i32, i32>(42).is_ok();
+    /// ```
+    #[clippy::version = "1.31.0"]
+    pub REDUNDANT_PATTERN_MATCHING,
+    style,
+    "use the proper utility function avoiding an `if let`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `match`  or `if let` expressions producing a
+    /// `bool` that could be written using `matches!`
+    ///
+    /// ### Why is this bad?
+    /// Readability and needless complexity.
+    ///
+    /// ### Known problems
+    /// This lint falsely triggers, if there are arms with
+    /// `cfg` attributes that remove an arm evaluating to `false`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x = Some(5);
+    ///
+    /// // Bad
+    /// let a = match x {
+    ///     Some(0) => true,
+    ///     _ => false,
+    /// };
+    ///
+    /// let a = if let Some(0) = x {
+    ///     true
+    /// } else {
+    ///     false
+    /// };
+    ///
+    /// // Good
+    /// let a = matches!(x, Some(0));
+    /// ```
+    #[clippy::version = "1.47.0"]
+    pub MATCH_LIKE_MATCHES_MACRO,
+    style,
+    "a match that could be written with the matches! macro"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `match` with identical arm bodies.
+    ///
+    /// ### Why is this bad?
+    /// This is probably a copy & paste error. If arm bodies
+    /// are the same on purpose, you can factor them
+    /// [using `|`](https://doc.rust-lang.org/book/patterns.html#multiple-patterns).
+    ///
+    /// ### Known problems
+    /// False positive possible with order dependent `match`
+    /// (see issue
+    /// [#860](https://github.com/rust-lang/rust-clippy/issues/860)).
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// match foo {
+    ///     Bar => bar(),
+    ///     Quz => quz(),
+    ///     Baz => bar(), // <= oops
+    /// }
+    /// ```
+    ///
+    /// This should probably be
+    /// ```rust,ignore
+    /// match foo {
+    ///     Bar => bar(),
+    ///     Quz => quz(),
+    ///     Baz => baz(), // <= fixed
+    /// }
+    /// ```
+    ///
+    /// or if the original code was not a typo:
+    /// ```rust,ignore
+    /// match foo {
+    ///     Bar | Baz => bar(), // <= shows the intent better
+    ///     Quz => quz(),
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub MATCH_SAME_ARMS,
+    pedantic,
+    "`match` with identical arm bodies"
+}
+
+#[derive(Default)]
+pub struct Matches {
+    msrv: Option<RustcVersion>,
+    infallible_destructuring_match_linted: bool,
+}
+
+impl Matches {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self {
+            msrv,
+            ..Matches::default()
+        }
+    }
+}
+
+impl_lint_pass!(Matches => [
+    SINGLE_MATCH,
+    MATCH_REF_PATS,
+    MATCH_BOOL,
+    SINGLE_MATCH_ELSE,
+    MATCH_OVERLAPPING_ARM,
+    MATCH_WILD_ERR_ARM,
+    MATCH_AS_REF,
+    WILDCARD_ENUM_MATCH_ARM,
+    MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
+    WILDCARD_IN_OR_PATTERNS,
+    MATCH_SINGLE_BINDING,
+    INFALLIBLE_DESTRUCTURING_MATCH,
+    REST_PAT_IN_FULLY_BOUND_STRUCTS,
+    REDUNDANT_PATTERN_MATCHING,
+    MATCH_LIKE_MATCHES_MACRO,
+    MATCH_SAME_ARMS,
+]);
+
+impl<'tcx> LateLintPass<'tcx> for Matches {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+
+        redundant_pattern_match::check(cx, expr);
+
+        if meets_msrv(self.msrv.as_ref(), &msrvs::MATCHES_MACRO) {
+            if !match_like_matches::check(cx, expr) {
+                match_same_arms::check(cx, expr);
+            }
+        } else {
+            match_same_arms::check(cx, expr);
+        }
+
+        if let ExprKind::Match(ex, arms, MatchSource::Normal) = expr.kind {
+            single_match::check(cx, ex, arms, expr);
+            match_bool::check(cx, ex, arms, expr);
+            overlapping_arms::check(cx, ex, arms);
+            match_wild_err_arm::check(cx, ex, arms);
+            match_wild_enum::check(cx, ex, arms);
+            match_as_ref::check(cx, ex, arms, expr);
+            wild_in_or_pats::check(cx, arms);
+
+            if self.infallible_destructuring_match_linted {
+                self.infallible_destructuring_match_linted = false;
+            } else {
+                match_single_binding::check(cx, ex, arms, expr);
+            }
+        }
+        if let ExprKind::Match(ex, arms, _) = expr.kind {
+            match_ref_pats::check(cx, ex, arms.iter().map(|el| el.pat), expr);
+        }
+    }
+
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
+        self.infallible_destructuring_match_linted |= infalliable_detructuring_match::check(cx, local);
+    }
+
+    fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
+        rest_pat_in_fully_bound_struct::check(cx, pat);
+    }
+
+    extract_msrv_attr!(LateContext);
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
new file mode 100644 (file)
index 0000000..7e65812
--- /dev/null
@@ -0,0 +1,181 @@
+use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
+use clippy_utils::diagnostics::span_lint_and_note;
+use core::cmp::Ordering;
+use rustc_hir::{Arm, Expr, PatKind, RangeEnd};
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::Span;
+
+use super::MATCH_OVERLAPPING_ARM;
+
+pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
+    if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
+        let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
+        if !ranges.is_empty() {
+            if let Some((start, end)) = overlapping(&ranges) {
+                span_lint_and_note(
+                    cx,
+                    MATCH_OVERLAPPING_ARM,
+                    start.span,
+                    "some ranges overlap",
+                    Some(end.span),
+                    "overlaps with this",
+                );
+            }
+        }
+    }
+}
+
+/// Gets the ranges for each range pattern arm. Applies `ty` bounds for open ranges.
+fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) -> Vec<SpannedRange<FullInt>> {
+    arms.iter()
+        .filter_map(|arm| {
+            if let Arm { pat, guard: None, .. } = *arm {
+                if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind {
+                    let lhs_const = match lhs {
+                        Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0,
+                        None => miri_to_const(ty.numeric_min_val(cx.tcx)?)?,
+                    };
+                    let rhs_const = match rhs {
+                        Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
+                        None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
+                    };
+
+                    let lhs_val = lhs_const.int_value(cx, ty)?;
+                    let rhs_val = rhs_const.int_value(cx, ty)?;
+
+                    let rhs_bound = match range_end {
+                        RangeEnd::Included => EndBound::Included(rhs_val),
+                        RangeEnd::Excluded => EndBound::Excluded(rhs_val),
+                    };
+                    return Some(SpannedRange {
+                        span: pat.span,
+                        node: (lhs_val, rhs_bound),
+                    });
+                }
+
+                if let PatKind::Lit(value) = pat.kind {
+                    let value = constant_full_int(cx, cx.typeck_results(), value)?;
+                    return Some(SpannedRange {
+                        span: pat.span,
+                        node: (value, EndBound::Included(value)),
+                    });
+                }
+            }
+            None
+        })
+        .collect()
+}
+
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum EndBound<T> {
+    Included(T),
+    Excluded(T),
+}
+
+#[derive(Debug, Eq, PartialEq)]
+struct SpannedRange<T> {
+    pub span: Span,
+    pub node: (T, EndBound<T>),
+}
+
+fn overlapping<T>(ranges: &[SpannedRange<T>]) -> Option<(&SpannedRange<T>, &SpannedRange<T>)>
+where
+    T: Copy + Ord,
+{
+    #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
+    enum BoundKind {
+        EndExcluded,
+        Start,
+        EndIncluded,
+    }
+
+    #[derive(Copy, Clone, Debug, Eq, PartialEq)]
+    struct RangeBound<'a, T>(T, BoundKind, &'a SpannedRange<T>);
+
+    impl<'a, T: Copy + Ord> PartialOrd for RangeBound<'a, T> {
+        fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+            Some(self.cmp(other))
+        }
+    }
+
+    impl<'a, T: Copy + Ord> Ord for RangeBound<'a, T> {
+        fn cmp(&self, RangeBound(other_value, other_kind, _): &Self) -> Ordering {
+            let RangeBound(self_value, self_kind, _) = *self;
+            (self_value, self_kind).cmp(&(*other_value, *other_kind))
+        }
+    }
+
+    let mut values = Vec::with_capacity(2 * ranges.len());
+
+    for r @ SpannedRange { node: (start, end), .. } in ranges {
+        values.push(RangeBound(*start, BoundKind::Start, r));
+        values.push(match end {
+            EndBound::Excluded(val) => RangeBound(*val, BoundKind::EndExcluded, r),
+            EndBound::Included(val) => RangeBound(*val, BoundKind::EndIncluded, r),
+        });
+    }
+
+    values.sort();
+
+    let mut started = vec![];
+
+    for RangeBound(_, kind, range) in values {
+        match kind {
+            BoundKind::Start => started.push(range),
+            BoundKind::EndExcluded | BoundKind::EndIncluded => {
+                let mut overlap = None;
+
+                while let Some(last_started) = started.pop() {
+                    if last_started == range {
+                        break;
+                    }
+                    overlap = Some(last_started);
+                }
+
+                if let Some(first_overlapping) = overlap {
+                    return Some((range, first_overlapping));
+                }
+            },
+        }
+    }
+
+    None
+}
+
+#[test]
+fn test_overlapping() {
+    use rustc_span::source_map::DUMMY_SP;
+
+    let sp = |s, e| SpannedRange {
+        span: DUMMY_SP,
+        node: (s, e),
+    };
+
+    assert_eq!(None, overlapping::<u8>(&[]));
+    assert_eq!(None, overlapping(&[sp(1, EndBound::Included(4))]));
+    assert_eq!(
+        None,
+        overlapping(&[sp(1, EndBound::Included(4)), sp(5, EndBound::Included(6))])
+    );
+    assert_eq!(
+        None,
+        overlapping(&[
+            sp(1, EndBound::Included(4)),
+            sp(5, EndBound::Included(6)),
+            sp(10, EndBound::Included(11))
+        ],)
+    );
+    assert_eq!(
+        Some((&sp(1, EndBound::Included(4)), &sp(3, EndBound::Included(6)))),
+        overlapping(&[sp(1, EndBound::Included(4)), sp(3, EndBound::Included(6))])
+    );
+    assert_eq!(
+        Some((&sp(5, EndBound::Included(6)), &sp(6, EndBound::Included(11)))),
+        overlapping(&[
+            sp(1, EndBound::Included(4)),
+            sp(5, EndBound::Included(6)),
+            sp(6, EndBound::Included(11))
+        ],)
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
new file mode 100644 (file)
index 0000000..e195fdd
--- /dev/null
@@ -0,0 +1,436 @@
+use super::REDUNDANT_PATTERN_MATCHING;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::snippet;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, is_type_lang_item, match_type};
+use clippy_utils::{higher, match_def_path};
+use clippy_utils::{is_lang_ctor, is_trait_method, paths};
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
+use rustc_hir::LangItem::{OptionNone, PollPending};
+use rustc_hir::{
+    intravisit::{walk_expr, Visitor},
+    Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath, UnOp,
+};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, subst::GenericArgKind, DefIdTree, Ty};
+use rustc_span::sym;
+
+pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+    if let Some(higher::IfLet {
+        if_else,
+        let_pat,
+        let_expr,
+        ..
+    }) = higher::IfLet::hir(cx, expr)
+    {
+        find_sugg_for_if_let(cx, expr, let_pat, let_expr, "if", if_else.is_some());
+    }
+    if let ExprKind::Match(op, arms, MatchSource::Normal) = &expr.kind {
+        find_sugg_for_match(cx, expr, op, arms);
+    }
+    if let Some(higher::WhileLet { let_pat, let_expr, .. }) = higher::WhileLet::hir(expr) {
+        find_sugg_for_if_let(cx, expr, let_pat, let_expr, "while", false);
+    }
+}
+
+/// Checks if the drop order for a type matters. Some std types implement drop solely to
+/// deallocate memory. For these types, and composites containing them, changing the drop order
+/// won't result in any observable side effects.
+fn type_needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    type_needs_ordered_drop_inner(cx, ty, &mut FxHashSet::default())
+}
+
+fn type_needs_ordered_drop_inner<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet<Ty<'tcx>>) -> bool {
+    if !seen.insert(ty) {
+        return false;
+    }
+    if !ty.needs_drop(cx.tcx, cx.param_env) {
+        false
+    } else if !cx
+        .tcx
+        .lang_items()
+        .drop_trait()
+        .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+    {
+        // This type doesn't implement drop, so no side effects here.
+        // Check if any component type has any.
+        match ty.kind() {
+            ty::Tuple(_) => ty.tuple_fields().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
+            ty::Array(ty, _) => type_needs_ordered_drop_inner(cx, *ty, seen),
+            ty::Adt(adt, subs) => adt
+                .all_fields()
+                .map(|f| f.ty(cx.tcx, subs))
+                .any(|ty| type_needs_ordered_drop_inner(cx, ty, seen)),
+            _ => true,
+        }
+    }
+    // Check for std types which implement drop, but only for memory allocation.
+    else if is_type_diagnostic_item(cx, ty, sym::Vec)
+        || is_type_lang_item(cx, ty, LangItem::OwnedBox)
+        || is_type_diagnostic_item(cx, ty, sym::Rc)
+        || is_type_diagnostic_item(cx, ty, sym::Arc)
+        || is_type_diagnostic_item(cx, ty, sym::cstring_type)
+        || is_type_diagnostic_item(cx, ty, sym::BTreeMap)
+        || is_type_diagnostic_item(cx, ty, sym::LinkedList)
+        || match_type(cx, ty, &paths::WEAK_RC)
+        || match_type(cx, ty, &paths::WEAK_ARC)
+    {
+        // Check all of the generic arguments.
+        if let ty::Adt(_, subs) = ty.kind() {
+            subs.types().any(|ty| type_needs_ordered_drop_inner(cx, ty, seen))
+        } else {
+            true
+        }
+    } else {
+        true
+    }
+}
+
+// Extract the generic arguments out of a type
+fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
+    if_chain! {
+        if let ty::Adt(_, subs) = ty.kind();
+        if let Some(sub) = subs.get(index);
+        if let GenericArgKind::Type(sub_ty) = sub.unpack();
+        then {
+            Some(sub_ty)
+        } else {
+            None
+        }
+    }
+}
+
+// Checks if there are any temporaries created in the given expression for which drop order
+// matters.
+fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    struct V<'a, 'tcx> {
+        cx: &'a LateContext<'tcx>,
+        res: bool,
+    }
+    impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
+        fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+            match expr.kind {
+                // Taking the reference of a value leaves a temporary
+                // e.g. In `&String::new()` the string is a temporary value.
+                // Remaining fields are temporary values
+                // e.g. In `(String::new(), 0).1` the string is a temporary value.
+                ExprKind::AddrOf(_, _, expr) | ExprKind::Field(expr, _) => {
+                    if !matches!(expr.kind, ExprKind::Path(_)) {
+                        if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(expr)) {
+                            self.res = true;
+                        } else {
+                            self.visit_expr(expr);
+                        }
+                    }
+                },
+                // the base type is alway taken by reference.
+                // e.g. In `(vec![0])[0]` the vector is a temporary value.
+                ExprKind::Index(base, index) => {
+                    if !matches!(base.kind, ExprKind::Path(_)) {
+                        if type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(base)) {
+                            self.res = true;
+                        } else {
+                            self.visit_expr(base);
+                        }
+                    }
+                    self.visit_expr(index);
+                },
+                // Method calls can take self by reference.
+                // e.g. In `String::new().len()` the string is a temporary value.
+                ExprKind::MethodCall(_, [self_arg, args @ ..], _) => {
+                    if !matches!(self_arg.kind, ExprKind::Path(_)) {
+                        let self_by_ref = self
+                            .cx
+                            .typeck_results()
+                            .type_dependent_def_id(expr.hir_id)
+                            .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().inputs()[0].is_ref());
+                        if self_by_ref && type_needs_ordered_drop(self.cx, self.cx.typeck_results().expr_ty(self_arg)) {
+                            self.res = true;
+                        } else {
+                            self.visit_expr(self_arg);
+                        }
+                    }
+                    args.iter().for_each(|arg| self.visit_expr(arg));
+                },
+                // Either explicitly drops values, or changes control flow.
+                ExprKind::DropTemps(_)
+                | ExprKind::Ret(_)
+                | ExprKind::Break(..)
+                | ExprKind::Yield(..)
+                | ExprKind::Block(Block { expr: None, .. }, _)
+                | ExprKind::Loop(..) => (),
+
+                // Only consider the final expression.
+                ExprKind::Block(Block { expr: Some(expr), .. }, _) => self.visit_expr(expr),
+
+                _ => walk_expr(self, expr),
+            }
+        }
+    }
+
+    let mut v = V { cx, res: false };
+    v.visit_expr(expr);
+    v.res
+}
+
+fn find_sugg_for_if_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+    let_pat: &Pat<'_>,
+    let_expr: &'tcx Expr<'_>,
+    keyword: &'static str,
+    has_else: bool,
+) {
+    // also look inside refs
+    // if we have &None for example, peel it so we can detect "if let None = x"
+    let check_pat = match let_pat.kind {
+        PatKind::Ref(inner, _mutability) => inner,
+        _ => let_pat,
+    };
+    let op_ty = cx.typeck_results().expr_ty(let_expr);
+    // Determine which function should be used, and the type contained by the corresponding
+    // variant.
+    let (good_method, inner_ty) = match check_pat.kind {
+        PatKind::TupleStruct(ref qpath, [sub_pat], _) => {
+            if let PatKind::Wild = sub_pat.kind {
+                let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id);
+                let Some(id) = res.opt_def_id().and_then(|ctor_id| cx.tcx.parent(ctor_id)) else { return };
+                let lang_items = cx.tcx.lang_items();
+                if Some(id) == lang_items.result_ok_variant() {
+                    ("is_ok()", try_get_generic_ty(op_ty, 0).unwrap_or(op_ty))
+                } else if Some(id) == lang_items.result_err_variant() {
+                    ("is_err()", try_get_generic_ty(op_ty, 1).unwrap_or(op_ty))
+                } else if Some(id) == lang_items.option_some_variant() {
+                    ("is_some()", op_ty)
+                } else if Some(id) == lang_items.poll_ready_variant() {
+                    ("is_ready()", op_ty)
+                } else if match_def_path(cx, id, &paths::IPADDR_V4) {
+                    ("is_ipv4()", op_ty)
+                } else if match_def_path(cx, id, &paths::IPADDR_V6) {
+                    ("is_ipv6()", op_ty)
+                } else {
+                    return;
+                }
+            } else {
+                return;
+            }
+        },
+        PatKind::Path(ref path) => {
+            let method = if is_lang_ctor(cx, path, OptionNone) {
+                "is_none()"
+            } else if is_lang_ctor(cx, path, PollPending) {
+                "is_pending()"
+            } else {
+                return;
+            };
+            // `None` and `Pending` don't have an inner type.
+            (method, cx.tcx.types.unit)
+        },
+        _ => return,
+    };
+
+    // If this is the last expression in a block or there is an else clause then the whole
+    // type needs to be considered, not just the inner type of the branch being matched on.
+    // Note the last expression in a block is dropped after all local bindings.
+    let check_ty = if has_else
+        || (keyword == "if" && matches!(cx.tcx.hir().parent_iter(expr.hir_id).next(), Some((_, Node::Block(..)))))
+    {
+        op_ty
+    } else {
+        inner_ty
+    };
+
+    // All temporaries created in the scrutinee expression are dropped at the same time as the
+    // scrutinee would be, so they have to be considered as well.
+    // e.g. in `if let Some(x) = foo.lock().unwrap().baz.as_ref() { .. }` the lock will be held
+    // for the duration if body.
+    let needs_drop = type_needs_ordered_drop(cx, check_ty) || temporaries_need_ordered_drop(cx, let_expr);
+
+    // check that `while_let_on_iterator` lint does not trigger
+    if_chain! {
+        if keyword == "while";
+        if let ExprKind::MethodCall(method_path, _, _) = let_expr.kind;
+        if method_path.ident.name == sym::next;
+        if is_trait_method(cx, let_expr, sym::Iterator);
+        then {
+            return;
+        }
+    }
+
+    let result_expr = match &let_expr.kind {
+        ExprKind::AddrOf(_, _, borrowed) => borrowed,
+        ExprKind::Unary(UnOp::Deref, deref) => deref,
+        _ => let_expr,
+    };
+
+    span_lint_and_then(
+        cx,
+        REDUNDANT_PATTERN_MATCHING,
+        let_pat.span,
+        &format!("redundant pattern matching, consider using `{}`", good_method),
+        |diag| {
+            // if/while let ... = ... { ... }
+            // ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+            let expr_span = expr.span;
+
+            // if/while let ... = ... { ... }
+            //                 ^^^
+            let op_span = result_expr.span.source_callsite();
+
+            // if/while let ... = ... { ... }
+            // ^^^^^^^^^^^^^^^^^^^
+            let span = expr_span.until(op_span.shrink_to_hi());
+
+            let app = if needs_drop {
+                Applicability::MaybeIncorrect
+            } else {
+                Applicability::MachineApplicable
+            };
+
+            let sugg = Sugg::hir_with_macro_callsite(cx, result_expr, "_")
+                .maybe_par()
+                .to_string();
+
+            diag.span_suggestion(span, "try this", format!("{} {}.{}", keyword, sugg, good_method), app);
+
+            if needs_drop {
+                diag.note("this will change drop order of the result, as well as all temporaries");
+                diag.note("add `#[allow(clippy::redundant_pattern_matching)]` if this is important");
+            }
+        },
+    );
+}
+
+fn find_sugg_for_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op: &Expr<'_>, arms: &[Arm<'_>]) {
+    if arms.len() == 2 {
+        let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind);
+
+        let found_good_method = match node_pair {
+            (
+                PatKind::TupleStruct(ref path_left, patterns_left, _),
+                PatKind::TupleStruct(ref path_right, patterns_right, _),
+            ) if patterns_left.len() == 1 && patterns_right.len() == 1 => {
+                if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) {
+                    find_good_method_for_match(
+                        cx,
+                        arms,
+                        path_left,
+                        path_right,
+                        &paths::RESULT_OK,
+                        &paths::RESULT_ERR,
+                        "is_ok()",
+                        "is_err()",
+                    )
+                    .or_else(|| {
+                        find_good_method_for_match(
+                            cx,
+                            arms,
+                            path_left,
+                            path_right,
+                            &paths::IPADDR_V4,
+                            &paths::IPADDR_V6,
+                            "is_ipv4()",
+                            "is_ipv6()",
+                        )
+                    })
+                } else {
+                    None
+                }
+            },
+            (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right))
+            | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _))
+                if patterns.len() == 1 =>
+            {
+                if let PatKind::Wild = patterns[0].kind {
+                    find_good_method_for_match(
+                        cx,
+                        arms,
+                        path_left,
+                        path_right,
+                        &paths::OPTION_SOME,
+                        &paths::OPTION_NONE,
+                        "is_some()",
+                        "is_none()",
+                    )
+                    .or_else(|| {
+                        find_good_method_for_match(
+                            cx,
+                            arms,
+                            path_left,
+                            path_right,
+                            &paths::POLL_READY,
+                            &paths::POLL_PENDING,
+                            "is_ready()",
+                            "is_pending()",
+                        )
+                    })
+                } else {
+                    None
+                }
+            },
+            _ => None,
+        };
+
+        if let Some(good_method) = found_good_method {
+            let span = expr.span.to(op.span);
+            let result_expr = match &op.kind {
+                ExprKind::AddrOf(_, _, borrowed) => borrowed,
+                _ => op,
+            };
+            span_lint_and_then(
+                cx,
+                REDUNDANT_PATTERN_MATCHING,
+                expr.span,
+                &format!("redundant pattern matching, consider using `{}`", good_method),
+                |diag| {
+                    diag.span_suggestion(
+                        span,
+                        "try this",
+                        format!("{}.{}", snippet(cx, result_expr.span, "_"), good_method),
+                        Applicability::MaybeIncorrect, // snippet
+                    );
+                },
+            );
+        }
+    }
+}
+
+#[allow(clippy::too_many_arguments)]
+fn find_good_method_for_match<'a>(
+    cx: &LateContext<'_>,
+    arms: &[Arm<'_>],
+    path_left: &QPath<'_>,
+    path_right: &QPath<'_>,
+    expected_left: &[&str],
+    expected_right: &[&str],
+    should_be_left: &'a str,
+    should_be_right: &'a str,
+) -> Option<&'a str> {
+    let left_id = cx
+        .typeck_results()
+        .qpath_res(path_left, arms[0].pat.hir_id)
+        .opt_def_id()?;
+    let right_id = cx
+        .typeck_results()
+        .qpath_res(path_right, arms[1].pat.hir_id)
+        .opt_def_id()?;
+    let body_node_pair = if match_def_path(cx, left_id, expected_left) && match_def_path(cx, right_id, expected_right) {
+        (&(*arms[0].body).kind, &(*arms[1].body).kind)
+    } else if match_def_path(cx, right_id, expected_left) && match_def_path(cx, right_id, expected_right) {
+        (&(*arms[1].body).kind, &(*arms[0].body).kind)
+    } else {
+        return None;
+    };
+
+    match body_node_pair {
+        (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) {
+            (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left),
+            (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right),
+            _ => None,
+        },
+        _ => None,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs b/src/tools/clippy/clippy_lints/src/matches/rest_pat_in_fully_bound_struct.rs
new file mode 100644 (file)
index 0000000..5076239
--- /dev/null
@@ -0,0 +1,29 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_hir::{Pat, PatKind, QPath};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+
+use super::REST_PAT_IN_FULLY_BOUND_STRUCTS;
+
+pub(crate) fn check(cx: &LateContext<'_>, pat: &Pat<'_>) {
+    if_chain! {
+        if !pat.span.from_expansion();
+        if let PatKind::Struct(QPath::Resolved(_, path), fields, true) = pat.kind;
+        if let Some(def_id) = path.res.opt_def_id();
+        let ty = cx.tcx.type_of(def_id);
+        if let ty::Adt(def, _) = ty.kind();
+        if def.is_struct() || def.is_union();
+        if fields.len() == def.non_enum_variant().fields.len();
+
+        then {
+            span_lint_and_help(
+                cx,
+                REST_PAT_IN_FULLY_BOUND_STRUCTS,
+                pat.span,
+                "unnecessary use of `..` pattern in struct binding. All fields were already bound",
+                None,
+                "consider removing `..` from this binding",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
new file mode 100644 (file)
index 0000000..0c4cb45
--- /dev/null
@@ -0,0 +1,269 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::{expr_block, snippet};
+use clippy_utils::ty::{implements_trait, match_type, peel_mid_ty_refs};
+use clippy_utils::{
+    is_lint_allowed, is_unit_expr, is_wild, paths, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs,
+};
+use core::cmp::max;
+use rustc_errors::Applicability;
+use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty};
+
+use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
+
+#[rustfmt::skip]
+pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
+    if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
+        if expr.span.from_expansion() {
+            // Don't lint match expressions present in
+            // macro_rules! block
+            return;
+        }
+        if let PatKind::Or(..) = arms[0].pat.kind {
+            // don't lint for or patterns for now, this makes
+            // the lint noisy in unnecessary situations
+            return;
+        }
+        let els = arms[1].body;
+        let els = if is_unit_expr(peel_blocks(els)) {
+            None
+        } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
+            if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
+                // single statement/expr "else" block, don't lint
+                return;
+            }
+            // block with 2+ statements or 1 expr and 1+ statement
+            Some(els)
+        } else {
+            // not a block, don't lint
+            return;
+        };
+
+        let ty = cx.typeck_results().expr_ty(ex);
+        if *ty.kind() != ty::Bool || is_lint_allowed(cx, MATCH_BOOL, ex.hir_id) {
+            check_single_pattern(cx, ex, arms, expr, els);
+            check_opt_like(cx, ex, arms, expr, ty, els);
+        }
+    }
+}
+
+fn check_single_pattern(
+    cx: &LateContext<'_>,
+    ex: &Expr<'_>,
+    arms: &[Arm<'_>],
+    expr: &Expr<'_>,
+    els: Option<&Expr<'_>>,
+) {
+    if is_wild(arms[1].pat) {
+        report_single_pattern(cx, ex, arms, expr, els);
+    }
+}
+
+fn report_single_pattern(
+    cx: &LateContext<'_>,
+    ex: &Expr<'_>,
+    arms: &[Arm<'_>],
+    expr: &Expr<'_>,
+    els: Option<&Expr<'_>>,
+) {
+    let lint = if els.is_some() { SINGLE_MATCH_ELSE } else { SINGLE_MATCH };
+    let els_str = els.map_or(String::new(), |els| {
+        format!(" else {}", expr_block(cx, els, None, "..", Some(expr.span)))
+    });
+
+    let (pat, pat_ref_count) = peel_hir_pat_refs(arms[0].pat);
+    let (msg, sugg) = if_chain! {
+        if let PatKind::Path(_) | PatKind::Lit(_) = pat.kind;
+        let (ty, ty_ref_count) = peel_mid_ty_refs(cx.typeck_results().expr_ty(ex));
+        if let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait();
+        if let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait();
+        if ty.is_integral() || ty.is_char() || ty.is_str()
+            || (implements_trait(cx, ty, spe_trait_id, &[])
+                && implements_trait(cx, ty, pe_trait_id, &[ty.into()]));
+        then {
+            // scrutinee derives PartialEq and the pattern is a constant.
+            let pat_ref_count = match pat.kind {
+                // string literals are already a reference.
+                PatKind::Lit(Expr { kind: ExprKind::Lit(lit), .. }) if lit.node.is_str() => pat_ref_count + 1,
+                _ => pat_ref_count,
+            };
+            // References are only implicitly added to the pattern, so no overflow here.
+            // e.g. will work: match &Some(_) { Some(_) => () }
+            // will not: match Some(_) { &Some(_) => () }
+            let ref_count_diff = ty_ref_count - pat_ref_count;
+
+            // Try to remove address of expressions first.
+            let (ex, removed) = peel_n_hir_expr_refs(ex, ref_count_diff);
+            let ref_count_diff = ref_count_diff - removed;
+
+            let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
+            let sugg = format!(
+                "if {} == {}{} {}{}",
+                snippet(cx, ex.span, ".."),
+                // PartialEq for different reference counts may not exist.
+                "&".repeat(ref_count_diff),
+                snippet(cx, arms[0].pat.span, ".."),
+                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
+                els_str,
+            );
+            (msg, sugg)
+        } else {
+            let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
+            let sugg = format!(
+                "if let {} = {} {}{}",
+                snippet(cx, arms[0].pat.span, ".."),
+                snippet(cx, ex.span, ".."),
+                expr_block(cx, arms[0].body, None, "..", Some(expr.span)),
+                els_str,
+            );
+            (msg, sugg)
+        }
+    };
+
+    span_lint_and_sugg(
+        cx,
+        lint,
+        expr.span,
+        msg,
+        "try this",
+        sugg,
+        Applicability::HasPlaceholders,
+    );
+}
+
+fn check_opt_like<'a>(
+    cx: &LateContext<'a>,
+    ex: &Expr<'_>,
+    arms: &[Arm<'_>],
+    expr: &Expr<'_>,
+    ty: Ty<'a>,
+    els: Option<&Expr<'_>>,
+) {
+    // list of candidate `Enum`s we know will never get any more members
+    let candidates = &[
+        (&paths::COW, "Borrowed"),
+        (&paths::COW, "Cow::Borrowed"),
+        (&paths::COW, "Cow::Owned"),
+        (&paths::COW, "Owned"),
+        (&paths::OPTION, "None"),
+        (&paths::RESULT, "Err"),
+        (&paths::RESULT, "Ok"),
+    ];
+
+    // We want to suggest to exclude an arm that contains only wildcards or forms the exhaustive
+    // match with the second branch, without enum variants in matches.
+    if !contains_only_wilds(arms[1].pat) && !form_exhaustive_matches(arms[0].pat, arms[1].pat) {
+        return;
+    }
+
+    let mut paths_and_types = Vec::new();
+    if !collect_pat_paths(&mut paths_and_types, cx, arms[1].pat, ty) {
+        return;
+    }
+
+    let in_candidate_enum = |path_info: &(String, Ty<'_>)| -> bool {
+        let (path, ty) = path_info;
+        for &(ty_path, pat_path) in candidates {
+            if path == pat_path && match_type(cx, *ty, ty_path) {
+                return true;
+            }
+        }
+        false
+    };
+    if paths_and_types.iter().all(in_candidate_enum) {
+        report_single_pattern(cx, ex, arms, expr, els);
+    }
+}
+
+/// Collects paths and their types from the given patterns. Returns true if the given pattern could
+/// be simplified, false otherwise.
+fn collect_pat_paths<'a>(acc: &mut Vec<(String, Ty<'a>)>, cx: &LateContext<'a>, pat: &Pat<'_>, ty: Ty<'a>) -> bool {
+    match pat.kind {
+        PatKind::Wild => true,
+        PatKind::Tuple(inner, _) => inner.iter().all(|p| {
+            let p_ty = cx.typeck_results().pat_ty(p);
+            collect_pat_paths(acc, cx, p, p_ty)
+        }),
+        PatKind::TupleStruct(ref path, ..) => {
+            let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
+                s.print_qpath(path, false);
+            });
+            acc.push((path, ty));
+            true
+        },
+        PatKind::Binding(BindingAnnotation::Unannotated, .., ident, None) => {
+            acc.push((ident.to_string(), ty));
+            true
+        },
+        PatKind::Path(ref path) => {
+            let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| {
+                s.print_qpath(path, false);
+            });
+            acc.push((path, ty));
+            true
+        },
+        _ => false,
+    }
+}
+
+/// Returns true if the given arm of pattern matching contains wildcard patterns.
+fn contains_only_wilds(pat: &Pat<'_>) -> bool {
+    match pat.kind {
+        PatKind::Wild => true,
+        PatKind::Tuple(inner, _) | PatKind::TupleStruct(_, inner, ..) => inner.iter().all(contains_only_wilds),
+        _ => false,
+    }
+}
+
+/// Returns true if the given patterns forms only exhaustive matches that don't contain enum
+/// patterns without a wildcard.
+fn form_exhaustive_matches(left: &Pat<'_>, right: &Pat<'_>) -> bool {
+    match (&left.kind, &right.kind) {
+        (PatKind::Wild, _) | (_, PatKind::Wild) => true,
+        (PatKind::Tuple(left_in, left_pos), PatKind::Tuple(right_in, right_pos)) => {
+            // We don't actually know the position and the presence of the `..` (dotdot) operator
+            // in the arms, so we need to evaluate the correct offsets here in order to iterate in
+            // both arms at the same time.
+            let len = max(
+                left_in.len() + {
+                    if left_pos.is_some() { 1 } else { 0 }
+                },
+                right_in.len() + {
+                    if right_pos.is_some() { 1 } else { 0 }
+                },
+            );
+            let mut left_pos = left_pos.unwrap_or(usize::MAX);
+            let mut right_pos = right_pos.unwrap_or(usize::MAX);
+            let mut left_dot_space = 0;
+            let mut right_dot_space = 0;
+            for i in 0..len {
+                let mut found_dotdot = false;
+                if i == left_pos {
+                    left_dot_space += 1;
+                    if left_dot_space < len - left_in.len() {
+                        left_pos += 1;
+                    }
+                    found_dotdot = true;
+                }
+                if i == right_pos {
+                    right_dot_space += 1;
+                    if right_dot_space < len - right_in.len() {
+                        right_pos += 1;
+                    }
+                    found_dotdot = true;
+                }
+                if found_dotdot {
+                    continue;
+                }
+                if !contains_only_wilds(&left_in[i - left_dot_space])
+                    && !contains_only_wilds(&right_in[i - right_dot_space])
+                {
+                    return false;
+                }
+            }
+            true
+        },
+        _ => false,
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs b/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs
new file mode 100644 (file)
index 0000000..459513e
--- /dev/null
@@ -0,0 +1,24 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_wild;
+use rustc_hir::{Arm, PatKind};
+use rustc_lint::LateContext;
+
+use super::WILDCARD_IN_OR_PATTERNS;
+
+pub(crate) fn check(cx: &LateContext<'_>, arms: &[Arm<'_>]) {
+    for arm in arms {
+        if let PatKind::Or(fields) = arm.pat.kind {
+            // look for multiple fields in this arm that contains at least one Wild pattern
+            if fields.len() > 1 && fields.iter().any(is_wild) {
+                span_lint_and_help(
+                    cx,
+                    WILDCARD_IN_OR_PATTERNS,
+                    arm.pat.span,
+                    "wildcard pattern covers any other pattern as it will match anyway",
+                    None,
+                    "consider handling `_` separately",
+                );
+            }
+        }
+    }
+}
index 514c411876551150478608f8f4756d0ecb5074ef..2cf2c5641bf10654e37c51cfb31171ce62bce223 100644 (file)
@@ -1,13 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{method_chain_args, single_segment_path};
+use clippy_utils::{method_chain_args, path_def_id};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_lint::Lint;
-use rustc_middle::ty;
-use rustc_span::sym;
+use rustc_middle::ty::{self, DefIdTree};
 
 /// Wrapper fn for `CHARS_NEXT_CMP` and `CHARS_LAST_CMP` lints.
 pub(super) fn check(
@@ -19,11 +18,9 @@ pub(super) fn check(
 ) -> bool {
     if_chain! {
         if let Some(args) = method_chain_args(info.chain, chain_methods);
-        if let hir::ExprKind::Call(fun, arg_char) = info.other.kind;
-        if arg_char.len() == 1;
-        if let hir::ExprKind::Path(ref qpath) = fun.kind;
-        if let Some(segment) = single_segment_path(qpath);
-        if segment.ident.name == sym::Some;
+        if let hir::ExprKind::Call(fun, [arg_char]) = info.other.kind;
+        if let Some(id) = path_def_id(cx, fun).and_then(|ctor_id| cx.tcx.parent(ctor_id));
+        if Some(id) == cx.tcx.lang_items().option_some_variant();
         then {
             let mut applicability = Applicability::MachineApplicable;
             let self_ty = cx.typeck_results().expr_ty_adjusted(&args[0][0]).peel_refs();
@@ -42,7 +39,7 @@ pub(super) fn check(
                         if info.eq { "" } else { "!" },
                         snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
                         suggest,
-                        snippet_with_applicability(cx, arg_char[0].span, "..", &mut applicability)),
+                        snippet_with_applicability(cx, arg_char.span, "..", &mut applicability)),
                 applicability,
             );
 
index 4275857757fee4552ee56536a9622261a78a86e5..a7c0e43923e139b3cc378b6f54aa19161d396f6e 100644 (file)
@@ -32,7 +32,7 @@ pub(super) fn check<'tcx>(
                         if info.eq { "" } else { "!" },
                         snippet_with_applicability(cx, args[0][0].span, "..", &mut applicability),
                         suggest,
-                        c),
+                        c.escape_default()),
                 applicability,
             );
 
index 6fe69b8f01f9be2670e8bb70b3d10a2a91c523eb..67a585edc2550615aa610d2c958f0a2591582c14 100644 (file)
@@ -30,7 +30,7 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span,
     };
     match inner_ty.kind() {
         // &T where T: Copy
-        ty::Ref(_, ty, _) if is_copy(cx, ty) => {},
+        ty::Ref(_, ty, _) if is_copy(cx, *ty) => {},
         _ => return,
     };
     span_lint_and_sugg(
index d813edab687e87a47fe08b6dc9fa46ecc00b42a0..c3cb02329a11c7c3b944ae1be9de30170de4c80d 100644 (file)
@@ -73,7 +73,7 @@ fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
                     match cx.qpath_res(p, fun.hir_id) {
                         hir::def::Res::Def(hir::def::DefKind::Fn | hir::def::DefKind::AssocFn, def_id) => matches!(
                             cx.tcx.fn_sig(def_id).output().skip_binder().kind(),
-                            ty::Ref(ty::ReStatic, ..)
+                            ty::Ref(re, ..) if re.is_static(),
                         ),
                         _ => false,
                     }
@@ -87,7 +87,7 @@ fn can_be_static_str(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
                     .map_or(false, |method_id| {
                         matches!(
                             cx.tcx.fn_sig(method_id).output().skip_binder().kind(),
-                            ty::Ref(ty::ReStatic, ..)
+                            ty::Ref(re, ..) if re.is_static()
                         )
                     })
             },
index ca33bfc643da84a5d3a669eaa163c6fcd718e2df..b93f1399eaeed8e9c13692355049678cf450cb42 100644 (file)
@@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(
     };
 
     match inner_ty.kind() {
-        ty::Ref(_, ty, _) if !is_copy(cx, ty) => {},
+        ty::Ref(_, ty, _) if !is_copy(cx, *ty) => {},
         _ => return,
     };
 
index 4307cbf00507a1fcb130f83793770af35a4c334d..0fe510beaa07ee8640d48599b3025775744c8e84 100644 (file)
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_qpath_def_path;
 use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{match_def_path, path_def_id};
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_errors::Applicability;
@@ -93,12 +93,12 @@ fn is_min_or_max<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) -> Option<M
     let ty_str = ty.to_string();
 
     // `std::T::MAX` `std::T::MIN` constants
-    if let hir::ExprKind::Path(path) = &expr.kind {
-        if is_qpath_def_path(cx, path, expr.hir_id, &["core", &ty_str, "MAX"][..]) {
+    if let Some(id) = path_def_id(cx, expr) {
+        if match_def_path(cx, id, &["core", &ty_str, "MAX"]) {
             return Some(MinMax::Max);
         }
 
-        if is_qpath_def_path(cx, path, expr.hir_id, &["core", &ty_str, "MIN"][..]) {
+        if match_def_path(cx, id, &["core", &ty_str, "MIN"]) {
             return Some(MinMax::Min);
         }
     }
index d74c910b676717a244a43f1e4255fa0b1d8eadde..68a75667914aa0f8f6ab34c80d408ba3a812741a 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty, TyS};
+use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::sym;
 use std::borrow::Cow;
 
@@ -37,8 +37,8 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
     } else {
         let ty = cx.typeck_results().expr_ty(e);
         if is_type_diagnostic_item(cx, ty, sym::String)
-            || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, TyS::is_str))
-            || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, TyS::is_str))
+            || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, Ty::is_str))
+            || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, Ty::is_str))
         {
             Some(RepeatKind::String)
         } else {
index 80e1eb86e6c6c10aecc7d38f0afbc37b1f405c76..3021a40fae142a03bfd4d3cdea0a83810f1c8387 100644 (file)
     ///
     /// ### Why is this bad?
     /// Readability, this can be written more concisely as
-    /// `_.flat_map(_)`
+    /// `_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option`
     ///
     /// ### Example
     /// ```rust
     /// let vec = vec![vec![1]];
+    /// let opt = Some(5);
     ///
     /// // Bad
     /// vec.iter().map(|x| x.iter()).flatten();
+    /// opt.map(|x| Some(x * 2)).flatten();
     ///
     /// // Good
     /// vec.iter().flat_map(|x| x.iter());
+    /// opt.and_then(|x| Some(x * 2));
     /// ```
     #[clippy::version = "1.31.0"]
     pub MAP_FLATTEN,
@@ -2103,7 +2106,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
             let method_sig = cx.tcx.fn_sig(impl_item.def_id);
             let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
 
-            let first_arg_ty = &method_sig.inputs().iter().next();
+            let first_arg_ty = method_sig.inputs().iter().next();
 
             // check conventions w.r.t. conversion method names and predicates
             if let Some(first_arg_ty) = first_arg_ty;
@@ -2116,7 +2119,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
                         if name == method_config.method_name &&
                             sig.decl.inputs.len() == method_config.param_count &&
                             method_config.output_type.matches(&sig.decl.output) &&
-                            method_config.self_kind.matches(cx, self_ty, first_arg_ty) &&
+                            method_config.self_kind.matches(cx, self_ty, *first_arg_ty) &&
                             fn_header_equals(method_config.fn_header, sig.header) &&
                             method_config.lifetime_param_cond(impl_item)
                         {
@@ -2148,7 +2151,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
                         cx,
                         name,
                         self_ty,
-                        first_arg_ty,
+                        *first_arg_ty,
                         first_arg.pat.span,
                         implements_trait,
                         false
@@ -2399,10 +2402,17 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
                 implicit_clone::check(cx, name, expr, recv);
             },
-            ("unwrap", []) => match method_call(recv) {
-                Some(("get", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, false),
-                Some(("get_mut", [recv, get_arg], _)) => get_unwrap::check(cx, expr, recv, get_arg, true),
-                _ => unwrap_used::check(cx, expr, recv),
+            ("unwrap", []) => {
+                match method_call(recv) {
+                    Some(("get", [recv, get_arg], _)) => {
+                        get_unwrap::check(cx, expr, recv, get_arg, false);
+                    },
+                    Some(("get_mut", [recv, get_arg], _)) => {
+                        get_unwrap::check(cx, expr, recv, get_arg, true);
+                    },
+                    _ => {},
+                }
+                unwrap_used::check(cx, expr, recv);
             },
             ("unwrap_or", [u_arg]) => match method_call(recv) {
                 Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
index 5e5c1038e829e76ddfe9a7007f19ca54328f9412..bdf8cea120739f63b1092dc88cafc352cfb0f741 100644 (file)
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_lang_ctor, single_segment_path};
+use clippy_utils::{is_lang_ctor, path_def_id};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_lint::LateContext;
+use rustc_middle::ty::DefIdTree;
 use rustc_span::symbol::sym;
 
 use super::OPTION_MAP_OR_NONE;
@@ -76,13 +77,11 @@ pub(super) fn check<'tcx>(
         if let hir::ExprKind::Closure(_, _, id, span, _) = map_arg.kind;
             let arg_snippet = snippet(cx, span, "..");
             let body = cx.tcx.hir().body(id);
-                if let Some((func, arg_char)) = reduce_unit_expression(cx, &body.value);
-                if arg_char.len() == 1;
-                if let hir::ExprKind::Path(ref qpath) = func.kind;
-                if let Some(segment) = single_segment_path(qpath);
-                if segment.ident.name == sym::Some;
+                if let Some((func, [arg_char])) = reduce_unit_expression(cx, &body.value);
+                if let Some(id) = path_def_id(cx, func).and_then(|ctor_id| cx.tcx.parent(ctor_id));
+                if Some(id) == cx.tcx.lang_items().option_some_variant();
                 then {
-                    let func_snippet = snippet(cx, arg_char[0].span, "..");
+                    let func_snippet = snippet(cx, arg_char.span, "..");
                     let msg = "called `map_or(None, ..)` on an `Option` value. This can be done more directly by calling \
                        `map(..)` instead";
                     return span_lint_and_sugg(
index 9c6f421103185c7f02437bc63372256642fa3111..6c641af59f92b9c6a3f1b6941c01305f8b8bd464 100644 (file)
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::differing_macro_contexts;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_copy;
 use clippy_utils::ty::is_type_diagnostic_item;
@@ -48,7 +47,7 @@ pub(super) fn check<'tcx>(
             }
         }
 
-        if differing_macro_contexts(unwrap_arg.span, map_span) {
+        if unwrap_arg.span.ctxt() != map_span.ctxt() {
             return;
         }
 
index b2f624ed480e4cc903fcbebc08722105a9449037..926c25b4b40a5c7aa2bd7c5003384ed5951fa857 100644 (file)
@@ -45,16 +45,16 @@ pub(super) fn check_manual_split_once(
         IterUsageKind::Next | IterUsageKind::Second => {
             let self_deref = {
                 let adjust = cx.typeck_results().expr_adjustments(self_arg);
-                if adjust.is_empty() {
+                if adjust.len() < 2 {
                     String::new()
                 } else if cx.typeck_results().expr_ty(self_arg).is_box()
                     || adjust
                         .iter()
                         .any(|a| matches!(a.kind, Adjust::Deref(Some(_))) || a.target.is_box())
                 {
-                    format!("&{}", "*".repeat(adjust.len() - 1))
+                    format!("&{}", "*".repeat(adjust.len().saturating_sub(1)))
                 } else {
-                    "*".repeat(adjust.len() - 2)
+                    "*".repeat(adjust.len().saturating_sub(2))
                 }
             };
             if matches!(usage.kind, IterUsageKind::Next) {
index ccfce31713f93469b7e620b8b65770abc1e2ad9f..12ad3d8d69038d3016ebf021f0fa7895603fa749 100644 (file)
@@ -33,9 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, arg: &hir::Expr<
         } else if !found_mapping && !mutates_arg {
             let in_ty = cx.typeck_results().node_type(body.params[0].hir_id);
             match cx.typeck_results().expr_ty(&body.value).kind() {
-                ty::Adt(adt, subst)
-                    if cx.tcx.is_diagnostic_item(sym::Option, adt.did) && in_ty == subst.type_at(0) =>
-                {
+                ty::Adt(adt, subst) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) && in_ty == subst.type_at(0) => {
                     "filter"
                 },
                 _ => return,
index b67bfb6597b0489d243987669f3fab4600390e0c..7916fb8e3b45ca2739f6efc35a6c079bfd864ed7 100644 (file)
@@ -105,7 +105,7 @@ fn check_addr_of_expr(
         if is_copy(cx, receiver_ty) || is_cow_into_owned(cx, method_name, method_def_id);
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
-            let (target_ty, n_target_refs) = peel_mid_ty_refs(target_ty);
+            let (target_ty, n_target_refs) = peel_mid_ty_refs(*target_ty);
             let (receiver_ty, n_receiver_refs) = peel_mid_ty_refs(receiver_ty);
             if receiver_ty == target_ty && n_target_refs >= n_receiver_refs {
                 span_lint_and_sugg(
@@ -228,7 +228,7 @@ fn check_other_call_arg<'tcx>(
         let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
         if let Some(i) = call_args.iter().position(|arg| arg.hir_id == maybe_arg.hir_id);
         if let Some(input) = fn_sig.inputs().get(i);
-        let (input, n_refs) = peel_mid_ty_refs(input);
+        let (input, n_refs) = peel_mid_ty_refs(*input);
         if let (trait_predicates, projection_predicates) = get_input_traits_and_projections(cx, callee_def_id, input);
         if let Some(sized_def_id) = cx.tcx.lang_items().sized_trait();
         if let [trait_predicate] = trait_predicates
index c4cf994aacaa9f8aba2d595ed50a4aa2e5b3dbca..63c3273bd6816c1e27e237f5a31854967ad7920e 100644 (file)
@@ -19,7 +19,7 @@ fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
             ty::Adt(def, _) if def.is_box() => may_slice(cx, ty.boxed_ty()),
             ty::Adt(..) => is_type_diagnostic_item(cx, ty, sym::Vec),
             ty::Array(_, size) => size.try_eval_usize(cx.tcx, cx.param_env).is_some(),
-            ty::Ref(_, inner, _) => may_slice(cx, inner),
+            ty::Ref(_, inner, _) => may_slice(cx, *inner),
             _ => false,
         }
     }
@@ -35,7 +35,7 @@ fn may_slice<'a>(cx: &LateContext<'a>, ty: Ty<'a>) -> bool {
             ty::Slice(_) => Some(expr),
             ty::Adt(def, _) if def.is_box() && may_slice(cx, ty.boxed_ty()) => Some(expr),
             ty::Ref(_, inner, _) => {
-                if may_slice(cx, inner) {
+                if may_slice(cx, *inner) {
                     Some(expr)
                 } else {
                     None
index a2e09e5ecec1f3334766d163236dfac3b1a01524..aecfea9c141cfad801b75fedc45472f76d0be272 100644 (file)
@@ -2,7 +2,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::is_copy;
 use rustc_lint::LateContext;
-use rustc_middle::ty::TyS;
+use rustc_middle::ty::Ty;
 use rustc_span::source_map::Span;
 use std::fmt;
 
@@ -41,7 +41,7 @@ impl Convention {
     fn check<'tcx>(
         &self,
         cx: &LateContext<'tcx>,
-        self_ty: &'tcx TyS<'tcx>,
+        self_ty: Ty<'tcx>,
         other: &str,
         implements_trait: bool,
         is_trait_item: bool,
@@ -84,8 +84,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     item_name: &str,
-    self_ty: &'tcx TyS<'tcx>,
-    first_arg_ty: &'tcx TyS<'tcx>,
+    self_ty: Ty<'tcx>,
+    first_arg_ty: Ty<'tcx>,
     first_arg_span: Span,
     implements_trait: bool,
     is_trait_item: bool,
index 866cf616679c29a0d5adf02572ca971f43fbb41d..e9f268da691565c926ce31e9ab98ce5486a5ed08 100644 (file)
@@ -9,7 +9,7 @@
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if_chain! {
         if let ty::RawPtr(ty::TypeAndMut { ty, .. }) = cx.typeck_results().expr_ty(recv).kind();
-        if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
+        if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(*ty));
         if layout.is_zst();
         then {
             span_lint(cx, ZST_OFFSET, expr.span, "offset calculation on zero-sized value");
index 3918bdbdf4387cc7e5bc926df8d5519bfdd684b8..ac82dd306a52879d1d96976dac46938d06abd974 100644 (file)
@@ -20,8 +20,8 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    expr_path_res, get_item_name, get_parent_expr, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats,
-    last_path_segment, match_any_def_paths, paths, unsext, SpanlessEq,
+    get_item_name, get_parent_expr, in_constant, is_diag_trait_item, is_integer_const, iter_input_pats,
+    last_path_segment, match_any_def_paths, path_def_id, paths, unsext, SpanlessEq,
 };
 
 declare_clippy_lint! {
@@ -583,8 +583,7 @@ fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'t
             )
         },
         ExprKind::Call(path, [arg]) => {
-            if expr_path_res(cx, path)
-                .opt_def_id()
+            if path_def_id(cx, path)
                 .and_then(|id| match_any_def_paths(cx, id, &[&paths::FROM_STR_METHOD, &paths::FROM_FROM]))
                 .is_some()
             {
index 566e15ab2a6d640aff7e55090733d58c4313762b..3d0a23822838e871c3c6ef5f891aa4303505b7d3 100644 (file)
@@ -58,7 +58,7 @@ pub fn new(conf_renames: Vec<Rename>) -> Self {
 impl LateLintPass<'_> for ImportRename {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
         for Rename { path, rename } in &self.conf_renames {
-            if let Res::Def(_, id) = clippy_utils::path_to_res(cx, &path.split("::").collect::<Vec<_>>()) {
+            if let Res::Def(_, id) = clippy_utils::def_path_res(cx, &path.split("::").collect::<Vec<_>>()) {
                 self.renames.insert(id, Symbol::intern(rename));
             }
         }
index d182a7d52497d45fd59cf8d367f8e84e207d3e10..195b2e5c2ee0a0ff722e1f39bbccadc1ed649b17 100644 (file)
@@ -4,7 +4,7 @@
 use if_chain::if_chain;
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use std::fmt::Display;
 
@@ -77,7 +77,7 @@ fn floating_point_operand_info<T: Display + PartialOrd + From<f32>>(f: &T) -> Op
     }
 }
 
-fn might_have_negative_value(t: &ty::TyS<'_>) -> bool {
+fn might_have_negative_value(t: Ty<'_>) -> bool {
     t.is_signed() || t.is_floating_point()
 }
 
index 1bdd805f658549801dec79a6bfd63d1d14e6e66f..b4e29101b396185c2f70cf6e7f71d18e3d8550fb 100644 (file)
@@ -113,7 +113,7 @@ fn check_sig<'tcx>(cx: &LateContext<'tcx>, item_hir_id: hir::HirId, decl: &hir::
     let fn_def_id = cx.tcx.hir().local_def_id(item_hir_id);
     let fn_sig = cx.tcx.fn_sig(fn_def_id);
     for (hir_ty, ty) in iter::zip(decl.inputs, fn_sig.inputs().skip_binder()) {
-        check_ty(cx, hir_ty.span, ty);
+        check_ty(cx, hir_ty.span, *ty);
     }
     check_ty(cx, decl.output.span(), cx.tcx.erase_late_bound_regions(fn_sig.output()));
 }
index 7871be41d62946b94dbf2cb3c43a731f6be555b4..b7f981faa2d42c6491d8745fc9b76168bd4a2fe6 100644 (file)
@@ -53,7 +53,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, ex: &'tcx Expr<'tcx>) {
             if path.ident.name == sym!(lock);
             let ty = cx.typeck_results().expr_ty(self_arg);
             if let ty::Ref(_, inner_ty, Mutability::Mut) = ty.kind();
-            if is_type_diagnostic_item(cx, inner_ty, sym::Mutex);
+            if is_type_diagnostic_item(cx, *inner_ty, sym::Mutex);
             then {
                 span_lint_and_sugg(
                     cx,
index 21ac6548b0179cafa486608e4f7153d04e137080..3ba99403f06d005645138f6511fd9e1c3d5418e9 100644 (file)
@@ -136,14 +136,14 @@ fn is_value_unfrozen_raw<'tcx>(
     result: Result<ConstValue<'tcx>, ErrorHandled>,
     ty: Ty<'tcx>,
 ) -> bool {
-    fn inner<'tcx>(cx: &LateContext<'tcx>, val: &'tcx Const<'tcx>) -> bool {
-        match val.ty.kind() {
+    fn inner<'tcx>(cx: &LateContext<'tcx>, val: Const<'tcx>) -> bool {
+        match val.ty().kind() {
             // the fact that we have to dig into every structs to search enums
             // leads us to the point checking `UnsafeCell` directly is the only option.
             ty::Adt(ty_def, ..) if Some(ty_def.did) == cx.tcx.lang_items().unsafe_cell_type() => true,
             ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => {
                 let val = cx.tcx.destructure_const(cx.param_env.and(val));
-                val.fields.iter().any(|field| inner(cx, field))
+                val.fields.iter().any(|field| inner(cx, *field))
             },
             _ => false,
         }
index ab1559c85d8b1f431946778eeb03991ffa925aa9..f4de999a9281a3391149ac7fbf1842f9dd45eb09 100644 (file)
@@ -205,7 +205,7 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
         ty::Tuple(_) => ty
             .tuple_fields()
             .all(|ty| ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait)),
-        ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, ty, send_trait),
+        ty::Array(ty, _) | ty::Slice(ty) => ty_allowed_with_raw_pointer_heuristic(cx, *ty, send_trait),
         ty::Adt(_, substs) => {
             if contains_pointer_like(cx, ty) {
                 // descends only if ADT contains any raw pointers
index 3092ab8392a7231b99e23e74f71764ce88c21b1e..d59249d7f13d32343bcb237ae44bb5afd860e0a1 100644 (file)
@@ -167,8 +167,8 @@ fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &F
 
                     if_chain! {
                         if !output_lts.contains(input_lt);
-                        if is_copy(cx, ty);
-                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
+                        if is_copy(cx, *ty);
+                        if let Some(size) = cx.layout_of(*ty).ok().map(|l| l.size.bytes());
                         if size <= self.ref_min_size;
                         if let hir::TyKind::Rptr(_, MutTy { ty: decl_ty, .. }) = input.kind;
                         then {
index b5d65542de0bf1c068279149bb67df8615006a81..e0ce1b7db003afb96091e912a701d1e0ab2f7a84 100644 (file)
@@ -3,9 +3,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::expr_sig;
-use clippy_utils::{
-    expr_path_res, get_expr_use_or_unification_node, is_lint_allowed, match_any_diagnostic_items, path_to_local, paths,
-};
+use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
@@ -153,7 +151,9 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
                 cx.tcx.fn_sig(item.def_id).skip_binder().inputs(),
                 sig.decl.inputs,
                 &[],
-            ) {
+            )
+            .filter(|arg| arg.mutability() == Mutability::Not)
+            {
                 span_lint_and_sugg(
                     cx,
                     PTR_ARG,
@@ -170,10 +170,10 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
     fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
         let hir = cx.tcx.hir();
         let mut parents = hir.parent_iter(body.value.hir_id);
-        let (item_id, decl) = match parents.next() {
+        let (item_id, decl, is_trait_item) = match parents.next() {
             Some((_, Node::Item(i))) => {
                 if let ItemKind::Fn(sig, ..) = &i.kind {
-                    (i.def_id, sig.decl)
+                    (i.def_id, sig.decl, false)
                 } else {
                     return;
                 }
@@ -185,14 +185,14 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
                     return;
                 }
                 if let ImplItemKind::Fn(sig, _) = &i.kind {
-                    (i.def_id, sig.decl)
+                    (i.def_id, sig.decl, false)
                 } else {
                     return;
                 }
             },
             Some((_, Node::TraitItem(i))) => {
                 if let TraitItemKind::Fn(sig, _) = &i.kind {
-                    (i.def_id, sig.decl)
+                    (i.def_id, sig.decl, true)
                 } else {
                     return;
                 }
@@ -202,7 +202,9 @@ fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
 
         check_mut_from_ref(cx, decl);
         let sig = cx.tcx.fn_sig(item_id).skip_binder();
-        let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params).collect();
+        let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params)
+            .filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not)
+            .collect();
         let results = check_ptr_arg_usage(cx, body, &lint_args);
 
         for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) {
@@ -318,6 +320,10 @@ fn build_msg(&self) -> String {
             self.deref_ty.argless_str(),
         )
     }
+
+    fn mutability(&self) -> Mutability {
+        self.ref_prefix.mutability
+    }
 }
 
 struct RefPrefix {
@@ -641,7 +647,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                     },
                     _ => {
                         skip_count += 1;
-                        results[arg.idx].skip = true;
+                        results[i].skip = true;
                         None
                     },
                 }
@@ -665,8 +671,8 @@ fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutabil
 
 fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     if let ExprKind::Call(pathexp, []) = expr.kind {
-        expr_path_res(cx, pathexp).opt_def_id().map_or(false, |id| {
-            match_any_diagnostic_items(cx, id, &[sym::ptr_null, sym::ptr_null_mut]).is_some()
+        path_def_id(cx, pathexp).map_or(false, |id| {
+            matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut))
         })
     } else {
         false
index 027ab70014fc0c2ca51ced2aa25f329cfcb87028..be7610f365c5be716dc68aaf25de986b0a99f651 100644 (file)
@@ -2,19 +2,18 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, single_segment_path};
+use clippy_utils::{get_parent_expr, in_constant, is_integer_const, meets_msrv, msrvs, path_to_local};
 use clippy_utils::{higher, SpanlessEq};
 use if_chain::if_chain;
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath};
+use rustc_hir::{BinOpKind, Expr, ExprKind, HirId, PathSegment, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{Span, Spanned};
 use rustc_span::sym;
-use rustc_span::symbol::Ident;
 use std::cmp::Ordering;
 
 declare_clippy_lint! {
@@ -220,12 +219,12 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
         _ => return,
     };
     // value, name, order (higher/lower), inclusiveness
-    if let (Some((lval, lname, name_span, lval_span, lord, linc)), Some((rval, rname, _, rval_span, rord, rinc))) =
+    if let (Some((lval, lid, name_span, lval_span, lord, linc)), Some((rval, rid, _, rval_span, rord, rinc))) =
         (check_range_bounds(cx, l), check_range_bounds(cx, r))
     {
         // we only lint comparisons on the same name and with different
         // direction
-        if lname != rname || lord == rord {
+        if lid != rid || lord == rord {
             return;
         }
         let ord = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(l), &lval, &rval);
@@ -293,7 +292,7 @@ fn check_possible_range_contains(cx: &LateContext<'_>, op: BinOpKind, l: &Expr<'
     }
 }
 
-fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, Ident, Span, Span, Ordering, bool)> {
+fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant, HirId, Span, Span, Ordering, bool)> {
     if let ExprKind::Binary(ref op, l, r) = ex.kind {
         let (inclusive, ordering) = match op.node {
             BinOpKind::Gt => (false, Ordering::Greater),
@@ -302,11 +301,11 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant,
             BinOpKind::Le => (true, Ordering::Less),
             _ => return None,
         };
-        if let Some(id) = match_ident(l) {
+        if let Some(id) = path_to_local(l) {
             if let Some((c, _)) = constant(cx, cx.typeck_results(), r) {
                 return Some((c, id, l.span, r.span, ordering, inclusive));
             }
-        } else if let Some(id) = match_ident(r) {
+        } else if let Some(id) = path_to_local(r) {
             if let Some((c, _)) = constant(cx, cx.typeck_results(), l) {
                 return Some((c, id, r.span, l.span, ordering.reverse(), inclusive));
             }
@@ -315,17 +314,6 @@ fn check_range_bounds(cx: &LateContext<'_>, ex: &Expr<'_>) -> Option<(Constant,
     None
 }
 
-fn match_ident(e: &Expr<'_>) -> Option<Ident> {
-    if let ExprKind::Path(ref qpath) = e.kind {
-        if let Some(seg) = single_segment_path(qpath) {
-            if seg.args.is_none() {
-                return Some(seg.ident);
-            }
-        }
-    }
-    None
-}
-
 fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: &[Expr<'_>], span: Span) {
     if_chain! {
         if path.ident.as_str() == "zip";
index 971729e5c54b35d2bc05866d567fb08954247062..f3515ea3c2dde19addc39a4519dbbcc8990b5833 100644 (file)
@@ -116,7 +116,7 @@ fn get_pointee_ty_and_count_expr<'tcx>(
         if let ty::RawPtr(TypeAndMut { ty: pointee_ty, .. }) =
             cx.typeck_results().expr_ty(ptr_self).kind();
         then {
-            return Some((pointee_ty, count));
+            return Some((*pointee_ty, count));
         }
     };
     None
index 4c10b12437d7b5e3465c5e520529b626f5fc8a3a..1885f3ca414dfe9dbef2a600fc961cf4f6b9ebb5 100644 (file)
@@ -2,7 +2,7 @@
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{can_mut_borrow_both, differing_macro_contexts, eq_expr_value, std_or_core};
+use clippy_utils::{can_mut_borrow_both, eq_expr_value, std_or_core};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind};
@@ -172,7 +172,7 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
         if_chain! {
             if let StmtKind::Semi(first) = w[0].kind;
             if let StmtKind::Semi(second) = w[1].kind;
-            if !differing_macro_contexts(first.span, second.span);
+            if first.span.ctxt() == second.span.ctxt();
             if let ExprKind::Assign(lhs0, rhs0, _) = first.kind;
             if let ExprKind::Assign(lhs1, rhs1, _) = second.kind;
             if eq_expr_value(cx, lhs0, rhs1);
index 5257f5302cd90d87c2ced61cd1f582cb2b4d1dd7..bca95b7f25638449b03f0c13d68c1d2a41d250f6 100644 (file)
@@ -98,7 +98,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tc
                 if let WherePredicate::BoundPredicate(ref bound_predicate) = predicate;
                 if !bound_predicate.span.from_expansion();
                 if let TyKind::Path(QPath::Resolved(_, Path { segments, .. })) = bound_predicate.bounded_ty.kind;
-                if let Some(PathSegment { res: Some(Res::SelfTy(Some(def_id), _)), .. }) = segments.first();
+                if let Some(PathSegment { res: Some(Res::SelfTy{ trait_: Some(def_id), alias_to: _ }), .. }) = segments.first();
 
                 if let Some(
                     Node::Item(
index 3ad4ec74bf51c1bdde228e00f451c3685fa92e31..5e94ab6d04820afe307d36b4915ec11617e2aff6 100644 (file)
@@ -7,6 +7,7 @@
 mod transmute_ptr_to_ptr;
 mod transmute_ptr_to_ref;
 mod transmute_ref_to_ref;
+mod transmute_undefined_repr;
 mod transmutes_expressible_as_ptr_casts;
 mod unsound_collection_transmute;
 mod useless_transmute;
     "transmute between collections of layout-incompatible types"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for transmutes either to or from a type which does not have a defined representation.
+    ///
+    /// ### Why is this bad?
+    /// The results of such a transmute are not defined.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct Foo<T>(u32, T);
+    /// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// #[repr(C)]
+    /// struct Foo<T>(u32, T);
+    /// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub TRANSMUTE_UNDEFINED_REPR,
+    nursery,
+    "transmute to or from a type with an undefined representation"
+}
+
 declare_lint_pass!(Transmute => [
     CROSSPOINTER_TRANSMUTE,
     TRANSMUTE_PTR_TO_REF,
     TRANSMUTE_NUM_TO_BYTES,
     UNSOUND_COLLECTION_TRANSMUTE,
     TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS,
+    TRANSMUTE_UNDEFINED_REPR,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Transmute {
-    #[allow(clippy::similar_names, clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::Call(path_expr, args) = e.kind;
+            if let ExprKind::Call(path_expr, [arg]) = e.kind;
             if let ExprKind::Path(ref qpath) = path_expr.kind;
             if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id();
             if cx.tcx.is_diagnostic_item(sym::transmute, def_id);
@@ -385,28 +410,31 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
                 // And see https://github.com/rust-lang/rust/issues/51911 for dereferencing raw pointers.
                 let const_context = in_constant(cx, e.hir_id);
 
-                let from_ty = cx.typeck_results().expr_ty(&args[0]);
+                let from_ty = cx.typeck_results().expr_ty(arg);
                 let to_ty = cx.typeck_results().expr_ty(e);
 
                 // If useless_transmute is triggered, the other lints can be skipped.
-                if useless_transmute::check(cx, e, from_ty, to_ty, args) {
+                if useless_transmute::check(cx, e, from_ty, to_ty, arg) {
                     return;
                 }
 
-                let mut linted = wrong_transmute::check(cx, e, from_ty, to_ty);
-                linted |= crosspointer_transmute::check(cx, e, from_ty, to_ty);
-                linted |= transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, args, qpath);
-                linted |= transmute_int_to_char::check(cx, e, from_ty, to_ty, args);
-                linted |= transmute_ref_to_ref::check(cx, e, from_ty, to_ty, args, const_context);
-                linted |= transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, args);
-                linted |= transmute_int_to_bool::check(cx, e, from_ty, to_ty, args);
-                linted |= transmute_int_to_float::check(cx, e, from_ty, to_ty, args, const_context);
-                linted |= transmute_float_to_int::check(cx, e, from_ty, to_ty, args, const_context);
-                linted |= transmute_num_to_bytes::check(cx, e, from_ty, to_ty, args, const_context);
-                linted |= unsound_collection_transmute::check(cx, e, from_ty, to_ty);
+                let linted = wrong_transmute::check(cx, e, from_ty, to_ty)
+                    | crosspointer_transmute::check(cx, e, from_ty, to_ty)
+                    | transmute_ptr_to_ref::check(cx, e, from_ty, to_ty, arg, qpath)
+                    | transmute_int_to_char::check(cx, e, from_ty, to_ty, arg)
+                    | transmute_ref_to_ref::check(cx, e, from_ty, to_ty, arg, const_context)
+                    | transmute_ptr_to_ptr::check(cx, e, from_ty, to_ty, arg)
+                    | transmute_int_to_bool::check(cx, e, from_ty, to_ty, arg)
+                    | transmute_int_to_float::check(cx, e, from_ty, to_ty, arg, const_context)
+                    | transmute_float_to_int::check(cx, e, from_ty, to_ty, arg, const_context)
+                    | transmute_num_to_bytes::check(cx, e, from_ty, to_ty, arg, const_context)
+                    | (
+                        unsound_collection_transmute::check(cx, e, from_ty, to_ty)
+                        || transmute_undefined_repr::check(cx, e, from_ty, to_ty)
+                    );
 
                 if !linted {
-                    transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, args);
+                    transmutes_expressible_as_ptr_casts::check(cx, e, from_ty, to_ty, arg);
                 }
             }
         }
index 3aa3c393ba57cce3a8d26a402683405ba607f099..d5ef86dc4e572703af49941486832c5c9bea462e 100644 (file)
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(
     e: &'tcx Expr<'_>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
-    args: &'tcx [Expr<'_>],
+    mut arg: &'tcx Expr<'_>,
     const_context: bool,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
@@ -26,37 +26,36 @@ pub(super) fn check<'tcx>(
                 e.span,
                 &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
                 |diag| {
-                    let mut expr = &args[0];
-                    let mut arg = sugg::Sugg::hir(cx, expr, "..");
+                    let mut sugg = sugg::Sugg::hir(cx, arg, "..");
 
-                    if let ExprKind::Unary(UnOp::Neg, inner_expr) = &expr.kind {
-                        expr = inner_expr;
+                    if let ExprKind::Unary(UnOp::Neg, inner_expr) = &arg.kind {
+                        arg = inner_expr;
                     }
 
                     if_chain! {
                         // if the expression is a float literal and it is unsuffixed then
                         // add a suffix so the suggestion is valid and unambiguous
-                        if let ExprKind::Lit(lit) = &expr.kind;
+                        if let ExprKind::Lit(lit) = &arg.kind;
                         if let ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) = lit.node;
                         then {
-                            let op = format!("{}{}", arg, float_ty.name_str()).into();
-                            match arg {
-                                sugg::Sugg::MaybeParen(_) => arg = sugg::Sugg::MaybeParen(op),
-                                _ => arg = sugg::Sugg::NonParen(op)
+                            let op = format!("{}{}", sugg, float_ty.name_str()).into();
+                            match sugg {
+                                sugg::Sugg::MaybeParen(_) => sugg = sugg::Sugg::MaybeParen(op),
+                                _ => sugg = sugg::Sugg::NonParen(op)
                             }
                         }
                     }
 
-                    arg = sugg::Sugg::NonParen(format!("{}.to_bits()", arg.maybe_par()).into());
+                    sugg = sugg::Sugg::NonParen(format!("{}.to_bits()", sugg.maybe_par()).into());
 
                     // cast the result of `to_bits` if `to_ty` is signed
-                    arg = if let ty::Int(int_ty) = to_ty.kind() {
-                        arg.as_ty(int_ty.name_str().to_string())
+                    sugg = if let ty::Int(int_ty) = to_ty.kind() {
+                        sugg.as_ty(int_ty.name_str().to_string())
                     } else {
-                        arg
+                        sugg
                     };
 
-                    diag.span_suggestion(e.span, "consider using", arg.to_string(), Applicability::Unspecified);
+                    diag.span_suggestion(e.span, "consider using", sugg.to_string(), Applicability::Unspecified);
                 },
             );
             true
index cc0a5643e2a7d35295de3f9eff785371fdbc1ad7..8c50b58ca4b862af20360774f2a4654df4fa1085 100644 (file)
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(
     e: &'tcx Expr<'_>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
-    args: &'tcx [Expr<'_>],
+    arg: &'tcx Expr<'_>,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
         (ty::Int(ty::IntTy::I8) | ty::Uint(ty::UintTy::U8), ty::Bool) => {
@@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(
                 e.span,
                 &format!("transmute from a `{}` to a `bool`", from_ty),
                 |diag| {
-                    let arg = sugg::Sugg::hir(cx, &args[0], "..");
+                    let arg = sugg::Sugg::hir(cx, arg, "..");
                     let zero = sugg::Sugg::NonParen(Cow::from("0"));
                     diag.span_suggestion(
                         e.span,
index e83d2e06b9a8d26800e7b0a65b6f02e2b42221c8..3eb07b68992a89b96ff10c4a40277023c8878536 100644 (file)
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(
     e: &'tcx Expr<'_>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
-    args: &'tcx [Expr<'_>],
+    arg: &'tcx Expr<'_>,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
         (ty::Int(ty::IntTy::I32) | ty::Uint(ty::UintTy::U32), &ty::Char) => {
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
                 e.span,
                 &format!("transmute from a `{}` to a `char`", from_ty),
                 |diag| {
-                    let arg = sugg::Sugg::hir(cx, &args[0], "..");
+                    let arg = sugg::Sugg::hir(cx, arg, "..");
                     let arg = if let ty::Int(_) = from_ty.kind() {
                         arg.as_ty(ast::UintTy::U32.name_str())
                     } else {
index 05eee380d6f409bdf275384d089a16b4334abf80..b8703052e6c869750a09751579885123c0e1143a 100644 (file)
@@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(
     e: &'tcx Expr<'_>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
-    args: &'tcx [Expr<'_>],
+    arg: &'tcx Expr<'_>,
     const_context: bool,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(
                 e.span,
                 &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
                 |diag| {
-                    let arg = sugg::Sugg::hir(cx, &args[0], "..");
+                    let arg = sugg::Sugg::hir(cx, arg, "..");
                     let arg = if let ty::Int(int_ty) = from_ty.kind() {
                         arg.as_ty(format!(
                             "u{}",
index 5ba58a764940191728d0266f5c77b2e2cc113ef2..52d193d11e1a08dab87adca2de3548d904b3d16f 100644 (file)
@@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(
     e: &'tcx Expr<'_>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
-    args: &'tcx [Expr<'_>],
+    arg: &'tcx Expr<'_>,
     const_context: bool,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
@@ -33,7 +33,7 @@ pub(super) fn check<'tcx>(
                 e.span,
                 &format!("transmute from a `{}` to a `{}`", from_ty, to_ty),
                 |diag| {
-                    let arg = sugg::Sugg::hir(cx, &args[0], "..");
+                    let arg = sugg::Sugg::hir(cx, arg, "..");
                     diag.span_suggestion(
                         e.span,
                         "consider using `to_ne_bytes()`",
index 7b646bfc0c6d13e0bb544d4aef8fede6beb8f0cb..d712b33de9e1a49ead17804603354e5d09055bcd 100644 (file)
@@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(
     e: &'tcx Expr<'_>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
-    args: &'tcx [Expr<'_>],
+    arg: &'tcx Expr<'_>,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
         (ty::RawPtr(_), ty::RawPtr(to_ty)) => {
@@ -23,7 +23,7 @@ pub(super) fn check<'tcx>(
                 e.span,
                 "transmute from a pointer to a pointer",
                 |diag| {
-                    if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
+                    if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
                         let sugg = arg.as_ty(cx.tcx.mk_ptr(*to_ty));
                         diag.span_suggestion(e.span, "try", sugg.to_string(), Applicability::Unspecified);
                     }
index f14eef936453114abb3b4814fafe2cfe09c95826..f3653199b3758b2ecf4d68ef22832da4c298e8c6 100644 (file)
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(
     e: &'tcx Expr<'_>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
-    args: &'tcx [Expr<'_>],
+    arg: &'tcx Expr<'_>,
     qpath: &'tcx QPath<'_>,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
@@ -28,7 +28,7 @@ pub(super) fn check<'tcx>(
                     from_ty, to_ty
                 ),
                 |diag| {
-                    let arg = sugg::Sugg::hir(cx, &args[0], "..");
+                    let arg = sugg::Sugg::hir(cx, arg, "..");
                     let (deref, cast) = if *mutbl == Mutability::Mut {
                         ("&mut *", "*mut")
                     } else {
@@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(
                     let arg = if from_ptr_ty.ty == *to_ref_ty {
                         arg
                     } else {
-                        arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, to_ref_ty)))
+                        arg.as_ty(&format!("{} {}", cast, get_type_snippet(cx, qpath, *to_ref_ty)))
                     };
 
                     diag.span_suggestion(
index d105e37abf9c08281553f4298958db2e2f1bc9c6..7570bc2a7a8f0d8195e2f8d560f29f36a06c97b3 100644 (file)
@@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(
     e: &'tcx Expr<'_>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
-    args: &'tcx [Expr<'_>],
+    arg: &'tcx Expr<'_>,
     const_context: bool,
 ) -> bool {
     let mut triggered = false;
@@ -41,7 +41,7 @@ pub(super) fn check<'tcx>(
                     format!(
                         "std::str::from_utf8{}({}).unwrap()",
                         postfix,
-                        snippet(cx, args[0].span, ".."),
+                        snippet(cx, arg.span, ".."),
                     ),
                     Applicability::Unspecified,
                 );
@@ -54,12 +54,12 @@ pub(super) fn check<'tcx>(
                         TRANSMUTE_PTR_TO_PTR,
                         e.span,
                         "transmute from a reference to a reference",
-                        |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
+                        |diag| if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
                             let ty_from_and_mut = ty::TypeAndMut {
-                                ty: ty_from,
+                                ty: *ty_from,
                                 mutbl: *from_mutbl
                             };
-                            let ty_to_and_mut = ty::TypeAndMut { ty: ty_to, mutbl: *to_mutbl };
+                            let ty_to_and_mut = ty::TypeAndMut { ty: *ty_to, mutbl: *to_mutbl };
                             let sugg_paren = arg
                                 .as_ty(cx.tcx.mk_ptr(ty_from_and_mut))
                                 .as_ty(cx.tcx.mk_ptr(ty_to_and_mut));
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
new file mode 100644 (file)
index 0000000..9ed5952
--- /dev/null
@@ -0,0 +1,293 @@
+use super::TRANSMUTE_UNDEFINED_REPR;
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::subst::{GenericArg, Subst};
+use rustc_middle::ty::{self, Ty, TypeAndMut};
+use rustc_span::Span;
+
+#[allow(clippy::too_many_lines)]
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    e: &'tcx Expr<'_>,
+    from_ty_orig: Ty<'tcx>,
+    to_ty_orig: Ty<'tcx>,
+) -> bool {
+    let mut from_ty = cx.tcx.erase_regions(from_ty_orig);
+    let mut to_ty = cx.tcx.erase_regions(to_ty_orig);
+
+    while from_ty != to_ty {
+        match reduce_refs(cx, e.span, from_ty, to_ty) {
+            ReducedTys::FromFatPtr { unsized_ty, .. } => {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
+                    |diag| {
+                        if from_ty_orig.peel_refs() != unsized_ty {
+                            diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
+                        }
+                    },
+                );
+                return true;
+            },
+            ReducedTys::ToFatPtr { unsized_ty, .. } => {
+                span_lint_and_then(
+                    cx,
+                    TRANSMUTE_UNDEFINED_REPR,
+                    e.span,
+                    &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
+                    |diag| {
+                        if to_ty_orig.peel_refs() != unsized_ty {
+                            diag.note(&format!("the contained type `&{}` has an undefined layout", unsized_ty));
+                        }
+                    },
+                );
+                return true;
+            },
+            ReducedTys::ToPtr {
+                from_ty: from_sub_ty,
+                to_ty: to_sub_ty,
+            } => match reduce_ty(cx, from_sub_ty) {
+                ReducedTy::UnorderedFields(from_ty) => {
+                    span_lint_and_then(
+                        cx,
+                        TRANSMUTE_UNDEFINED_REPR,
+                        e.span,
+                        &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
+                        |diag| {
+                            if from_ty_orig.peel_refs() != from_ty {
+                                diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
+                            }
+                        },
+                    );
+                    return true;
+                },
+                ReducedTy::Ref(from_sub_ty) => {
+                    from_ty = from_sub_ty;
+                    to_ty = to_sub_ty;
+                    continue;
+                },
+                _ => break,
+            },
+            ReducedTys::FromPtr {
+                from_ty: from_sub_ty,
+                to_ty: to_sub_ty,
+            } => match reduce_ty(cx, to_sub_ty) {
+                ReducedTy::UnorderedFields(to_ty) => {
+                    span_lint_and_then(
+                        cx,
+                        TRANSMUTE_UNDEFINED_REPR,
+                        e.span,
+                        &format!("transmute to `{}` which has an undefined layout", to_ty_orig),
+                        |diag| {
+                            if to_ty_orig.peel_refs() != to_ty {
+                                diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
+                            }
+                        },
+                    );
+                    return true;
+                },
+                ReducedTy::Ref(to_sub_ty) => {
+                    from_ty = from_sub_ty;
+                    to_ty = to_sub_ty;
+                    continue;
+                },
+                _ => break,
+            },
+            ReducedTys::Other {
+                from_ty: from_sub_ty,
+                to_ty: to_sub_ty,
+            } => match (reduce_ty(cx, from_sub_ty), reduce_ty(cx, to_sub_ty)) {
+                (ReducedTy::IntArray, _) | (_, ReducedTy::IntArray) => return false,
+                (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
+                    span_lint_and_then(
+                        cx,
+                        TRANSMUTE_UNDEFINED_REPR,
+                        e.span,
+                        &format!(
+                            "transmute from `{}` to `{}`, both of which have an undefined layout",
+                            from_ty_orig, to_ty_orig
+                        ),
+                        |diag| {
+                            if_chain! {
+                                if let (Some(from_def), Some(to_def)) = (from_ty.ty_adt_def(), to_ty.ty_adt_def());
+                                if from_def == to_def;
+                                then {
+                                    diag.note(&format!(
+                                        "two instances of the same generic type (`{}`) may have different layouts",
+                                        cx.tcx.item_name(from_def.did)
+                                    ));
+                                } else {
+                                    if from_ty_orig.peel_refs() != from_ty {
+                                        diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
+                                    }
+                                    if to_ty_orig.peel_refs() != to_ty {
+                                        diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
+                                    }
+                                }
+                            }
+                        },
+                    );
+                    return true;
+                },
+                (
+                    ReducedTy::UnorderedFields(from_ty),
+                    ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
+                ) => {
+                    span_lint_and_then(
+                        cx,
+                        TRANSMUTE_UNDEFINED_REPR,
+                        e.span,
+                        &format!("transmute from `{}` which has an undefined layout", from_ty_orig),
+                        |diag| {
+                            if from_ty_orig.peel_refs() != from_ty {
+                                diag.note(&format!("the contained type `{}` has an undefined layout", from_ty));
+                            }
+                        },
+                    );
+                    return true;
+                },
+                (
+                    ReducedTy::Other(_) | ReducedTy::OrderedFields(_) | ReducedTy::Ref(_),
+                    ReducedTy::UnorderedFields(to_ty),
+                ) => {
+                    span_lint_and_then(
+                        cx,
+                        TRANSMUTE_UNDEFINED_REPR,
+                        e.span,
+                        &format!("transmute into `{}` which has an undefined layout", to_ty_orig),
+                        |diag| {
+                            if to_ty_orig.peel_refs() != to_ty {
+                                diag.note(&format!("the contained type `{}` has an undefined layout", to_ty));
+                            }
+                        },
+                    );
+                    return true;
+                },
+                (ReducedTy::Ref(from_sub_ty), ReducedTy::Ref(to_sub_ty)) => {
+                    from_ty = from_sub_ty;
+                    to_ty = to_sub_ty;
+                    continue;
+                },
+                (
+                    ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_),
+                    ReducedTy::OrderedFields(_) | ReducedTy::Ref(_) | ReducedTy::Other(_),
+                )
+                | (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => break,
+            },
+        }
+    }
+
+    false
+}
+
+enum ReducedTys<'tcx> {
+    FromFatPtr { unsized_ty: Ty<'tcx> },
+    ToFatPtr { unsized_ty: Ty<'tcx> },
+    ToPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
+    FromPtr { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
+    Other { from_ty: Ty<'tcx>, to_ty: Ty<'tcx> },
+}
+
+fn reduce_refs<'tcx>(
+    cx: &LateContext<'tcx>,
+    span: Span,
+    mut from_ty: Ty<'tcx>,
+    mut to_ty: Ty<'tcx>,
+) -> ReducedTys<'tcx> {
+    loop {
+        return match (from_ty.kind(), to_ty.kind()) {
+            (
+                &ty::Ref(_, from_sub_ty, _) | &ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. }),
+                &ty::Ref(_, to_sub_ty, _) | &ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. }),
+            ) => {
+                from_ty = from_sub_ty;
+                to_ty = to_sub_ty;
+                continue;
+            },
+            (&ty::Ref(_, unsized_ty, _) | &ty::RawPtr(TypeAndMut { ty: unsized_ty, .. }), _)
+                if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) =>
+            {
+                ReducedTys::FromFatPtr { unsized_ty }
+            },
+            (_, &ty::Ref(_, unsized_ty, _) | &ty::RawPtr(TypeAndMut { ty: unsized_ty, .. }))
+                if !unsized_ty.is_sized(cx.tcx.at(span), cx.param_env) =>
+            {
+                ReducedTys::ToFatPtr { unsized_ty }
+            },
+            (&ty::Ref(_, from_ty, _) | &ty::RawPtr(TypeAndMut { ty: from_ty, .. }), _) => {
+                ReducedTys::FromPtr { from_ty, to_ty }
+            },
+            (_, &ty::Ref(_, to_ty, _) | &ty::RawPtr(TypeAndMut { ty: to_ty, .. })) => {
+                ReducedTys::ToPtr { from_ty, to_ty }
+            },
+            _ => ReducedTys::Other { from_ty, to_ty },
+        };
+    }
+}
+
+enum ReducedTy<'tcx> {
+    OrderedFields(Ty<'tcx>),
+    UnorderedFields(Ty<'tcx>),
+    Ref(Ty<'tcx>),
+    Other(Ty<'tcx>),
+    IntArray,
+}
+
+fn reduce_ty<'tcx>(cx: &LateContext<'tcx>, mut ty: Ty<'tcx>) -> ReducedTy<'tcx> {
+    loop {
+        ty = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty).unwrap_or(ty);
+        return match *ty.kind() {
+            ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => ReducedTy::IntArray,
+            ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
+                ty = sub_ty;
+                continue;
+            },
+            ty::Tuple(args) => {
+                let mut iter = args.iter().map(GenericArg::expect_ty);
+                let Some(sized_ty) = iter.find(|ty| !is_zero_sized_ty(cx, *ty)) else {
+                    return ReducedTy::OrderedFields(ty);
+                };
+                if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
+                    ty = sized_ty;
+                    continue;
+                }
+                ReducedTy::UnorderedFields(ty)
+            },
+            ty::Adt(def, substs) if def.is_struct() => {
+                if def.repr.inhibit_struct_field_reordering_opt() {
+                    return ReducedTy::OrderedFields(ty);
+                }
+                let mut iter = def
+                    .non_enum_variant()
+                    .fields
+                    .iter()
+                    .map(|f| cx.tcx.type_of(f.did).subst(cx.tcx, substs));
+                let Some(sized_ty) = iter.find(|ty| !is_zero_sized_ty(cx, *ty)) else {
+                    return ReducedTy::OrderedFields(ty);
+                };
+                if iter.all(|ty| is_zero_sized_ty(cx, ty)) {
+                    ty = sized_ty;
+                    continue;
+                }
+                ReducedTy::UnorderedFields(ty)
+            },
+            ty::Ref(..) | ty::RawPtr(_) => ReducedTy::Ref(ty),
+            _ => ReducedTy::Other(ty),
+        };
+    }
+}
+
+fn is_zero_sized_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    if_chain! {
+        if let Ok(ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, ty);
+        if let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty));
+        then {
+            layout.layout.size.bytes() == 0
+        } else {
+            false
+        }
+    }
+}
index e2c6d130f3c9cd40c537732af1e4b02e8305e0a7..626d7cd46fc43c1383717d3b670780df06bc6201 100644 (file)
@@ -14,7 +14,7 @@ pub(super) fn check<'tcx>(
     e: &'tcx Expr<'_>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
-    args: &'tcx [Expr<'_>],
+    arg: &'tcx Expr<'_>,
 ) -> bool {
     if can_be_expressed_as_pointer_cast(cx, e, from_ty, to_ty) {
         span_lint_and_then(
@@ -26,7 +26,7 @@ pub(super) fn check<'tcx>(
                 from_ty, to_ty
             ),
             |diag| {
-                if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
+                if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
                     let sugg = arg.as_ty(&to_ty.to_string()).to_string();
                     diag.span_suggestion(e.span, "try", sugg, Applicability::MachineApplicable);
                 }
index 2ce8d4031d77cb7c721bf207404c8e5bc6d68875..2d67401a15f2d65b96cacdbaa0f92e69c6ae7fce 100644 (file)
@@ -1,29 +1,31 @@
 use super::utils::is_layout_incompatible;
 use super::UNSOUND_COLLECTION_TRANSMUTE;
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::match_any_diagnostic_items;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::symbol::{sym, Symbol};
-
-// used to check for UNSOUND_COLLECTION_TRANSMUTE
-static COLLECTIONS: &[Symbol] = &[
-    sym::Vec,
-    sym::VecDeque,
-    sym::BinaryHeap,
-    sym::BTreeSet,
-    sym::BTreeMap,
-    sym::HashSet,
-    sym::HashMap,
-];
+use rustc_span::symbol::sym;
 
 /// Checks for `unsound_collection_transmute` lint.
 /// Returns `true` if it's triggered, otherwise returns `false`.
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, from_ty: Ty<'tcx>, to_ty: Ty<'tcx>) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
         (ty::Adt(from_adt, from_substs), ty::Adt(to_adt, to_substs)) => {
-            if from_adt.did != to_adt.did || match_any_diagnostic_items(cx, to_adt.did, COLLECTIONS).is_none() {
+            if from_adt.did != to_adt.did {
+                return false;
+            }
+            if !matches!(
+                cx.tcx.get_diagnostic_name(to_adt.did),
+                Some(
+                    sym::BTreeMap
+                        | sym::BTreeSet
+                        | sym::BinaryHeap
+                        | sym::HashMap
+                        | sym::HashSet
+                        | sym::Vec
+                        | sym::VecDeque
+                )
+            ) {
                 return false;
             }
             if from_substs
index 445bcf60fa71a68e4481a945f4abda3a012d2cb3..3cc3d40a143dc1c96ca8d535e866968187b0eb48 100644 (file)
@@ -13,7 +13,7 @@ pub(super) fn check<'tcx>(
     e: &'tcx Expr<'_>,
     from_ty: Ty<'tcx>,
     to_ty: Ty<'tcx>,
-    args: &'tcx [Expr<'_>],
+    arg: &'tcx Expr<'_>,
 ) -> bool {
     match (&from_ty.kind(), &to_ty.kind()) {
         _ if from_ty == to_ty => {
@@ -32,9 +32,9 @@ pub(super) fn check<'tcx>(
                 e.span,
                 "transmute from a reference to a pointer",
                 |diag| {
-                    if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
+                    if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
                         let rty_and_mut = ty::TypeAndMut {
-                            ty: rty,
+                            ty: *rty,
                             mutbl: *rty_mutbl,
                         };
 
@@ -57,7 +57,7 @@ pub(super) fn check<'tcx>(
                 e.span,
                 "transmute from an integer to a pointer",
                 |diag| {
-                    if let Some(arg) = sugg::Sugg::hir_opt(cx, &args[0]) {
+                    if let Some(arg) = sugg::Sugg::hir_opt(cx, arg) {
                         diag.span_suggestion(
                             e.span,
                             "try",
index 538c10a5b2045403640a0cae49cb1ce8ba9db760..21a9558ec076a54e938fadc06f56fb6f9fa5ee34 100644 (file)
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_ty_param_diagnostic_item;
+use clippy_utils::{path_def_id, qpath_generic_tys};
 use rustc_hir::{self as hir, def_id::DefId, QPath};
 use rustc_lint::LateContext;
-use rustc_span::symbol::sym;
+use rustc_span::{sym, Symbol};
 
 use super::BOX_COLLECTION;
 
@@ -11,10 +11,9 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
         if Some(def_id) == cx.tcx.lang_items().owned_box();
         if let Some(item_type) = get_std_collection(cx, qpath);
         then {
-            let generic = if item_type == "String" {
-                ""
-            } else {
-                "<..>"
+            let generic = match item_type {
+                sym::String => "",
+                _ => "<..>",
             };
             span_lint_and_help(
                 cx,
@@ -37,14 +36,10 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
     }
 }
 
-fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
-    if is_ty_param_diagnostic_item(cx, qpath, sym::Vec).is_some() {
-        Some("Vec")
-    } else if is_ty_param_diagnostic_item(cx, qpath, sym::String).is_some() {
-        Some("String")
-    } else if is_ty_param_diagnostic_item(cx, qpath, sym::HashMap).is_some() {
-        Some("HashMap")
-    } else {
-        None
-    }
+fn get_std_collection(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Symbol> {
+    let param = qpath_generic_tys(qpath).next()?;
+    let id = path_def_id(cx, param)?;
+    cx.tcx
+        .get_diagnostic_name(id)
+        .filter(|&name| matches!(name, sym::HashMap | sym::String | sym::Vec))
 }
index 903e62995c61702be4775eb152c9674a5e25486b..8767e3c30a68ac4564ba72814b48f53719090be3 100644 (file)
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_ty_param_diagnostic_item;
+use clippy_utils::{path_def_id, qpath_generic_tys};
+use if_chain::if_chain;
 use rustc_hir::{self as hir, def_id::DefId, QPath};
 use rustc_lint::LateContext;
 use rustc_span::symbol::sym;
@@ -7,16 +8,21 @@
 use super::OPTION_OPTION;
 
 pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
-    if cx.tcx.is_diagnostic_item(sym::Option, def_id) && is_ty_param_diagnostic_item(cx, qpath, sym::Option).is_some() {
-        span_lint(
-            cx,
-            OPTION_OPTION,
-            hir_ty.span,
-            "consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
-                                 enum if you need to distinguish all 3 cases",
-        );
-        true
-    } else {
-        false
+    if_chain! {
+        if cx.tcx.is_diagnostic_item(sym::Option, def_id);
+        if let Some(arg) = qpath_generic_tys(qpath).next();
+        if path_def_id(cx, arg) == Some(def_id);
+        then {
+            span_lint(
+                cx,
+                OPTION_OPTION,
+                hir_ty.span,
+                "consider using `Option<T>` instead of `Option<Option<T>>` or a custom \
+                                     enum if you need to distinguish all 3 cases",
+            );
+            true
+        } else {
+            false
+        }
     }
 }
index 31c4abdfc95ea59d4f953926d80af3e14f9c9f1a..4d72a29e8c74722711aeb3b6a754e3d0c2bd4765 100644 (file)
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item};
+use clippy_utils::{path_def_id, qpath_generic_tys};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind};
 use rustc_lint::LateContext;
@@ -20,12 +20,17 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                 format!("Rc<{}>", alternate),
                 Applicability::MachineApplicable,
             );
-        } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Vec) {
+        } else {
+            let Some(ty) = qpath_generic_tys(qpath).next() else { return false };
+            let Some(id) = path_def_id(cx, ty) else { return false };
+            if !cx.tcx.is_diagnostic_item(sym::Vec, id) {
+                return false;
+            }
             let qpath = match &ty.kind {
                 TyKind::Path(qpath) => qpath,
                 _ => return false,
             };
-            let inner_span = match get_qpath_generic_tys(qpath).next() {
+            let inner_span = match qpath_generic_tys(qpath).next() {
                 Some(ty) => ty.span,
                 None => return false,
             };
@@ -55,12 +60,16 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
                 format!("Arc<{}>", alternate),
                 Applicability::MachineApplicable,
             );
-        } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Vec) {
+        } else if let Some(ty) = qpath_generic_tys(qpath).next() {
+            let Some(id) = path_def_id(cx, ty) else { return false };
+            if !cx.tcx.is_diagnostic_item(sym::Vec, id) {
+                return false;
+            }
             let qpath = match &ty.kind {
                 TyKind::Path(qpath) => qpath,
                 _ => return false,
             };
-            let inner_span = match get_qpath_generic_tys(qpath).next() {
+            let inner_span = match qpath_generic_tys(qpath).next() {
                 Some(ty) => ty.span,
                 None => return false,
             };
@@ -85,13 +94,13 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
 }
 
 fn match_buffer_type(cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<&'static str> {
-    if is_ty_param_diagnostic_item(cx, qpath, sym::String).is_some() {
-        Some("str")
-    } else if is_ty_param_diagnostic_item(cx, qpath, sym::OsString).is_some() {
-        Some("std::ffi::OsStr")
-    } else if is_ty_param_diagnostic_item(cx, qpath, sym::PathBuf).is_some() {
-        Some("std::path::Path")
-    } else {
-        None
-    }
+    let ty = qpath_generic_tys(qpath).next()?;
+    let id = path_def_id(cx, ty)?;
+    let path = match cx.tcx.get_diagnostic_name(id)? {
+        sym::String => "str",
+        sym::OsString => "std::ffi::OsStr",
+        sym::PathBuf => "std::path::Path",
+        _ => return None,
+    };
+    Some(path)
 }
index d54608a07bb27e70a5432be150f6fcd137b9653e..a75972cf3ddbe1e2d91acbf11fc541577c7ed7e5 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_ty_param_diagnostic_item;
+use clippy_utils::{path_def_id, qpath_generic_tys};
 use if_chain::if_chain;
 use rustc_hir::{self as hir, def_id::DefId, QPath};
 use rustc_lint::LateContext;
@@ -10,7 +10,9 @@
 pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
     if_chain! {
         if cx.tcx.is_diagnostic_item(sym::Rc, def_id) ;
-        if let Some(_) = is_ty_param_diagnostic_item(cx, qpath, sym::Mutex) ;
+        if let Some(arg) = qpath_generic_tys(qpath).next();
+        if let Some(id) = path_def_id(cx, arg);
+        if cx.tcx.is_diagnostic_item(sym::Mutex, id);
         then {
             span_lint_and_help(
                 cx,
index ac7bdd6a1ebebf318c6e8eab2a46bbcb999b2328..10d2ae2eb1dbb8808eb0fa601d0fc1ffad349dfb 100644 (file)
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{snippet, snippet_with_applicability};
-use clippy_utils::{get_qpath_generic_tys, is_ty_param_diagnostic_item, is_ty_param_lang_item};
+use clippy_utils::{path_def_id, qpath_generic_tys};
 use rustc_errors::Applicability;
-use rustc_hir::{self as hir, def_id::DefId, LangItem, QPath, TyKind};
+use rustc_hir::{self as hir, def_id::DefId, QPath, TyKind};
 use rustc_lint::LateContext;
 use rustc_span::symbol::sym;
 
@@ -39,21 +39,20 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_
         return true;
     }
 
-    let (inner_sym, ty) = if let Some(ty) = is_ty_param_lang_item(cx, qpath, LangItem::OwnedBox) {
-        ("Box", ty)
-    } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Rc) {
-        ("Rc", ty)
-    } else if let Some(ty) = is_ty_param_diagnostic_item(cx, qpath, sym::Arc) {
-        ("Arc", ty)
-    } else {
-        return false;
+    let Some(ty) = qpath_generic_tys(qpath).next() else { return false };
+    let Some(id) = path_def_id(cx, ty) else { return false };
+    let (inner_sym, ty) = match cx.tcx.get_diagnostic_name(id) {
+        Some(sym::Arc) => ("Arc", ty),
+        Some(sym::Rc) => ("Rc", ty),
+        _ if Some(id) == cx.tcx.lang_items().owned_box() => ("Box", ty),
+        _ => return false,
     };
 
     let inner_qpath = match &ty.kind {
         TyKind::Path(inner_qpath) => inner_qpath,
         _ => return false,
     };
-    let inner_span = match get_qpath_generic_tys(inner_qpath).next() {
+    let inner_span = match qpath_generic_tys(inner_qpath).next() {
         Some(ty) => {
             // Box<Box<dyn T>> is smaller than Box<dyn T> because of wide pointers
             if matches!(ty.kind, TyKind::TraitObject(..)) {
index eee1229e1ef0356745ec361f76929e1570c322bf..7c39a08a336b6565c984e7cfb37c07d35a94e343 100644 (file)
@@ -84,7 +84,8 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
         let partial_ord_preds =
             get_trait_predicates_for_trait_id(cx, generics, cx.tcx.lang_items().partial_ord_trait());
         // Trying to call erase_late_bound_regions on fn_sig.inputs() gives the following error
-        // The trait `rustc::ty::TypeFoldable<'_>` is not implemented for `&[&rustc::ty::TyS<'_>]`
+        // The trait `rustc::ty::TypeFoldable<'_>` is not implemented for
+        // `&[rustc_middle::ty::Ty<'_>]`
         let inputs_output = cx.tcx.erase_late_bound_regions(fn_sig.inputs_and_output());
         inputs_output
             .iter()
index e984048701341099acc25ba8b70b5981f2bb14ae..9b9e25326f9663b11e84984b0acb71e59ffc1cfa 100644 (file)
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{differing_macro_contexts, path_to_local, usage::is_potentially_mutated};
+use clippy_utils::{path_to_local, usage::is_potentially_mutated};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
@@ -238,8 +238,9 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 if let Some(unwrappable) = self.unwrappables.iter()
                     .find(|u| u.local_id == id);
                 // Span contexts should not differ with the conditional branch
-                if !differing_macro_contexts(unwrappable.branch.span, expr.span);
-                if !differing_macro_contexts(unwrappable.branch.span, unwrappable.check.span);
+                let span_ctxt = expr.span.ctxt();
+                if unwrappable.branch.span.ctxt() == span_ctxt;
+                if unwrappable.check.span.ctxt() == span_ctxt;
                 then {
                     if call_to_unwrap == unwrappable.safe_to_unwrap {
                         let is_entire_condition = unwrappable.is_entire_condition;
index be20282b3b88c53547571a7ec2f2a28443e3ab14..80164c59ba74c3e570d82fb46985d25f6e47255a 100644 (file)
@@ -204,7 +204,7 @@ fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
                 ref types_to_skip,
             }) = self.stack.last();
             if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
-            if !matches!(path.res, Res::SelfTy(..) | Res::Def(DefKind::TyParam, _));
+            if !matches!(path.res, Res::SelfTy { .. } | Res::Def(DefKind::TyParam, _));
             if !types_to_skip.contains(&hir_ty.hir_id);
             let ty = if in_body > 0 {
                 cx.typeck_results().node_type(hir_ty.hir_id)
@@ -231,7 +231,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         }
         match expr.kind {
             ExprKind::Struct(QPath::Resolved(_, path), ..) => match path.res {
-                Res::SelfTy(..) => (),
+                Res::SelfTy { .. } => (),
                 Res::Def(DefKind::Variant, _) => lint_path_to_variant(cx, path),
                 _ => span_lint(cx, path.span),
             },
index c9d99617c1e281f8315bfc2669fd71243155a3ad..680b2eb1da723d7696878d7d9f1ed2d27f69ebc7 100644 (file)
@@ -322,6 +322,9 @@ pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
     let mut current = env::var_os("CLIPPY_CONF_DIR")
         .or_else(|| env::var_os("CARGO_MANIFEST_DIR"))
         .map_or_else(|| PathBuf::from("."), PathBuf::from);
+
+    let mut found_config: Option<PathBuf> = None;
+
     loop {
         for config_file_name in &CONFIG_FILE_NAMES {
             if let Ok(config_file) = current.join(config_file_name).canonicalize() {
@@ -329,11 +332,26 @@ pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> {
                     Err(e) if e.kind() == io::ErrorKind::NotFound => {},
                     Err(e) => return Err(e),
                     Ok(md) if md.is_dir() => {},
-                    Ok(_) => return Ok(Some(config_file)),
+                    Ok(_) => {
+                        // warn if we happen to find two config files #8323
+                        if let Some(ref found_config_) = found_config {
+                            eprintln!(
+                                "Using config file `{}`\nWarning: `{}` will be ignored.",
+                                found_config_.display(),
+                                config_file.display(),
+                            );
+                        } else {
+                            found_config = Some(config_file);
+                        }
+                    },
                 }
             }
         }
 
+        if found_config.is_some() {
+            return Ok(found_config);
+        }
+
         // If the current directory has no parent, we're done searching.
         if !current.pop() {
             return Ok(None);
index b58325ac73ee964770ce951ffb6a25400932c234..8691148313702e4657a2137b664289b4b1925cb8 100644 (file)
@@ -54,9 +54,6 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
             ),
             hir::VisibilityKind::Inherited => println!("visibility inherited from outer item"),
         }
-        if item.defaultness.is_default() {
-            println!("default");
-        }
         match item.kind {
             hir::ImplItemKind::Const(_, body_id) => {
                 println!("associated constant");
index f170ff69154b6532934489e96d089d670beb32dd..dc0f515bfe5cb1d97e075396e242722eeab43502 100644 (file)
@@ -4,8 +4,8 @@
 use clippy_utils::source::snippet;
 use clippy_utils::ty::match_type;
 use clippy_utils::{
-    higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path, method_calls,
-    path_to_res, paths, peel_blocks_with_stmt, SpanlessEq,
+    def_path_res, higher, is_else_clause, is_expn_of, is_expr_path_def_path, is_lint_allowed, match_def_path,
+    method_calls, paths, peel_blocks_with_stmt, SpanlessEq,
 };
 use if_chain::if_chain;
 use rustc_ast as ast;
@@ -844,7 +844,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             // Extract the path to the matched type
             if let Some(segments) = path_to_matched_type(cx, ty_path);
             let segments: Vec<&str> = segments.iter().map(Symbol::as_str).collect();
-            if let Some(ty_did) = path_to_res(cx, &segments[..]).opt_def_id();
+            if let Some(ty_did) = def_path_res(cx, &segments[..]).opt_def_id();
             // Check if the matched type is a diagnostic item
             if let Some(item_name) = cx.tcx.get_diagnostic_name(ty_did);
             then {
@@ -917,7 +917,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
 // This is not a complete resolver for paths. It works on all the paths currently used in the paths
 // module.  That's all it does and all it needs to do.
 pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
-    if path_to_res(cx, path) != Res::Err {
+    if def_path_res(cx, path) != Res::Err {
         return true;
     }
 
@@ -999,7 +999,7 @@ fn check_crate(&mut self, cx: &LateContext<'_>) {
         }
 
         for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
-            if let Some(def_id) = path_to_res(cx, module).opt_def_id() {
+            if let Some(def_id) = def_path_res(cx, module).opt_def_id() {
                 for item in cx.tcx.module_children(def_id).iter() {
                     if_chain! {
                         if let Res::Def(DefKind::Const, item_def_id) = item.res;
index 3547f0b4e0ae05266096e2a214e80fea4e3b85c4..56633490eaa1a7d51d1c4744eaba273226ccaa09 100644 (file)
@@ -612,8 +612,8 @@ fn get_lint_group_and_level_or_lint(
 }
 
 fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option<String> {
-    for (group_name, lints, _) in &cx.lint_store.get_lint_groups() {
-        if IGNORED_LINT_GROUPS.contains(group_name) {
+    for (group_name, lints, _) in cx.lint_store.get_lint_groups() {
+        if IGNORED_LINT_GROUPS.contains(&group_name) {
             continue;
         }
 
index b0044695ea8a88388da9a655e3336873c4252a8f..1fa6301ebd73dfcc04f1e555fda3b93ab03204ad 100644 (file)
@@ -453,7 +453,7 @@ fn push(&mut self, arg: rustc_parse_format::Argument<'_>, span: Span) {
                     }
                 }
             },
-            ArgumentNamed(n) => {
+            ArgumentNamed(n, _) => {
                 if let Some(x) = self.named.iter_mut().find(|x| x.0 == n) {
                     match x.1.as_slice() {
                         // A non-empty format string has been seen already.
index 34c5af848a6dbe1bfaa92ec1efbfae3e4b4624bf..d40583c47dd7074a8c069c0656652fdcf4652509 100644 (file)
@@ -331,17 +331,16 @@ pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> {
                     let def_path: Vec<&str> = def_path.iter().take(4).map(Symbol::as_str).collect();
                     if let ["core", "num", int_impl, "max_value"] = *def_path;
                     then {
-                       let value = match int_impl {
-                           "<impl i8>" => i8::MAX as u128,
-                           "<impl i16>" => i16::MAX as u128,
-                           "<impl i32>" => i32::MAX as u128,
-                           "<impl i64>" => i64::MAX as u128,
-                           "<impl i128>" => i128::MAX as u128,
-                           _ => return None,
-                       };
-                       Some(Constant::Int(value))
-                    }
-                    else {
+                        let value = match int_impl {
+                            "<impl i8>" => i8::MAX as u128,
+                            "<impl i16>" => i16::MAX as u128,
+                            "<impl i32>" => i32::MAX as u128,
+                            "<impl i64>" => i64::MAX as u128,
+                            "<impl i128>" => i128::MAX as u128,
+                            _ => return None,
+                        };
+                        Some(Constant::Int(value))
+                    } else {
                         None
                     }
                 }
@@ -568,11 +567,11 @@ fn binop(&mut self, op: BinOp, left: &Expr<'_>, right: &Expr<'_>) -> Option<Cons
     }
 }
 
-pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
+pub fn miri_to_const(result: ty::Const<'_>) -> Option<Constant> {
     use rustc_middle::mir::interpret::ConstValue;
-    match result.val {
+    match result.val() {
         ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(int))) => {
-            match result.ty.kind() {
+            match result.ty().kind() {
                 ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
                 ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
                 ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(
@@ -591,7 +590,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
                 _ => None,
             }
         },
-        ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty.kind() {
+        ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => match result.ty().kind() {
             ty::Ref(_, tam, _) => match tam.kind() {
                 ty::Str => String::from_utf8(
                     data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)
@@ -603,9 +602,9 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
             },
             _ => None,
         },
-        ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty.kind() {
+        ty::ConstKind::Value(ConstValue::ByRef { alloc, offset: _ }) => match result.ty().kind() {
             ty::Array(sub_type, len) => match sub_type.kind() {
-                ty::Float(FloatTy::F32) => match miri_to_const(len) {
+                ty::Float(FloatTy::F32) => match miri_to_const(*len) {
                     Some(Constant::Int(len)) => alloc
                         .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * len as usize))
                         .to_owned()
@@ -619,7 +618,7 @@ pub fn miri_to_const(result: &ty::Const<'_>) -> Option<Constant> {
                         .map(Constant::Vec),
                     _ => None,
                 },
-                ty::Float(FloatTy::F64) => match miri_to_const(len) {
+                ty::Float(FloatTy::F64) => match miri_to_const(*len) {
                     Some(Constant::Int(len)) => alloc
                         .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * len as usize))
                         .to_owned()
index 160a51740cd7cde24cf8f31fa13a52fb02925ff8..2095fc966c5dc7535f3be122d08bef255130de57 100644 (file)
@@ -284,8 +284,7 @@ pub fn hir(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option<VecArgs<'a>>
                 return if match_def_path(cx, fun_def_id, &paths::VEC_FROM_ELEM) && args.len() == 2 {
                     // `vec![elem; size]` case
                     Some(VecArgs::Repeat(&args[0], &args[1]))
-                }
-                else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
+                } else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 {
                     // `vec![a, b, c]` case
                     if_chain! {
                         if let hir::ExprKind::Box(boxed) = args[0].kind;
@@ -296,11 +295,9 @@ pub fn hir(cx: &LateContext<'_>, expr: &'a hir::Expr<'_>) -> Option<VecArgs<'a>>
                     }
 
                     None
-                }
-                else if match_def_path(cx, fun_def_id, &paths::VEC_NEW) && args.is_empty() {
+                } else if match_def_path(cx, fun_def_id, &paths::VEC_NEW) && args.is_empty() {
                     Some(VecArgs::Vec(&[]))
-                }
-                else {
+                } else {
                     None
                 };
             }
@@ -456,7 +453,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
                         if let ExprKind::Lit(lit) = &arg.kind;
                         if let LitKind::Int(num, _) = lit.node;
                         then {
-                            return Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?))
+                            return Some(VecInitKind::WithLiteralCapacity(num.try_into().ok()?));
                         }
                     }
                     return Some(VecInitKind::WithExprCapacity(arg.hir_id));
index 7b5c5af8f79bfb1d761e92db4597a77443ea0160..9654895060f85bde17984d509fb4fc2f0906adf4 100644 (file)
@@ -1,5 +1,4 @@
 use crate::consts::{constant_context, constant_simple};
-use crate::differing_macro_contexts;
 use crate::source::snippet_opt;
 use rustc_ast::ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxHasher;
@@ -186,7 +185,7 @@ pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
 
     #[allow(clippy::similar_names)]
     pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
-        if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) {
+        if !self.inner.allow_side_effects && left.span.ctxt() != right.span.ctxt() {
             return false;
         }
 
index a2f1f4696513e067febb58cc2b688faef4c04c73..4bb401273c4002b535178f015c28f4540d13cef6 100644 (file)
@@ -77,9 +77,9 @@
 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 use rustc_hir::{
     def, lang_items, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr,
-    ExprKind, FnDecl, ForeignItem, GenericArgs, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem,
-    Local, MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind,
-    Target, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
+    ExprKind, FnDecl, ForeignItem, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local,
+    MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Target,
+    TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::place::PlaceBase;
@@ -134,13 +134,6 @@ fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast
     };
 }
 
-/// Returns `true` if the two spans come from differing expansions (i.e., one is
-/// from a macro and one isn't).
-#[must_use]
-pub fn differing_macro_contexts(lhs: Span, rhs: Span) -> bool {
-    rhs.ctxt() != lhs.ctxt()
-}
-
 /// If the given expression is a local binding, find the initializer expression.
 /// If that initializer expression is another local binding, find its initializer again.
 /// This process repeats as long as possible (but usually no more than once). Initializer
@@ -262,44 +255,6 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
     matches!(pat.kind, PatKind::Wild)
 }
 
-/// Checks if the first type parameter is a lang item.
-pub fn is_ty_param_lang_item<'tcx>(
-    cx: &LateContext<'_>,
-    qpath: &QPath<'tcx>,
-    item: LangItem,
-) -> Option<&'tcx hir::Ty<'tcx>> {
-    let ty = get_qpath_generic_tys(qpath).next()?;
-
-    if let TyKind::Path(qpath) = &ty.kind {
-        cx.qpath_res(qpath, ty.hir_id)
-            .opt_def_id()
-            .map_or(false, |id| {
-                cx.tcx.lang_items().require(item).map_or(false, |lang_id| id == lang_id)
-            })
-            .then(|| ty)
-    } else {
-        None
-    }
-}
-
-/// Checks if the first type parameter is a diagnostic item.
-pub fn is_ty_param_diagnostic_item<'tcx>(
-    cx: &LateContext<'_>,
-    qpath: &QPath<'tcx>,
-    item: Symbol,
-) -> Option<&'tcx hir::Ty<'tcx>> {
-    let ty = get_qpath_generic_tys(qpath).next()?;
-
-    if let TyKind::Path(qpath) = &ty.kind {
-        cx.qpath_res(qpath, ty.hir_id)
-            .opt_def_id()
-            .map_or(false, |id| cx.tcx.is_diagnostic_item(item, id))
-            .then(|| ty)
-    } else {
-        None
-    }
-}
-
 /// Checks if the method call given in `expr` belongs to the given trait.
 /// This is a deprecated function, consider using [`is_trait_method`].
 pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
@@ -360,35 +315,17 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
     }
 }
 
-pub fn get_qpath_generics<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'tcx>> {
-    match path {
-        QPath::Resolved(_, p) => p.segments.last().and_then(|s| s.args),
-        QPath::TypeRelative(_, s) => s.args,
-        QPath::LangItem(..) => None,
-    }
-}
-
-pub fn get_qpath_generic_tys<'tcx>(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
-    get_qpath_generics(path)
-        .map_or([].as_ref(), |a| a.args)
+pub fn qpath_generic_tys<'tcx>(qpath: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
+    last_path_segment(qpath)
+        .args
+        .map_or(&[][..], |a| a.args)
         .iter()
-        .filter_map(|a| {
-            if let hir::GenericArg::Type(ty) = a {
-                Some(ty)
-            } else {
-                None
-            }
+        .filter_map(|a| match a {
+            hir::GenericArg::Type(ty) => Some(ty),
+            _ => None,
         })
 }
 
-pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
-    match *path {
-        QPath::Resolved(_, path) => path.segments.get(0),
-        QPath::TypeRelative(_, seg) => Some(seg),
-        QPath::LangItem(..) => None,
-    }
-}
-
 /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
 /// entire path or resolved `DefId`. Prefer using `match_def_path`. Consider getting a `DefId` from
 /// `QPath::Resolved.1.res.opt_def_id()`.
@@ -420,37 +357,17 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
     }
 }
 
-/// If the expression is a path, resolve it. Otherwise, return `Res::Err`.
-pub fn expr_path_res(cx: &LateContext<'_>, expr: &Expr<'_>) -> Res {
-    if let ExprKind::Path(p) = &expr.kind {
-        cx.qpath_res(p, expr.hir_id)
-    } else {
-        Res::Err
-    }
-}
-
-/// Resolves the path to a `DefId` and checks if it matches the given path.
-pub fn is_qpath_def_path(cx: &LateContext<'_>, path: &QPath<'_>, hir_id: HirId, segments: &[&str]) -> bool {
-    cx.qpath_res(path, hir_id)
-        .opt_def_id()
-        .map_or(false, |id| match_def_path(cx, id, segments))
-}
-
 /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given path.
 ///
 /// Please use `is_expr_diagnostic_item` if the target is a diagnostic item.
 pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
-    expr_path_res(cx, expr)
-        .opt_def_id()
-        .map_or(false, |id| match_def_path(cx, id, segments))
+    path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments))
 }
 
 /// If the expression is a path, resolves it to a `DefId` and checks if it matches the given
 /// diagnostic item.
 pub fn is_expr_diagnostic_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
-    expr_path_res(cx, expr)
-        .opt_def_id()
-        .map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
+    path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
 }
 
 /// THIS METHOD IS DEPRECATED and will eventually be removed since it does not match against the
@@ -497,8 +414,46 @@ pub fn path_to_local_id(expr: &Expr<'_>, id: HirId) -> bool {
     path_to_local(expr) == Some(id)
 }
 
-/// Gets the definition associated to a path.
-pub fn path_to_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
+pub trait MaybePath<'hir> {
+    fn hir_id(&self) -> HirId;
+    fn qpath_opt(&self) -> Option<&QPath<'hir>>;
+}
+
+macro_rules! maybe_path {
+    ($ty:ident, $kind:ident) => {
+        impl<'hir> MaybePath<'hir> for hir::$ty<'hir> {
+            fn hir_id(&self) -> HirId {
+                self.hir_id
+            }
+            fn qpath_opt(&self) -> Option<&QPath<'hir>> {
+                match &self.kind {
+                    hir::$kind::Path(qpath) => Some(qpath),
+                    _ => None,
+                }
+            }
+        }
+    };
+}
+maybe_path!(Expr, ExprKind);
+maybe_path!(Pat, PatKind);
+maybe_path!(Ty, TyKind);
+
+/// If `maybe_path` is a path node, resolves it, otherwise returns `Res::Err`
+pub fn path_res<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Res {
+    match maybe_path.qpath_opt() {
+        None => Res::Err,
+        Some(qpath) => cx.qpath_res(qpath, maybe_path.hir_id()),
+    }
+}
+
+/// If `maybe_path` is a path node which resolves to an item, retrieves the item ID
+pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>) -> Option<DefId> {
+    path_res(cx, maybe_path).opt_def_id()
+}
+
+/// Resolves a def path like `std::vec::Vec`.
+/// This function is expensive and should be used sparingly.
+pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res {
     macro_rules! try_res {
         ($e:expr) => {
             match $e {
@@ -574,7 +529,7 @@ fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
 /// Convenience function to get the `DefId` of a trait by path.
 /// It could be a trait or trait alias.
 pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
-    match path_to_res(cx, path) {
+    match def_path_res(cx, path) {
         Res::Def(DefKind::Trait | DefKind::TraitAlias, trait_id) => Some(trait_id),
         _ => None,
     }
@@ -603,7 +558,9 @@ pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) ->
         if parent_impl != CRATE_DEF_ID;
         if let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl);
         if let hir::ItemKind::Impl(impl_) = &item.kind;
-        then { return impl_.of_trait.as_ref(); }
+        then {
+            return impl_.of_trait.as_ref();
+        }
     }
     None
 }
@@ -713,12 +670,7 @@ pub fn is_default_equivalent_call(cx: &LateContext<'_>, repl_func: &Expr<'_>) ->
         if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
         if is_diag_trait_item(cx, repl_def_id, sym::Default)
             || is_default_equivalent_ctor(cx, repl_def_id, repl_func_qpath);
-        then {
-            true
-        }
-        else {
-            false
-        }
+        then { true } else { false }
     }
 }
 
@@ -1508,7 +1460,7 @@ pub fn is_self(slf: &Param<'_>) -> bool {
 
 pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
     if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind {
-        if let Res::SelfTy(..) = path.res {
+        if let Res::SelfTy { .. } = path.res {
             return true;
         }
     }
@@ -1553,8 +1505,7 @@ fn is_err(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
             if arms.len() == 2;
             if arms[0].guard.is_none();
             if arms[1].guard.is_none();
-            if (is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) ||
-                (is_ok(cx, &arms[1]) && is_err(cx, &arms[0]));
+            if (is_ok(cx, &arms[0]) && is_err(cx, &arms[1])) || (is_ok(cx, &arms[1]) && is_err(cx, &arms[0]));
             then {
                 return Some(expr);
             }
@@ -1644,7 +1595,7 @@ pub fn match_function_call<'tcx>(
         if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
         if match_def_path(cx, fun_def_id, path);
         then {
-            return Some(args)
+            return Some(args);
         }
     };
     None
@@ -1653,7 +1604,7 @@ pub fn match_function_call<'tcx>(
 /// Checks if the given `DefId` matches any of the paths. Returns the index of matching path, if
 /// any.
 ///
-/// Please use `match_any_diagnostic_items` if the targets are all diagnostic items.
+/// Please use `tcx.get_diagnostic_name` if the targets are all diagnostic items.
 pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]]) -> Option<usize> {
     let search_path = cx.get_def_path(did);
     paths
@@ -1661,14 +1612,6 @@ pub fn match_any_def_paths(cx: &LateContext<'_>, did: DefId, paths: &[&[&str]])
         .position(|p| p.iter().map(|x| Symbol::intern(x)).eq(search_path.iter().copied()))
 }
 
-/// Checks if the given `DefId` matches any of provided diagnostic items. Returns the index of
-/// matching path, if any.
-pub fn match_any_diagnostic_items(cx: &LateContext<'_>, def_id: DefId, diag_items: &[Symbol]) -> Option<usize> {
-    diag_items
-        .iter()
-        .position(|item| cx.tcx.is_diagnostic_item(*item, def_id))
-}
-
 /// Checks if the given `DefId` matches the path.
 pub fn match_def_path<'tcx>(cx: &LateContext<'tcx>, did: DefId, syms: &[&str]) -> bool {
     // We should probably move to Symbols in Clippy as well rather than interning every time.
@@ -1821,8 +1764,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
 
     match expr.kind {
         ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
-        ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
-        _ => false,
+        _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)),
     }
 }
 
@@ -1969,10 +1911,10 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S
     let expr_type = cx.typeck_results().expr_ty_adjusted(expr);
     let expr_kind = expr_type.kind();
     let is_primitive = match expr_kind {
-        rustc_ty::Slice(element_type) => is_recursively_primitive_type(element_type),
+        rustc_ty::Slice(element_type) => is_recursively_primitive_type(*element_type),
         rustc_ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), &rustc_ty::Slice(_)) => {
             if let rustc_ty::Slice(element_type) = inner_ty.kind() {
-                is_recursively_primitive_type(element_type)
+                is_recursively_primitive_type(*element_type)
             } else {
                 unreachable!()
             }
@@ -2174,7 +2116,7 @@ fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(
 
 /// Checks if the function containing the given `HirId` is a `#[test]` function
 ///
-/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
+/// Note: Add `// compile-flags: --test` to UI tests with a `#[test]` function
 pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
     with_test_item_names(tcx, tcx.parent_module(id), |names| {
         tcx.hir()
@@ -2197,7 +2139,7 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
 /// Checks whether item either has `test` attribute applied, or
 /// is a module with `test` in its name.
 ///
-/// Note: If you use this function, please add a `#[test]` case in `tests/ui_test`.
+/// Note: Add `// compile-flags: --test` to UI tests with a `#[test]` function
 pub fn is_test_module_or_function(tcx: TyCtxt<'_>, item: &Item<'_>) -> bool {
     is_in_test_function(tcx, item.hir_id())
         || matches!(item.kind, ItemKind::Mod(..))
index a75f6b86a9bae4de295769ec1a72c5bfcd4db38c..5a76ac23332d31d5fd08c8826cd8f9c78ec876ff 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
 use rustc_lint::LateContext;
 use rustc_span::def_id::DefId;
-use rustc_span::hygiene::{MacroKind, SyntaxContext};
+use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
 use rustc_span::{sym, ExpnData, ExpnId, ExpnKind, Span, Symbol};
 use std::ops::ControlFlow;
 
@@ -306,6 +306,7 @@ fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) ->
 }
 
 /// A parsed `format_args!` expansion
+#[derive(Debug)]
 pub struct FormatArgsExpn<'tcx> {
     /// Span of the first argument, the format string
     pub format_string_span: Span,
@@ -462,7 +463,11 @@ pub fn args(&self) -> Option<Vec<FormatArgsArg<'tcx>>> {
                     if let Ok(i) = usize::try_from(position);
                     if let Some(&(j, format_trait)) = self.formatters.get(i);
                     then {
-                        Some(FormatArgsArg { value: self.value_args[j], format_trait, spec: Some(spec) })
+                        Some(FormatArgsArg {
+                            value: self.value_args[j],
+                            format_trait,
+                            spec: Some(spec),
+                        })
                     } else {
                         None
                     }
@@ -471,11 +476,13 @@ pub fn args(&self) -> Option<Vec<FormatArgsArg<'tcx>>> {
             .collect()
     }
 
-    /// Span of all inputs
+    /// Source callsite span of all inputs
     pub fn inputs_span(&self) -> Span {
         match *self.value_args {
             [] => self.format_string_span,
-            [.., last] => self.format_string_span.to(last.span),
+            [.., last] => self
+                .format_string_span
+                .to(hygiene::walk_chain(last.span, self.format_string_span.ctxt())),
         }
     }
 }
index 7512039a480bb95e191d17eed4b34d3708643d42..c039fec955db9d2641fc86e43ce772da69f04021 100644 (file)
@@ -149,7 +149,7 @@ fn check_rvalue<'tcx>(
         Rvalue::Cast(CastKind::Misc, operand, cast_ty) => {
             use rustc_middle::ty::cast::CastTy;
             let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast");
-            let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
+            let cast_out = CastTy::from_ty(*cast_ty).expect("bad output type for cast");
             match (cast_in, cast_out) {
                 (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => {
                     Err((span, "casting pointers to ints is unstable in const fn".into()))
index 819ff917b63364ac837ebf05477bd69707889ffb..b44899e6bd587235a64fbbb5fc2f4e066ec5759e 100644 (file)
@@ -20,7 +20,7 @@
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use std::iter;
 
-use crate::{expr_path_res, match_def_path, must_use_attr};
+use crate::{match_def_path, must_use_attr, path_res};
 
 // Checks if the given type implements copy.
 pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
@@ -103,7 +103,7 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<
     ];
 
     let ty_to_check = match probably_ref_ty.kind() {
-        ty::Ref(_, ty_to_check, _) => ty_to_check,
+        ty::Ref(_, ty_to_check, _) => *ty_to_check,
         _ => probably_ref_ty,
     };
 
@@ -209,7 +209,7 @@ fn is_normalizable_helper<'tcx>(
     ty: Ty<'tcx>,
     cache: &mut FxHashMap<Ty<'tcx>, bool>,
 ) -> bool {
-    if let Some(&cached_result) = cache.get(ty) {
+    if let Some(&cached_result) = cache.get(&ty) {
         return cached_result;
     }
     // prevent recursive loops, false-negative is better than endless loop leading to stack overflow
@@ -252,7 +252,7 @@ pub fn is_recursively_primitive_type(ty: Ty<'_>) -> bool {
     match ty.kind() {
         ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => true,
         ty::Ref(_, inner, _) if *inner.kind() == ty::Str => true,
-        ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(inner_type),
+        ty::Array(inner_type, _) | ty::Slice(inner_type) => is_recursively_primitive_type(*inner_type),
         ty::Tuple(inner_types) => inner_types.types().all(is_recursively_primitive_type),
         _ => false,
     }
@@ -318,7 +318,7 @@ pub fn match_type(cx: &LateContext<'_>, ty: Ty<'_>, path: &[&str]) -> bool {
 pub fn peel_mid_ty_refs(ty: Ty<'_>) -> (Ty<'_>, usize) {
     fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
         if let ty::Ref(_, ty, _) = ty.kind() {
-            peel(ty, count + 1)
+            peel(*ty, count + 1)
         } else {
             (ty, count)
         }
@@ -331,8 +331,8 @@ fn peel(ty: Ty<'_>, count: usize) -> (Ty<'_>, usize) {
 pub fn peel_mid_ty_refs_is_mutable(ty: Ty<'_>) -> (Ty<'_>, usize, Mutability) {
     fn f(ty: Ty<'_>, count: usize, mutability: Mutability) -> (Ty<'_>, usize, Mutability) {
         match ty.kind() {
-            ty::Ref(_, ty, Mutability::Mut) => f(ty, count + 1, mutability),
-            ty::Ref(_, ty, Mutability::Not) => f(ty, count + 1, Mutability::Not),
+            ty::Ref(_, ty, Mutability::Mut) => f(*ty, count + 1, mutability),
+            ty::Ref(_, ty, Mutability::Not) => f(*ty, count + 1, Mutability::Not),
             _ => (ty, count, mutability),
         }
     }
@@ -360,7 +360,7 @@ pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> {
 pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) {
     fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) {
         match ty.kind() {
-            ty::Ref(_, ty, _) => inner(ty, depth + 1),
+            ty::Ref(_, ty, _) => inner(*ty, depth + 1),
             _ => (ty, depth),
         }
     }
@@ -394,7 +394,7 @@ pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
 /// Checks if a given type looks safe to be uninitialized.
 pub fn is_uninit_value_valid_for_ty(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
     match ty.kind() {
-        ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, component),
+        ty::Array(component, _) => is_uninit_value_valid_for_ty(cx, *component),
         ty::Tuple(types) => types.types().all(|ty| is_uninit_value_valid_for_ty(cx, ty)),
         ty::Adt(adt, _) => cx.tcx.lang_items().maybe_uninit() == Some(adt.did),
         _ => false,
@@ -443,7 +443,7 @@ pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> {
 
 /// If the expression is function like, get the signature for it.
 pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
-    if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = expr_path_res(cx, expr) {
+    if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = path_res(cx, expr) {
         Some(ExprFnSig::Sig(cx.tcx.fn_sig(id)))
     } else {
         let ty = cx.typeck_results().expr_ty_adjusted(expr).peel_refs();
index 6c8a3dc418b1517f4156a7c58a0146f4b9ca2a0a..828bf4cbef9481526edc8840762be8421397dbe7 100644 (file)
@@ -26,7 +26,7 @@ Sometimes you may want to retrieve the type `Ty` of an expression `Expr`, for ex
 - does it implement a trait?
 
 This operation is performed using the [`expr_ty()`][expr_ty] method from the [`TypeckResults`][TypeckResults] struct,
-that gives you access to the underlying structure [`TyS`][TyS].
+that gives you access to the underlying structure [`Ty`][Ty].
 
 Example of use:
 ```rust
@@ -235,7 +235,11 @@ Use the following functions to deal with macros:
    assert_eq!(in_external_macro(cx.sess(), match_span), true);
    ```
 
-- `differing_macro_contexts()`: returns true if the two given spans are not from the same context
+- `span.ctxt()`: the span's context represents whether it is from expansion, and if so, what expanded it
+
+One thing `SpanContext` is useful for is to check if two spans are in the same context. For example,
+in `a == b`, `a` and `b` have the same context. In a `macro_rules!` with `a == $b`, `$b` is expanded to some
+expression with a different context from `a`.
 
    ```rust
    macro_rules! m {
@@ -252,10 +256,10 @@ Use the following functions to deal with macros:
    // These spans are not from the same context
    // x.is_some() is from inside the macro
    // x.unwrap() is from outside the macro
-   assert_eq!(differing_macro_contexts(x_is_some_span, x_unwrap_span), true);
+   assert_eq!(x_is_some_span.ctxt(), x_unwrap_span.ctxt());
    ```
 
-[TyS]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyS.html
+[Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html
 [TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html
 [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html
 [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty
index e23dc73ab08c1233e51d9b926923e2790fbabb5c..f065f0bffc7bf70fc934bec08ab33408bad2874c 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-01-27"
+channel = "nightly-2022-02-10"
 components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
index 6505028db9fadc1f5e75e62e468bcde1d805d737..a82ff182839314d625cd0078cbe2d17fda1fe670 100644 (file)
@@ -11,6 +11,7 @@
 use std::ffi::{OsStr, OsString};
 use std::fs;
 use std::io;
+use std::lazy::SyncLazy;
 use std::path::{Path, PathBuf};
 use test_utils::IS_RUSTC_TEST_SUITE;
 
 /// dependencies must be added to Cargo.toml at the project root. Test
 /// dependencies that are not *directly* used by this test module require an
 /// `extern crate` declaration.
-fn extern_flags() -> String {
+static EXTERN_FLAGS: SyncLazy<String> = SyncLazy::new(|| {
     let current_exe_depinfo = {
         let mut path = env::current_exe().unwrap();
         path.set_extension("d");
-        std::fs::read_to_string(path).unwrap()
+        fs::read_to_string(path).unwrap()
     };
     let mut crates: HashMap<&str, &str> = HashMap::with_capacity(TEST_DEPENDENCIES.len());
     for line in current_exe_depinfo.lines() {
@@ -112,16 +113,17 @@ fn extern_flags() -> String {
         .into_iter()
         .map(|(name, path)| format!(" --extern {}={}", name, path))
         .collect()
-}
+});
 
-fn default_config() -> compiletest::Config {
+fn base_config(test_dir: &str) -> compiletest::Config {
     let mut config = compiletest::Config {
         edition: Some("2021".into()),
+        mode: TestMode::Ui,
         ..compiletest::Config::default()
     };
 
     if let Ok(filters) = env::var("TESTNAME") {
-        config.filters = filters.split(',').map(std::string::ToString::to_string).collect();
+        config.filters = filters.split(',').map(ToString::to_string).collect();
     }
 
     if let Some(path) = option_env!("RUSTC_LIB_PATH") {
@@ -129,7 +131,7 @@ fn default_config() -> compiletest::Config {
         config.run_lib_path = path.clone();
         config.compile_lib_path = path;
     }
-    let current_exe_path = std::env::current_exe().unwrap();
+    let current_exe_path = env::current_exe().unwrap();
     let deps_path = current_exe_path.parent().unwrap();
     let profile_path = deps_path.parent().unwrap();
 
@@ -143,10 +145,11 @@ fn default_config() -> compiletest::Config {
         "--emit=metadata -Dwarnings -Zui-testing -L dependency={}{}{}",
         deps_path.display(),
         host_libs,
-        extern_flags(),
+        &*EXTERN_FLAGS,
     ));
 
-    config.build_base = profile_path.join("test");
+    config.src_base = Path::new("tests").join(test_dir);
+    config.build_base = profile_path.join("test").join(test_dir);
     config.rustc_path = profile_path.join(if cfg!(windows) {
         "clippy-driver.exe"
     } else {
@@ -155,38 +158,23 @@ fn default_config() -> compiletest::Config {
     config
 }
 
-fn run_ui(cfg: &mut compiletest::Config) {
-    cfg.mode = TestMode::Ui;
-    cfg.src_base = Path::new("tests").join("ui");
+fn run_ui() {
+    let config = base_config("ui");
     // use tests/clippy.toml
-    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
-    compiletest::run_tests(cfg);
-}
-
-fn run_ui_test(cfg: &mut compiletest::Config) {
-    cfg.mode = TestMode::Ui;
-    cfg.src_base = Path::new("tests").join("ui_test");
-    let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap());
-    let rustcflags = cfg.target_rustcflags.get_or_insert_with(Default::default);
-    let len = rustcflags.len();
-    rustcflags.push_str(" --test");
-    compiletest::run_tests(cfg);
-    if let Some(ref mut flags) = &mut cfg.target_rustcflags {
-        flags.truncate(len);
-    }
+    let _g = VarGuard::set("CARGO_MANIFEST_DIR", fs::canonicalize("tests").unwrap());
+    compiletest::run_tests(&config);
 }
 
-fn run_internal_tests(cfg: &mut compiletest::Config) {
+fn run_internal_tests() {
     // only run internal tests with the internal-tests feature
     if !RUN_INTERNAL_TESTS {
         return;
     }
-    cfg.mode = TestMode::Ui;
-    cfg.src_base = Path::new("tests").join("ui-internal");
-    compiletest::run_tests(cfg);
+    let config = base_config("ui-internal");
+    compiletest::run_tests(&config);
 }
 
-fn run_ui_toml(config: &mut compiletest::Config) {
+fn run_ui_toml() {
     fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>) -> Result<bool, io::Error> {
         let mut result = true;
         let opts = compiletest::test_opts(config);
@@ -222,12 +210,12 @@ fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>
         Ok(result)
     }
 
-    config.mode = TestMode::Ui;
-    config.src_base = Path::new("tests").join("ui-toml").canonicalize().unwrap();
+    let mut config = base_config("ui-toml");
+    config.src_base = config.src_base.canonicalize().unwrap();
 
-    let tests = compiletest::make_tests(config);
+    let tests = compiletest::make_tests(&config);
 
-    let res = run_tests(config, tests);
+    let res = run_tests(&config, tests);
     match res {
         Ok(true) => {},
         Ok(false) => panic!("Some tests failed"),
@@ -237,7 +225,7 @@ fn run_tests(config: &compiletest::Config, mut tests: Vec<tester::TestDescAndFn>
     }
 }
 
-fn run_ui_cargo(config: &mut compiletest::Config) {
+fn run_ui_cargo() {
     fn run_tests(
         config: &compiletest::Config,
         filters: &[String],
@@ -310,13 +298,13 @@ fn run_tests(
         return;
     }
 
-    config.mode = TestMode::Ui;
-    config.src_base = Path::new("tests").join("ui-cargo").canonicalize().unwrap();
+    let mut config = base_config("ui-cargo");
+    config.src_base = config.src_base.canonicalize().unwrap();
 
-    let tests = compiletest::make_tests(config);
+    let tests = compiletest::make_tests(&config);
 
     let current_dir = env::current_dir().unwrap();
-    let res = run_tests(config, &config.filters, tests);
+    let res = run_tests(&config, &config.filters, tests);
     env::set_current_dir(current_dir).unwrap();
 
     match res {
@@ -331,12 +319,10 @@ fn run_tests(
 #[test]
 fn compile_test() {
     set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
-    let mut config = default_config();
-    run_ui(&mut config);
-    run_ui_test(&mut config);
-    run_ui_toml(&mut config);
-    run_ui_cargo(&mut config);
-    run_internal_tests(&mut config);
+    run_ui();
+    run_ui_toml();
+    run_ui_cargo();
+    run_internal_tests();
 }
 
 /// Restores an env var on drop
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/Cargo.toml
new file mode 100644 (file)
index 0000000..79c973c
--- /dev/null
@@ -0,0 +1,8 @@
+[package]
+name = "no_warn"
+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/clippy/tests/ui-cargo/multiple_config_files/no_warn/clippy.toml b/src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/clippy.toml
new file mode 100644 (file)
index 0000000..cda8d17
--- /dev/null
@@ -0,0 +1 @@
+avoid-breaking-exported-api = false
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_config_files/no_warn/src/main.rs
new file mode 100644 (file)
index 0000000..e7a11a9
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/.clippy.toml b/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/.clippy.toml
new file mode 100644 (file)
index 0000000..cda8d17
--- /dev/null
@@ -0,0 +1 @@
+avoid-breaking-exported-api = false
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/Cargo.toml b/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/Cargo.toml
new file mode 100644 (file)
index 0000000..3d5c707
--- /dev/null
@@ -0,0 +1,8 @@
+[package]
+name = "warn"
+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/clippy/tests/ui-cargo/multiple_config_files/warn/clippy.toml b/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/clippy.toml
new file mode 100644 (file)
index 0000000..cda8d17
--- /dev/null
@@ -0,0 +1 @@
+avoid-breaking-exported-api = false
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.rs
new file mode 100644 (file)
index 0000000..2d0b4a7
--- /dev/null
@@ -0,0 +1,5 @@
+// ignore-windows
+
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.stderr b/src/tools/clippy/tests/ui-cargo/multiple_config_files/warn/src/main.stderr
new file mode 100644 (file)
index 0000000..2abb4e3
--- /dev/null
@@ -0,0 +1,2 @@
+Using config file `$SRC_DIR/tests/ui-cargo/multiple_config_files/warn/.clippy.toml`
+Warning: `$SRC_DIR/tests/ui-cargo/multiple_config_files/warn/clippy.toml` will be ignored.
index 3822f174598540ea2980e6469795872029d5a9e7..e0510d942c200843abd0432b756f60ab9002d265 100644 (file)
@@ -3,6 +3,7 @@
 // Test for https://github.com/rust-lang/rust-clippy/issues/4968
 
 #![warn(clippy::unsound_collection_transmute)]
+#![allow(clippy::transmute_undefined_repr)]
 
 trait Trait {
     type Assoc;
diff --git a/src/tools/clippy/tests/ui/crashes/ice-8250.rs b/src/tools/clippy/tests/ui/crashes/ice-8250.rs
new file mode 100644 (file)
index 0000000..d9a5ee1
--- /dev/null
@@ -0,0 +1,6 @@
+fn _f(s: &str) -> Option<()> {
+    let _ = s[1..].splitn(2, '.').next()?;
+    Some(())
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-8250.stderr b/src/tools/clippy/tests/ui/crashes/ice-8250.stderr
new file mode 100644 (file)
index 0000000..04ea445
--- /dev/null
@@ -0,0 +1,18 @@
+error: manual implementation of `split_once`
+  --> $DIR/ice-8250.rs:2:13
+   |
+LL |     let _ = s[1..].splitn(2, '.').next()?;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `s[1..].split_once('.').map_or(s[1..], |x| x.0)`
+   |
+   = note: `-D clippy::manual-split-once` implied by `-D warnings`
+
+error: unnecessary use of `splitn`
+  --> $DIR/ice-8250.rs:2:13
+   |
+LL |     let _ = s[1..].splitn(2, '.').next()?;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try this: `s[1..].split('.')`
+   |
+   = note: `-D clippy::needless-splitn` implied by `-D warnings`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-8386.rs b/src/tools/clippy/tests/ui/crashes/ice-8386.rs
new file mode 100644 (file)
index 0000000..3e38b14
--- /dev/null
@@ -0,0 +1,3 @@
+fn f(x: u32, mut arg: &String) {}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/default_union_representation.rs b/src/tools/clippy/tests/ui/default_union_representation.rs
new file mode 100644 (file)
index 0000000..93b2d33
--- /dev/null
@@ -0,0 +1,78 @@
+#![feature(transparent_unions)]
+#![warn(clippy::default_union_representation)]
+
+union NoAttribute {
+    a: i32,
+    b: u32,
+}
+
+#[repr(C)]
+union ReprC {
+    a: i32,
+    b: u32,
+}
+
+#[repr(packed)]
+union ReprPacked {
+    a: i32,
+    b: u32,
+}
+
+#[repr(C, packed)]
+union ReprCPacked {
+    a: i32,
+    b: u32,
+}
+
+#[repr(C, align(32))]
+union ReprCAlign {
+    a: i32,
+    b: u32,
+}
+
+#[repr(align(32))]
+union ReprAlign {
+    a: i32,
+    b: u32,
+}
+
+union SingleZST {
+    f0: (),
+}
+union ZSTsAndField1 {
+    f0: u32,
+    f1: (),
+    f2: (),
+    f3: (),
+}
+union ZSTsAndField2 {
+    f0: (),
+    f1: (),
+    f2: u32,
+    f3: (),
+}
+union ZSTAndTwoFields {
+    f0: u32,
+    f1: u64,
+    f2: (),
+}
+
+#[repr(C)]
+union CZSTAndTwoFields {
+    f0: u32,
+    f1: u64,
+    f2: (),
+}
+
+#[repr(transparent)]
+union ReprTransparent {
+    a: i32,
+}
+
+#[repr(transparent)]
+union ReprTransparentZST {
+    a: i32,
+    b: (),
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/default_union_representation.stderr b/src/tools/clippy/tests/ui/default_union_representation.stderr
new file mode 100644 (file)
index 0000000..138884a
--- /dev/null
@@ -0,0 +1,48 @@
+error: this union has the default representation
+  --> $DIR/default_union_representation.rs:4:1
+   |
+LL | / union NoAttribute {
+LL | |     a: i32,
+LL | |     b: u32,
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::default-union-representation` implied by `-D warnings`
+   = help: consider annotating `NoAttribute` with `#[repr(C)]` to explicitly specify memory layout
+
+error: this union has the default representation
+  --> $DIR/default_union_representation.rs:16:1
+   |
+LL | / union ReprPacked {
+LL | |     a: i32,
+LL | |     b: u32,
+LL | | }
+   | |_^
+   |
+   = help: consider annotating `ReprPacked` with `#[repr(C)]` to explicitly specify memory layout
+
+error: this union has the default representation
+  --> $DIR/default_union_representation.rs:34:1
+   |
+LL | / union ReprAlign {
+LL | |     a: i32,
+LL | |     b: u32,
+LL | | }
+   | |_^
+   |
+   = help: consider annotating `ReprAlign` with `#[repr(C)]` to explicitly specify memory layout
+
+error: this union has the default representation
+  --> $DIR/default_union_representation.rs:54:1
+   |
+LL | / union ZSTAndTwoFields {
+LL | |     f0: u32,
+LL | |     f1: u64,
+LL | |     f2: (),
+LL | | }
+   | |_^
+   |
+   = help: consider annotating `ZSTAndTwoFields` with `#[repr(C)]` to explicitly specify memory layout
+
+error: aborting due to 4 previous errors
+
index 707b449f82e4f04ea4e85b4efeb76b17820aaa33..422f9486503d2396a484653531936afe7aa18814 100644 (file)
@@ -1,58 +1,56 @@
-// does not test any rustfixable lints
-
-#[rustfmt::skip]
-#[warn(clippy::eq_op)]
-#[allow(clippy::identity_op, clippy::double_parens)]
-#[allow(clippy::no_effect, unused_variables, clippy::unnecessary_operation, clippy::short_circuit_statement)]
-#[allow(clippy::nonminimal_bool)]
-#[allow(unused)]
-#[allow(clippy::unnecessary_cast)]
+// compile-flags: --test
+
+#![warn(clippy::eq_op)]
+#![allow(clippy::double_parens, clippy::identity_op, clippy::nonminimal_bool)]
+
 fn main() {
     // simple values and comparisons
-    1 == 1;
-    "no" == "no";
+    let _ = 1 == 1;
+    let _ = "no" == "no";
     // even though I agree that no means no ;-)
-    false != false;
-    1.5 < 1.5;
-    1u64 >= 1u64;
+    let _ = false != false;
+    let _ = 1.5 < 1.5;
+    let _ = 1u64 >= 1u64;
 
     // casts, methods, parentheses
-    (1 as u64) & (1 as u64);
-    1 ^ ((((((1))))));
+    let _ = (1u32 as u64) & (1u32 as u64);
+    #[rustfmt::skip]
+    {
+        let _ = 1 ^ ((((((1))))));
+    };
 
     // unary and binary operators
-    (-(2) < -(2));
-    ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
-    (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
+    let _ = (-(2) < -(2));
+    let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
+    let _ = (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
 
     // various other things
-    ([1] != [1]);
-    ((1, 2) != (1, 2));
-    vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros
+    let _ = ([1] != [1]);
+    let _ = ((1, 2) != (1, 2));
+    let _ = vec![1, 2, 3] == vec![1, 2, 3]; //no error yet, as we don't match macros
 
     // const folding
-    1 + 1 == 2;
-    1 - 1 == 0;
+    let _ = 1 + 1 == 2;
+    let _ = 1 - 1 == 0;
 
-    1 - 1;
-    1 / 1;
-    true && true;
-
-    true || true;
+    let _ = 1 - 1;
+    let _ = 1 / 1;
+    let _ = true && true;
 
+    let _ = true || true;
 
     let a: u32 = 0;
     let b: u32 = 0;
 
-    a == b && b == a;
-    a != b && b != a;
-    a < b && b > a;
-    a <= b && b >= a;
+    let _ = a == b && b == a;
+    let _ = a != b && b != a;
+    let _ = a < b && b > a;
+    let _ = a <= b && b >= a;
 
     let mut a = vec![1];
-    a == a;
-    2*a.len() == 2*a.len(); // ok, functions
-    a.pop() == a.pop(); // ok, functions
+    let _ = a == a;
+    let _ = 2 * a.len() == 2 * a.len(); // ok, functions
+    let _ = a.pop() == a.pop(); // ok, functions
 
     check_ignore_macro();
 
@@ -63,15 +61,14 @@ fn main() {
     const D: u32 = A / A;
 }
 
-#[rustfmt::skip]
 macro_rules! check_if_named_foo {
-    ($expression:expr) => (
+    ($expression:expr) => {
         if stringify!($expression) == "foo" {
             println!("foo!");
         } else {
             println!("not foo.");
         }
-    )
+    };
 }
 
 macro_rules! bool_macro {
@@ -80,11 +77,10 @@ macro_rules! bool_macro {
     };
 }
 
-#[allow(clippy::short_circuit_statement)]
 fn check_ignore_macro() {
     check_if_named_foo!(foo);
     // checks if the lint ignores macros with `!` operator
-    !bool_macro!(1) && !bool_macro!("");
+    let _ = !bool_macro!(1) && !bool_macro!("");
 }
 
 struct Nested {
@@ -95,3 +91,18 @@ fn check_nested(n1: &Nested, n2: &Nested) -> bool {
     // `n2.inner.0.0` mistyped as `n1.inner.0.0`
     (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0
 }
+
+#[test]
+fn eq_op_shouldnt_trigger_in_tests() {
+    let a = 1;
+    let result = a + 1 == 1 + a;
+    assert!(result);
+}
+
+#[test]
+fn eq_op_macros_shouldnt_trigger_in_tests() {
+    let a = 1;
+    let b = 2;
+    assert_eq!(a, a);
+    assert_eq!(a + b, b + a);
+}
index 8ef658af8df429829ec50d85dfcdbe4f8ab3bd74..313ceed2b41facad2b115d1b36d0d77bbb4693a2 100644 (file)
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:12:5
+  --> $DIR/eq_op.rs:8:13
    |
-LL |     1 == 1;
-   |     ^^^^^^
+LL |     let _ = 1 == 1;
+   |             ^^^^^^
    |
    = note: `-D clippy::eq-op` implied by `-D warnings`
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:13:5
+  --> $DIR/eq_op.rs:9:13
    |
-LL |     "no" == "no";
-   |     ^^^^^^^^^^^^
+LL |     let _ = "no" == "no";
+   |             ^^^^^^^^^^^^
 
 error: equal expressions as operands to `!=`
-  --> $DIR/eq_op.rs:15:5
+  --> $DIR/eq_op.rs:11:13
    |
-LL |     false != false;
-   |     ^^^^^^^^^^^^^^
+LL |     let _ = false != false;
+   |             ^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `<`
-  --> $DIR/eq_op.rs:16:5
+  --> $DIR/eq_op.rs:12:13
    |
-LL |     1.5 < 1.5;
-   |     ^^^^^^^^^
+LL |     let _ = 1.5 < 1.5;
+   |             ^^^^^^^^^
 
 error: equal expressions as operands to `>=`
-  --> $DIR/eq_op.rs:17:5
+  --> $DIR/eq_op.rs:13:13
    |
-LL |     1u64 >= 1u64;
-   |     ^^^^^^^^^^^^
+LL |     let _ = 1u64 >= 1u64;
+   |             ^^^^^^^^^^^^
 
 error: equal expressions as operands to `&`
-  --> $DIR/eq_op.rs:20:5
+  --> $DIR/eq_op.rs:16:13
    |
-LL |     (1 as u64) & (1 as u64);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _ = (1u32 as u64) & (1u32 as u64);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `^`
-  --> $DIR/eq_op.rs:21:5
+  --> $DIR/eq_op.rs:19:17
    |
-LL |     1 ^ ((((((1))))));
-   |     ^^^^^^^^^^^^^^^^^
+LL |         let _ = 1 ^ ((((((1))))));
+   |                 ^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `<`
-  --> $DIR/eq_op.rs:24:5
+  --> $DIR/eq_op.rs:23:13
    |
-LL |     (-(2) < -(2));
-   |     ^^^^^^^^^^^^^
+LL |     let _ = (-(2) < -(2));
+   |             ^^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:25:5
+  --> $DIR/eq_op.rs:24:13
    |
-LL |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `&`
-  --> $DIR/eq_op.rs:25:6
+  --> $DIR/eq_op.rs:24:14
    |
-LL |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
-   |      ^^^^^^^^^^^^^^^^^
+LL |     let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
+   |              ^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `&`
-  --> $DIR/eq_op.rs:25:27
+  --> $DIR/eq_op.rs:24:35
    |
-LL |     ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
-   |                           ^^^^^^^^^^^^^^^^^
+LL |     let _ = ((1 + 1) & (1 + 1) == (1 + 1) & (1 + 1));
+   |                                   ^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:26:5
+  --> $DIR/eq_op.rs:25:13
    |
-LL |     (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _ = (1 * 2) + (3 * 4) == 1 * 2 + 3 * 4;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `!=`
-  --> $DIR/eq_op.rs:29:5
+  --> $DIR/eq_op.rs:28:13
    |
-LL |     ([1] != [1]);
-   |     ^^^^^^^^^^^^
+LL |     let _ = ([1] != [1]);
+   |             ^^^^^^^^^^^^
 
 error: equal expressions as operands to `!=`
-  --> $DIR/eq_op.rs:30:5
+  --> $DIR/eq_op.rs:29:13
    |
-LL |     ((1, 2) != (1, 2));
-   |     ^^^^^^^^^^^^^^^^^^
+LL |     let _ = ((1, 2) != (1, 2));
+   |             ^^^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:34:5
+  --> $DIR/eq_op.rs:33:13
    |
-LL |     1 + 1 == 2;
-   |     ^^^^^^^^^^
+LL |     let _ = 1 + 1 == 2;
+   |             ^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:35:5
+  --> $DIR/eq_op.rs:34:13
    |
-LL |     1 - 1 == 0;
-   |     ^^^^^^^^^^
+LL |     let _ = 1 - 1 == 0;
+   |             ^^^^^^^^^^
 
 error: equal expressions as operands to `-`
-  --> $DIR/eq_op.rs:35:5
+  --> $DIR/eq_op.rs:34:13
    |
-LL |     1 - 1 == 0;
-   |     ^^^^^
+LL |     let _ = 1 - 1 == 0;
+   |             ^^^^^
 
 error: equal expressions as operands to `-`
-  --> $DIR/eq_op.rs:37:5
+  --> $DIR/eq_op.rs:36:13
    |
-LL |     1 - 1;
-   |     ^^^^^
+LL |     let _ = 1 - 1;
+   |             ^^^^^
 
 error: equal expressions as operands to `/`
-  --> $DIR/eq_op.rs:38:5
+  --> $DIR/eq_op.rs:37:13
    |
-LL |     1 / 1;
-   |     ^^^^^
+LL |     let _ = 1 / 1;
+   |             ^^^^^
 
 error: equal expressions as operands to `&&`
-  --> $DIR/eq_op.rs:39:5
+  --> $DIR/eq_op.rs:38:13
    |
-LL |     true && true;
-   |     ^^^^^^^^^^^^
+LL |     let _ = true && true;
+   |             ^^^^^^^^^^^^
 
 error: equal expressions as operands to `||`
-  --> $DIR/eq_op.rs:41:5
+  --> $DIR/eq_op.rs:40:13
    |
-LL |     true || true;
-   |     ^^^^^^^^^^^^
+LL |     let _ = true || true;
+   |             ^^^^^^^^^^^^
 
 error: equal expressions as operands to `&&`
-  --> $DIR/eq_op.rs:47:5
+  --> $DIR/eq_op.rs:45:13
    |
-LL |     a == b && b == a;
-   |     ^^^^^^^^^^^^^^^^
+LL |     let _ = a == b && b == a;
+   |             ^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `&&`
-  --> $DIR/eq_op.rs:48:5
+  --> $DIR/eq_op.rs:46:13
    |
-LL |     a != b && b != a;
-   |     ^^^^^^^^^^^^^^^^
+LL |     let _ = a != b && b != a;
+   |             ^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `&&`
-  --> $DIR/eq_op.rs:49:5
+  --> $DIR/eq_op.rs:47:13
    |
-LL |     a < b && b > a;
-   |     ^^^^^^^^^^^^^^
+LL |     let _ = a < b && b > a;
+   |             ^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `&&`
-  --> $DIR/eq_op.rs:50:5
+  --> $DIR/eq_op.rs:48:13
    |
-LL |     a <= b && b >= a;
-   |     ^^^^^^^^^^^^^^^^
+LL |     let _ = a <= b && b >= a;
+   |             ^^^^^^^^^^^^^^^^
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:53:5
+  --> $DIR/eq_op.rs:51:13
    |
-LL |     a == a;
-   |     ^^^^^^
+LL |     let _ = a == a;
+   |             ^^^^^^
 
 error: equal expressions as operands to `/`
-  --> $DIR/eq_op.rs:63:20
+  --> $DIR/eq_op.rs:61:20
    |
 LL |     const D: u32 = A / A;
    |                    ^^^^^
 
 error: equal expressions as operands to `==`
-  --> $DIR/eq_op.rs:96:5
+  --> $DIR/eq_op.rs:92:5
    |
 LL |     (n1.inner.0).0 == (n1.inner.0).0 && (n1.inner.1).0 == (n2.inner.1).0 && (n1.inner.2).0 == (n2.inner.2).0
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `#[deny(clippy::eq_op)]` on by default
 
 error: aborting due to 28 previous errors
 
index cf923a6a5940c3574216eca71be849f9cd89d6e5..53e45d28bded91a7ab772f5aa2afd15c3f8a379e 100644 (file)
@@ -5,6 +5,12 @@
 
 /// Checks implementation of the `EXPECT_FUN_CALL` lint
 
+macro_rules! one {
+    () => {
+        1
+    };
+}
+
 fn main() {
     struct Foo;
 
@@ -31,6 +37,9 @@ fn main() {
     let with_none_and_as_str: Option<i32> = None;
     with_none_and_as_str.unwrap_or_else(|| panic!("Error {}: fake error", error_code));
 
+    let with_none_and_format_with_macro: Option<i32> = None;
+    with_none_and_format_with_macro.unwrap_or_else(|| panic!("Error {}: fake error", one!()));
+
     let with_ok: Result<(), ()> = Ok(());
     with_ok.expect("error");
 
index e6f252259df70427e2da39b9ca9a3c6172f51659..22e530b80349d81e27ef8fdeb015acbe54a027a5 100644 (file)
@@ -5,6 +5,12 @@
 
 /// Checks implementation of the `EXPECT_FUN_CALL` lint
 
+macro_rules! one {
+    () => {
+        1
+    };
+}
+
 fn main() {
     struct Foo;
 
@@ -31,6 +37,9 @@ fn expect(&self, msg: &str) {
     let with_none_and_as_str: Option<i32> = None;
     with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
 
+    let with_none_and_format_with_macro: Option<i32> = None;
+    with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str());
+
     let with_ok: Result<(), ()> = Ok(());
     with_ok.expect("error");
 
index ac48a06671cd2e0d572ecc36637c0237bc90426c..aca15935fca06596dca5f84edebe35b693baaa15 100644 (file)
@@ -1,5 +1,5 @@
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:29:26
+  --> $DIR/expect_fun_call.rs:35:26
    |
 LL |     with_none_and_format.expect(&format!("Error {}: fake error", error_code));
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
@@ -7,70 +7,76 @@ LL |     with_none_and_format.expect(&format!("Error {}: fake error", error_code
    = note: `-D clippy::expect-fun-call` implied by `-D warnings`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:32:26
+  --> $DIR/expect_fun_call.rs:38:26
    |
 LL |     with_none_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", error_code))`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:42:25
+  --> $DIR/expect_fun_call.rs:41:37
+   |
+LL |     with_none_and_format_with_macro.expect(format!("Error {}: fake error", one!()).as_str());
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("Error {}: fake error", one!()))`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:51:25
    |
 LL |     with_err_and_format.expect(&format!("Error {}: fake error", error_code));
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:45:25
+  --> $DIR/expect_fun_call.rs:54:25
    |
 LL |     with_err_and_as_str.expect(format!("Error {}: fake error", error_code).as_str());
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|_| panic!("Error {}: fake error", error_code))`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:57:17
+  --> $DIR/expect_fun_call.rs:66:17
    |
 LL |     Some("foo").expect(format!("{} {}", 1, 2).as_ref());
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{} {}", 1, 2))`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:78:21
+  --> $DIR/expect_fun_call.rs:87:21
    |
 LL |         Some("foo").expect(&get_string());
    |                     ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:79:21
+  --> $DIR/expect_fun_call.rs:88:21
    |
 LL |         Some("foo").expect(get_string().as_ref());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:80:21
+  --> $DIR/expect_fun_call.rs:89:21
    |
 LL |         Some("foo").expect(get_string().as_str());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:82:21
+  --> $DIR/expect_fun_call.rs:91:21
    |
 LL |         Some("foo").expect(get_static_str());
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:83:21
+  --> $DIR/expect_fun_call.rs:92:21
    |
 LL |         Some("foo").expect(get_non_static_str(&0));
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:87:16
+  --> $DIR/expect_fun_call.rs:96:16
    |
 LL |     Some(true).expect(&format!("key {}, {}", 1, 2));
    |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("key {}, {}", 1, 2))`
 
 error: use of `expect` followed by a function call
-  --> $DIR/expect_fun_call.rs:93:17
+  --> $DIR/expect_fun_call.rs:102:17
    |
 LL |         opt_ref.expect(&format!("{:?}", opt_ref));
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))`
 
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
 
index 9edddea651c26f01c12b1a7f774dafa0098d77ec..f9f8407d57755481de85bad8ad47efe42eba1563 100644 (file)
@@ -46,13 +46,13 @@ error: the variable `idx_usize` is used as a loop counter
   --> $DIR/explicit_counter_loop.rs:170:9
    |
 LL |         for _item in slice {
-   |         ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_usize, _item) in slice.into_iter().enumerate()`
+   |         ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_usize, _item) in slice.iter().enumerate()`
 
 error: the variable `idx_u32` is used as a loop counter
   --> $DIR/explicit_counter_loop.rs:182:9
    |
 LL |         for _item in slice {
-   |         ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_u32, _item) in (0_u32..).zip(slice.into_iter())`
+   |         ^^^^^^^^^^^^^^^^^^ help: consider using: `for (idx_u32, _item) in (0_u32..).zip(slice.iter())`
    |
    = note: `idx_u32` is of type `u32`, making it ineligible for `Iterator::enumerate`
 
index 692d2ca675f91ac6712d46be511934876151e9bd..74d0e5290282aff21105c871e8ba6223477e862b 100644 (file)
@@ -10,6 +10,12 @@ fn stderr() -> String {
     String::new()
 }
 
+macro_rules! one {
+    () => {
+        1
+    };
+}
+
 fn main() {
     // these should warn
     {
@@ -24,6 +30,12 @@ fn main() {
         // including newlines
         println!("test\ntest");
         eprintln!("test\ntest");
+
+        let value = 1;
+        eprintln!("with {}", value);
+        eprintln!("with {} {}", 2, value);
+        eprintln!("with {value}");
+        eprintln!("macro arg {}", one!());
     }
     // these should not warn, different destination
     {
index 455c5ef55d05c4209be525017565edc7706f26be..e7a698d3e012d35049febcde9222b519904e06e8 100644 (file)
@@ -10,6 +10,12 @@ fn stderr() -> String {
     String::new()
 }
 
+macro_rules! one {
+    () => {
+        1
+    };
+}
+
 fn main() {
     // these should warn
     {
@@ -24,6 +30,12 @@ fn main() {
         // including newlines
         writeln!(std::io::stdout(), "test\ntest").unwrap();
         writeln!(std::io::stderr(), "test\ntest").unwrap();
+
+        let value = 1;
+        writeln!(std::io::stderr(), "with {}", value).unwrap();
+        writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap();
+        writeln!(std::io::stderr(), "with {value}").unwrap();
+        writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap();
     }
     // these should not warn, different destination
     {
index 9feef9c0dc8443cb0ef33f4df01e59a9110bea1c..29ae0cdece2499e6466a957b8409f1faf007397b 100644 (file)
@@ -1,5 +1,5 @@
 error: use of `write!(stdout(), ...).unwrap()`
-  --> $DIR/explicit_write.rs:17:9
+  --> $DIR/explicit_write.rs:23:9
    |
 LL |         write!(std::io::stdout(), "test").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")`
@@ -7,46 +7,70 @@ LL |         write!(std::io::stdout(), "test").unwrap();
    = note: `-D clippy::explicit-write` implied by `-D warnings`
 
 error: use of `write!(stderr(), ...).unwrap()`
-  --> $DIR/explicit_write.rs:18:9
+  --> $DIR/explicit_write.rs:24:9
    |
 LL |         write!(std::io::stderr(), "test").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")`
 
 error: use of `writeln!(stdout(), ...).unwrap()`
-  --> $DIR/explicit_write.rs:19:9
+  --> $DIR/explicit_write.rs:25:9
    |
 LL |         writeln!(std::io::stdout(), "test").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test")`
 
 error: use of `writeln!(stderr(), ...).unwrap()`
-  --> $DIR/explicit_write.rs:20:9
+  --> $DIR/explicit_write.rs:26:9
    |
 LL |         writeln!(std::io::stderr(), "test").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test")`
 
 error: use of `stdout().write_fmt(...).unwrap()`
-  --> $DIR/explicit_write.rs:21:9
+  --> $DIR/explicit_write.rs:27:9
    |
 LL |         std::io::stdout().write_fmt(format_args!("test")).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `print!("test")`
 
 error: use of `stderr().write_fmt(...).unwrap()`
-  --> $DIR/explicit_write.rs:22:9
+  --> $DIR/explicit_write.rs:28:9
    |
 LL |         std::io::stderr().write_fmt(format_args!("test")).unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprint!("test")`
 
 error: use of `writeln!(stdout(), ...).unwrap()`
-  --> $DIR/explicit_write.rs:25:9
+  --> $DIR/explicit_write.rs:31:9
    |
 LL |         writeln!(std::io::stdout(), "test/ntest").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `println!("test/ntest")`
 
 error: use of `writeln!(stderr(), ...).unwrap()`
-  --> $DIR/explicit_write.rs:26:9
+  --> $DIR/explicit_write.rs:32:9
    |
 LL |         writeln!(std::io::stderr(), "test/ntest").unwrap();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("test/ntest")`
 
-error: aborting due to 8 previous errors
+error: use of `writeln!(stderr(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:35:9
+   |
+LL |         writeln!(std::io::stderr(), "with {}", value).unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {}", value)`
+
+error: use of `writeln!(stderr(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:36:9
+   |
+LL |         writeln!(std::io::stderr(), "with {} {}", 2, value).unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {} {}", 2, value)`
+
+error: use of `writeln!(stderr(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:37:9
+   |
+LL |         writeln!(std::io::stderr(), "with {value}").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("with {value}")`
+
+error: use of `writeln!(stderr(), ...).unwrap()`
+  --> $DIR/explicit_write.rs:38:9
+   |
+LL |         writeln!(std::io::stderr(), "macro arg {}", one!()).unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `eprintln!("macro arg {}", one!())`
+
+error: aborting due to 12 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_write_non_rustfix.rs b/src/tools/clippy/tests/ui/explicit_write_non_rustfix.rs
deleted file mode 100644 (file)
index f21e8ef..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#![allow(unused_imports, clippy::blacklisted_name)]
-#![warn(clippy::explicit_write)]
-
-fn main() {
-    use std::io::Write;
-    let bar = "bar";
-    writeln!(std::io::stderr(), "foo {}", bar).unwrap();
-}
diff --git a/src/tools/clippy/tests/ui/explicit_write_non_rustfix.stderr b/src/tools/clippy/tests/ui/explicit_write_non_rustfix.stderr
deleted file mode 100644 (file)
index b94ec64..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error: use of `writeln!(stderr(), ...).unwrap()`
-  --> $DIR/explicit_write_non_rustfix.rs:7:5
-   |
-LL |     writeln!(std::io::stderr(), "foo {}", bar).unwrap();
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::explicit-write` implied by `-D warnings`
-   = help: consider using `eprintln!` instead
-
-error: aborting due to previous error
-
index 924c02a4054d4022ef54225853514053b1b59980..c3a36dcabd1a9392278988dd9150ddd69a847649 100644 (file)
@@ -1,5 +1,7 @@
 // run-rustfix
+
 #![allow(unused_mut, clippy::from_iter_instead_of_collect)]
+#![warn(clippy::unwrap_used)]
 #![deny(clippy::get_unwrap)]
 
 use std::collections::BTreeMap;
@@ -37,6 +39,7 @@ fn main() {
         let _ = &some_vecdeque[0];
         let _ = &some_hashmap[&1];
         let _ = &some_btreemap[&1];
+        #[allow(clippy::unwrap_used)]
         let _ = false_positive.get(0).unwrap();
         // Test with deref
         let _: u8 = boxed_slice[1];
@@ -49,9 +52,12 @@ fn main() {
         some_vec[0] = 1;
         some_vecdeque[0] = 1;
         // Check false positives
-        *some_hashmap.get_mut(&1).unwrap() = 'b';
-        *some_btreemap.get_mut(&1).unwrap() = 'b';
-        *false_positive.get_mut(0).unwrap() = 1;
+        #[allow(clippy::unwrap_used)]
+        {
+            *some_hashmap.get_mut(&1).unwrap() = 'b';
+            *some_btreemap.get_mut(&1).unwrap() = 'b';
+            *false_positive.get_mut(0).unwrap() = 1;
+        }
     }
 
     {
index c0c37bb7206631e48334b79ac731c178f25dde72..d77a202aa39c3455026a095bd64e71b56c13fa40 100644 (file)
@@ -1,5 +1,7 @@
 // run-rustfix
+
 #![allow(unused_mut, clippy::from_iter_instead_of_collect)]
+#![warn(clippy::unwrap_used)]
 #![deny(clippy::get_unwrap)]
 
 use std::collections::BTreeMap;
@@ -37,6 +39,7 @@ fn main() {
         let _ = some_vecdeque.get(0).unwrap();
         let _ = some_hashmap.get(&1).unwrap();
         let _ = some_btreemap.get(&1).unwrap();
+        #[allow(clippy::unwrap_used)]
         let _ = false_positive.get(0).unwrap();
         // Test with deref
         let _: u8 = *boxed_slice.get(1).unwrap();
@@ -49,9 +52,12 @@ fn main() {
         *some_vec.get_mut(0).unwrap() = 1;
         *some_vecdeque.get_mut(0).unwrap() = 1;
         // Check false positives
-        *some_hashmap.get_mut(&1).unwrap() = 'b';
-        *some_btreemap.get_mut(&1).unwrap() = 'b';
-        *false_positive.get_mut(0).unwrap() = 1;
+        #[allow(clippy::unwrap_used)]
+        {
+            *some_hashmap.get_mut(&1).unwrap() = 'b';
+            *some_btreemap.get_mut(&1).unwrap() = 'b';
+            *false_positive.get_mut(0).unwrap() = 1;
+        }
     }
 
     {
index 76a098df82aa199adb0186eb098b0e540fc6ba91..cb5f44fbd59ee6114a6f339a533c93cf24dbd5a9 100644 (file)
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:34:17
+  --> $DIR/get_unwrap.rs:36:17
    |
 LL |         let _ = boxed_slice.get(1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&boxed_slice[1]`
    |
 note: the lint level is defined here
-  --> $DIR/get_unwrap.rs:3:9
+  --> $DIR/get_unwrap.rs:5:9
    |
 LL | #![deny(clippy::get_unwrap)]
    |         ^^^^^^^^^^^^^^^^^^
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:36:17
+   |
+LL |         let _ = boxed_slice.get(1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unwrap-used` implied by `-D warnings`
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:35:17
+  --> $DIR/get_unwrap.rs:37:17
    |
 LL |         let _ = some_slice.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_slice[0]`
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:37:17
+   |
+LL |         let _ = some_slice.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:36:17
+  --> $DIR/get_unwrap.rs:38:17
    |
 LL |         let _ = some_vec.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vec[0]`
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:38:17
+   |
+LL |         let _ = some_vec.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:37:17
+  --> $DIR/get_unwrap.rs:39:17
    |
 LL |         let _ = some_vecdeque.get(0).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_vecdeque[0]`
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:39:17
+   |
+LL |         let _ = some_vecdeque.get(0).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get().unwrap()` on a HashMap. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:38:17
+  --> $DIR/get_unwrap.rs:40:17
    |
 LL |         let _ = some_hashmap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_hashmap[&1]`
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:40:17
+   |
+LL |         let _ = some_hashmap.get(&1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get().unwrap()` on a BTreeMap. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:39:17
+  --> $DIR/get_unwrap.rs:41:17
    |
 LL |         let _ = some_btreemap.get(&1).unwrap();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&some_btreemap[&1]`
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:41:17
+   |
+LL |         let _ = some_btreemap.get(&1).unwrap();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:42:21
+  --> $DIR/get_unwrap.rs:45:21
    |
 LL |         let _: u8 = *boxed_slice.get(1).unwrap();
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[1]`
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:45:22
+   |
+LL |         let _: u8 = *boxed_slice.get(1).unwrap();
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:47:9
+  --> $DIR/get_unwrap.rs:50:9
    |
 LL |         *boxed_slice.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `boxed_slice[0]`
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:50:10
+   |
+LL |         *boxed_slice.get_mut(0).unwrap() = 1;
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get_mut().unwrap()` on a slice. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:48:9
+  --> $DIR/get_unwrap.rs:51:9
    |
 LL |         *some_slice.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_slice[0]`
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:51:10
+   |
+LL |         *some_slice.get_mut(0).unwrap() = 1;
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:49:9
+  --> $DIR/get_unwrap.rs:52:9
    |
 LL |         *some_vec.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0]`
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:52:10
+   |
+LL |         *some_vec.get_mut(0).unwrap() = 1;
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get_mut().unwrap()` on a VecDeque. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:50:9
+  --> $DIR/get_unwrap.rs:53:9
    |
 LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vecdeque[0]`
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:53:10
+   |
+LL |         *some_vecdeque.get_mut(0).unwrap() = 1;
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:59:17
+  --> $DIR/get_unwrap.rs:65:17
    |
 LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
 
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:65:17
+   |
+LL |         let _ = some_vec.get(0..1).unwrap().to_vec();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
 error: called `.get_mut().unwrap()` on a Vec. Using `[]` is more clear and more concise
-  --> $DIR/get_unwrap.rs:60:17
+  --> $DIR/get_unwrap.rs:66:17
    |
 LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `some_vec[0..1]`
 
-error: aborting due to 13 previous errors
+error: used `unwrap()` on `an Option` value
+  --> $DIR/get_unwrap.rs:66:17
+   |
+LL |         let _ = some_vec.get_mut(0..1).unwrap().to_vec();
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if you don't want to handle the `None` case gracefully, consider using `expect()` to provide a better panic message
+
+error: aborting due to 26 previous errors
 
index 6c2a25c37d8d73f6a1bd5960dbe8a8db954c91f7..d0bc640db88994c7c59312de4dfcb001aa984a78 100644 (file)
@@ -6,6 +6,12 @@
 #![warn(clippy::manual_assert)]
 #![allow(clippy::nonminimal_bool)]
 
+macro_rules! one {
+    () => {
+        1
+    };
+}
+
 fn main() {
     let a = vec![1, 2, 3];
     let c = Some(2);
@@ -42,4 +48,5 @@ fn main() {
     assert!(!(a.is_empty() && !b.is_empty()), "panic3");
     assert!(!(b.is_empty() || a.is_empty()), "panic4");
     assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+    assert!(!a.is_empty(), "with expansion {}", one!());
 }
index 77511631e449a9c4768780d531694aafdf144909..a0f31afd6ebfe5986ff06e2f716b539e713b1535 100644 (file)
@@ -1,5 +1,5 @@
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:24:5
+  --> $DIR/manual_assert.rs:30:5
    |
 LL | /     if !a.is_empty() {
 LL | |         panic!("qaqaq{:?}", a);
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::manual-assert` implied by `-D warnings`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:27:5
+  --> $DIR/manual_assert.rs:33:5
    |
 LL | /     if !a.is_empty() {
 LL | |         panic!("qwqwq");
@@ -17,7 +17,7 @@ LL | |     }
    | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:44:5
+  --> $DIR/manual_assert.rs:50:5
    |
 LL | /     if b.is_empty() {
 LL | |         panic!("panic1");
@@ -25,7 +25,7 @@ LL | |     }
    | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:47:5
+  --> $DIR/manual_assert.rs:53:5
    |
 LL | /     if b.is_empty() && a.is_empty() {
 LL | |         panic!("panic2");
@@ -33,7 +33,7 @@ LL | |     }
    | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:50:5
+  --> $DIR/manual_assert.rs:56:5
    |
 LL | /     if a.is_empty() && !b.is_empty() {
 LL | |         panic!("panic3");
@@ -41,7 +41,7 @@ LL | |     }
    | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:53:5
+  --> $DIR/manual_assert.rs:59:5
    |
 LL | /     if b.is_empty() || a.is_empty() {
 LL | |         panic!("panic4");
@@ -49,12 +49,20 @@ LL | |     }
    | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:56:5
+  --> $DIR/manual_assert.rs:62:5
    |
 LL | /     if a.is_empty() || !b.is_empty() {
 LL | |         panic!("panic5");
 LL | |     }
    | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
 
-error: aborting due to 7 previous errors
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:65:5
+   |
+LL | /     if a.is_empty() {
+LL | |         panic!("with expansion {}", one!())
+LL | |     }
+   | |_____^ help: try: `assert!(!a.is_empty(), "with expansion {}", one!());`
+
+error: aborting due to 8 previous errors
 
index 6c2a25c37d8d73f6a1bd5960dbe8a8db954c91f7..d0bc640db88994c7c59312de4dfcb001aa984a78 100644 (file)
@@ -6,6 +6,12 @@
 #![warn(clippy::manual_assert)]
 #![allow(clippy::nonminimal_bool)]
 
+macro_rules! one {
+    () => {
+        1
+    };
+}
+
 fn main() {
     let a = vec![1, 2, 3];
     let c = Some(2);
@@ -42,4 +48,5 @@ fn main() {
     assert!(!(a.is_empty() && !b.is_empty()), "panic3");
     assert!(!(b.is_empty() || a.is_empty()), "panic4");
     assert!(!(a.is_empty() || !b.is_empty()), "panic5");
+    assert!(!a.is_empty(), "with expansion {}", one!());
 }
index 77511631e449a9c4768780d531694aafdf144909..a0f31afd6ebfe5986ff06e2f716b539e713b1535 100644 (file)
@@ -1,5 +1,5 @@
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:24:5
+  --> $DIR/manual_assert.rs:30:5
    |
 LL | /     if !a.is_empty() {
 LL | |         panic!("qaqaq{:?}", a);
@@ -9,7 +9,7 @@ LL | |     }
    = note: `-D clippy::manual-assert` implied by `-D warnings`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:27:5
+  --> $DIR/manual_assert.rs:33:5
    |
 LL | /     if !a.is_empty() {
 LL | |         panic!("qwqwq");
@@ -17,7 +17,7 @@ LL | |     }
    | |_____^ help: try: `assert!(a.is_empty(), "qwqwq");`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:44:5
+  --> $DIR/manual_assert.rs:50:5
    |
 LL | /     if b.is_empty() {
 LL | |         panic!("panic1");
@@ -25,7 +25,7 @@ LL | |     }
    | |_____^ help: try: `assert!(!b.is_empty(), "panic1");`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:47:5
+  --> $DIR/manual_assert.rs:53:5
    |
 LL | /     if b.is_empty() && a.is_empty() {
 LL | |         panic!("panic2");
@@ -33,7 +33,7 @@ LL | |     }
    | |_____^ help: try: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:50:5
+  --> $DIR/manual_assert.rs:56:5
    |
 LL | /     if a.is_empty() && !b.is_empty() {
 LL | |         panic!("panic3");
@@ -41,7 +41,7 @@ LL | |     }
    | |_____^ help: try: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:53:5
+  --> $DIR/manual_assert.rs:59:5
    |
 LL | /     if b.is_empty() || a.is_empty() {
 LL | |         panic!("panic4");
@@ -49,12 +49,20 @@ LL | |     }
    | |_____^ help: try: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
 
 error: only a `panic!` in `if`-then statement
-  --> $DIR/manual_assert.rs:56:5
+  --> $DIR/manual_assert.rs:62:5
    |
 LL | /     if a.is_empty() || !b.is_empty() {
 LL | |         panic!("panic5");
 LL | |     }
    | |_____^ help: try: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
 
-error: aborting due to 7 previous errors
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:65:5
+   |
+LL | /     if a.is_empty() {
+LL | |         panic!("with expansion {}", one!())
+LL | |     }
+   | |_____^ help: try: `assert!(!a.is_empty(), "with expansion {}", one!());`
+
+error: aborting due to 8 previous errors
 
index d3e0897488f0c1ce8f315c4f8e4cf367e2f6ee76..027747d8386319431e82d9a836cf095063d2f2b9 100644 (file)
@@ -6,6 +6,12 @@
 #![warn(clippy::manual_assert)]
 #![allow(clippy::nonminimal_bool)]
 
+macro_rules! one {
+    () => {
+        1
+    };
+}
+
 fn main() {
     let a = vec![1, 2, 3];
     let c = Some(2);
@@ -56,4 +62,7 @@ fn main() {
     if a.is_empty() || !b.is_empty() {
         panic!("panic5");
     }
+    if a.is_empty() {
+        panic!("with expansion {}", one!())
+    }
 }
index 7db6b730963c94f6399e4ff2a69921b2a0d3ff61..6c5232ec5f55b7d0e59dec9373f55b4f91cd0f16 100644 (file)
@@ -26,8 +26,6 @@ fn main() {
     }
 
     // Test for loop over an implicit reference
-    // Note: if `clippy::manual_flatten` is made autofixable, this case will
-    // lead to a follow-up lint `clippy::into_iter_on_ref`
     let z = &y;
     for n in z {
         if let Ok(n) = n {
index be5f8a1d818847b8ce672df247d5e218d80bbd71..392e1a39393754214ce44a4c04bdc222b85cb6b3 100644 (file)
@@ -63,10 +63,10 @@ LL | |         }
    | |_________^
 
 error: unnecessary `if let` since only the `Ok` variant of the iterator element is used
-  --> $DIR/manual_flatten.rs:32:5
+  --> $DIR/manual_flatten.rs:30:5
    |
 LL |       for n in z {
-   |       ^        - help: try: `z.into_iter().flatten()`
+   |       ^        - help: try: `z.iter().flatten()`
    |  _____|
    | |
 LL | |         if let Ok(n) = n {
@@ -76,7 +76,7 @@ LL | |     }
    | |_____^
    |
 help: ...and remove the `if let` statement in the for loop
-  --> $DIR/manual_flatten.rs:33:9
+  --> $DIR/manual_flatten.rs:31:9
    |
 LL | /         if let Ok(n) = n {
 LL | |             println!("{}", n);
@@ -84,7 +84,7 @@ LL | |         }
    | |_________^
 
 error: unnecessary `if let` since only the `Some` variant of the iterator element is used
-  --> $DIR/manual_flatten.rs:41:5
+  --> $DIR/manual_flatten.rs:39:5
    |
 LL |       for n in z {
    |       ^        - help: try: `z.flatten()`
@@ -97,7 +97,7 @@ LL | |     }
    | |_____^
    |
 help: ...and remove the `if let` statement in the for loop
-  --> $DIR/manual_flatten.rs:42:9
+  --> $DIR/manual_flatten.rs:40:9
    |
 LL | /         if let Some(m) = n {
 LL | |             println!("{}", m);
@@ -105,7 +105,7 @@ LL | |         }
    | |_________^
 
 error: unnecessary `if let` since only the `Some` variant of the iterator element is used
-  --> $DIR/manual_flatten.rs:74:5
+  --> $DIR/manual_flatten.rs:72:5
    |
 LL |       for n in &vec_of_ref {
    |       ^        ----------- help: try: `vec_of_ref.iter().copied().flatten()`
@@ -118,7 +118,7 @@ LL | |     }
    | |_____^
    |
 help: ...and remove the `if let` statement in the for loop
-  --> $DIR/manual_flatten.rs:75:9
+  --> $DIR/manual_flatten.rs:73:9
    |
 LL | /         if let Some(n) = n {
 LL | |             println!("{:?}", n);
@@ -126,10 +126,10 @@ LL | |         }
    | |_________^
 
 error: unnecessary `if let` since only the `Some` variant of the iterator element is used
-  --> $DIR/manual_flatten.rs:81:5
+  --> $DIR/manual_flatten.rs:79:5
    |
 LL |       for n in vec_of_ref {
-   |       ^        ---------- help: try: `vec_of_ref.into_iter().copied().flatten()`
+   |       ^        ---------- help: try: `vec_of_ref.iter().copied().flatten()`
    |  _____|
    | |
 LL | |         if let Some(n) = n {
@@ -139,7 +139,7 @@ LL | |     }
    | |_____^
    |
 help: ...and remove the `if let` statement in the for loop
-  --> $DIR/manual_flatten.rs:82:9
+  --> $DIR/manual_flatten.rs:80:9
    |
 LL | /         if let Some(n) = n {
 LL | |             println!("{:?}", n);
@@ -147,10 +147,10 @@ LL | |         }
    | |_________^
 
 error: unnecessary `if let` since only the `Some` variant of the iterator element is used
-  --> $DIR/manual_flatten.rs:88:5
+  --> $DIR/manual_flatten.rs:86:5
    |
 LL |       for n in slice_of_ref {
-   |       ^        ------------ help: try: `slice_of_ref.into_iter().copied().flatten()`
+   |       ^        ------------ help: try: `slice_of_ref.iter().copied().flatten()`
    |  _____|
    | |
 LL | |         if let Some(n) = n {
@@ -160,7 +160,7 @@ LL | |     }
    | |_____^
    |
 help: ...and remove the `if let` statement in the for loop
-  --> $DIR/manual_flatten.rs:89:9
+  --> $DIR/manual_flatten.rs:87:9
    |
 LL | /         if let Some(n) = n {
 LL | |             println!("{:?}", n);
index b856f1375d303ad11520922ae7a78fc9e359c0be..efeb5cf5b2b25aedb3ad0cb7a06edc97c84ad29b 100644 (file)
@@ -64,9 +64,9 @@ fn main() {
     *x = 5;
 
     let s = String::new();
-    let _ = s.len();
-    let _ = s.capacity();
-    let _ = s.capacity();
+    // let _ = (&s).len();
+    // let _ = (&s).capacity();
+    // let _ = (&&s).capacity();
 
     let x = (1, 2);
     let _ = x.0;
index 0bfe222a3dc170ee85bf20f1e2fadb2766891560..3e416a0eb84aaa6ea38a285f0cefa7ca911e2904 100644 (file)
@@ -64,9 +64,9 @@ fn main() {
     *x = 5;
 
     let s = String::new();
-    let _ = (&s).len();
-    let _ = (&s).capacity();
-    let _ = (&&s).capacity();
+    // let _ = (&s).len();
+    // let _ = (&s).capacity();
+    // let _ = (&&s).capacity();
 
     let x = (1, 2);
     let _ = (&x).0;
index b90e8448db0a3ac377949addf360f56441a5b401..05591ce4117b2e3937fca808cd4adaab9c218ff7 100644 (file)
@@ -84,24 +84,6 @@ error: this expression creates a reference which is immediately dereferenced by
 LL |     let y: &mut i32 = &mut &mut x;
    |                       ^^^^^^^^^^^ help: change this to: `x`
 
-error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:67:13
-   |
-LL |     let _ = (&s).len();
-   |             ^^^^ help: change this to: `s`
-
-error: this expression borrows a value the compiler would automatically borrow
-  --> $DIR/needless_borrow.rs:68:13
-   |
-LL |     let _ = (&s).capacity();
-   |             ^^^^ help: change this to: `s`
-
-error: this expression creates a reference which is immediately dereferenced by the compiler
-  --> $DIR/needless_borrow.rs:69:13
-   |
-LL |     let _ = (&&s).capacity();
-   |             ^^^^^ help: change this to: `s`
-
 error: this expression borrows a value the compiler would automatically borrow
   --> $DIR/needless_borrow.rs:72:13
    |
@@ -114,5 +96,5 @@ error: this expression borrows a value the compiler would automatically borrow
 LL |     let _ = unsafe { (&*x).0 };
    |                      ^^^^^ help: change this to: `(*x)`
 
-error: aborting due to 19 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/non_expressive_names.stdout b/src/tools/clippy/tests/ui/non_expressive_names.stdout
deleted file mode 100644 (file)
index e69de29..0000000
index ed72423780821792ae61ea24d6fb322547465e16..00b99da2631c630aa1ef6e227e50c4c7f678f027 100644 (file)
@@ -180,3 +180,9 @@ fn dyn_fn_requires_vec(v: &Vec<u32>, f: &dyn Fn(&Vec<u32>)) {
 // No error for types behind an alias (#7699)
 type A = Vec<u8>;
 fn aliased(a: &A) {}
+
+// Issue #8366
+pub trait Trait {
+    fn f(v: &mut Vec<i32>);
+    fn f2(v: &mut Vec<i32>) {}
+}
index b1819e08d53bf5dc9054e41cde25c580077082c5..bd371888046361ceea6c5ce3b9c866301df7e5a4 100644 (file)
@@ -145,6 +145,84 @@ impl Eq for Bar {}
     };
 }
 
+// See: issue #8282
+fn ranges() {
+    enum E {
+        V,
+    }
+    let x = (Some(E::V), Some(42));
+
+    // Don't lint, because the `E` enum can be extended with additional fields later. Thus, the
+    // proposed replacement to `if let Some(E::V)` may hide non-exhaustive warnings that appeared
+    // because of `match` construction.
+    match x {
+        (Some(E::V), _) => {},
+        (None, _) => {},
+    }
+
+    // lint
+    match x {
+        (Some(_), _) => {},
+        (None, _) => {},
+    }
+
+    // lint
+    match x {
+        (Some(E::V), _) => todo!(),
+        (_, _) => {},
+    }
+
+    // lint
+    match (Some(42), Some(E::V), Some(42)) {
+        (.., Some(E::V), _) => {},
+        (..) => {},
+    }
+
+    // Don't lint, see above.
+    match (Some(E::V), Some(E::V), Some(E::V)) {
+        (.., Some(E::V), _) => {},
+        (.., None, _) => {},
+    }
+
+    // Don't lint, see above.
+    match (Some(E::V), Some(E::V), Some(E::V)) {
+        (Some(E::V), ..) => {},
+        (None, ..) => {},
+    }
+
+    // Don't lint, see above.
+    match (Some(E::V), Some(E::V), Some(E::V)) {
+        (_, Some(E::V), ..) => {},
+        (_, None, ..) => {},
+    }
+}
+
+fn skip_type_aliases() {
+    enum OptionEx {
+        Some(i32),
+        None,
+    }
+    enum ResultEx {
+        Err(i32),
+        Ok(i32),
+    }
+
+    use OptionEx::{None, Some};
+    use ResultEx::{Err, Ok};
+
+    // don't lint
+    match Err(42) {
+        Ok(_) => dummy(),
+        Err(_) => (),
+    };
+
+    // don't lint
+    match Some(1i32) {
+        Some(_) => dummy(),
+        None => (),
+    };
+}
+
 macro_rules! single_match {
     ($num:literal) => {
         match $num {
index c261b5111c8bf3edb40c7adf333968aadcb2b555..318faf2571758a1c5c7b7069207c014f645c8f90 100644 (file)
@@ -38,15 +38,6 @@ LL | |         _ => {},
 LL | |     };
    | |_____^ help: try this: `if let (2..=3, 7..=9) = z { dummy() }`
 
-error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match.rs:54:5
-   |
-LL | /     match x {
-LL | |         Some(y) => dummy(),
-LL | |         None => (),
-LL | |     };
-   | |_____^ help: try this: `if let Some(y) = x { dummy() }`
-
 error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
   --> $DIR/single_match.rs:59:5
    |
@@ -128,5 +119,32 @@ LL | |         _ => (),
 LL | |     };
    | |_____^ help: try this: `if let None = x { println!() }`
 
-error: aborting due to 13 previous errors
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:164:5
+   |
+LL | /     match x {
+LL | |         (Some(_), _) => {},
+LL | |         (None, _) => {},
+LL | |     }
+   | |_____^ help: try this: `if let (Some(_), _) = x {}`
+
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:170:5
+   |
+LL | /     match x {
+LL | |         (Some(E::V), _) => todo!(),
+LL | |         (_, _) => {},
+LL | |     }
+   | |_____^ help: try this: `if let (Some(E::V), _) = x { todo!() }`
+
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+  --> $DIR/single_match.rs:176:5
+   |
+LL | /     match (Some(42), Some(E::V), Some(42)) {
+LL | |         (.., Some(E::V), _) => {},
+LL | |         (..) => {},
+LL | |     }
+   | |_____^ help: try this: `if let (.., Some(E::V), _) = (Some(42), Some(E::V), Some(42)) {}`
+
+error: aborting due to 15 previous errors
 
index c61d80a905c9f0d0d5b097641c4d6719c7c8dc08..21ea704b62ab5c9134fcccdcda1d853a27af1c42 100644 (file)
@@ -19,45 +19,5 @@ LL +         None
 LL +     }
    |
 
-error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match_else.rs:70:5
-   |
-LL | /     match Some(1) {
-LL | |         Some(a) => println!("${:?}", a),
-LL | |         None => {
-LL | |             println!("else block");
-LL | |             return
-LL | |         },
-LL | |     }
-   | |_____^
-   |
-help: try this
-   |
-LL ~     if let Some(a) = Some(1) { println!("${:?}", a) } else {
-LL +         println!("else block");
-LL +         return
-LL +     }
-   |
-
-error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
-  --> $DIR/single_match_else.rs:79:5
-   |
-LL | /     match Some(1) {
-LL | |         Some(a) => println!("${:?}", a),
-LL | |         None => {
-LL | |             println!("else block");
-LL | |             return;
-LL | |         },
-LL | |     }
-   | |_____^
-   |
-help: try this
-   |
-LL ~     if let Some(a) = Some(1) { println!("${:?}", a) } else {
-LL +         println!("else block");
-LL +         return;
-LL +     }
-   |
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
index 7dfcf9c91e486a8b4bd7273660f4b358b99611c1..983fac7afe69a58c42ea43c4a1cfc7881a9b3bd7 100644 (file)
@@ -7,6 +7,10 @@ fn main() {}
 fn starts_with() {
     "".starts_with(' ');
     !"".starts_with(' ');
+
+    // Ensure that suggestion is escaped correctly
+    "".starts_with('\n');
+    !"".starts_with('\n');
 }
 
 fn chars_cmp_with_unwrap() {
@@ -31,7 +35,7 @@ fn chars_cmp_with_unwrap() {
         // !s.ends_with('o')
         // Nothing here
     }
-    if !s.ends_with('o') {
+    if !s.ends_with('\n') {
         // !s.ends_with('o')
         // Nothing here
     }
@@ -43,4 +47,8 @@ fn ends_with() {
     !"".ends_with(' ');
     "".ends_with(' ');
     !"".ends_with(' ');
+
+    // Ensure that suggestion is escaped correctly
+    "".ends_with('\n');
+    !"".ends_with('\n');
 }
index e48a4246354391000da93003a6347b02bafbd0cc..e3335dd2e2ef7727f6e92500fbeebb4450a47164 100644 (file)
@@ -7,6 +7,10 @@ fn main() {}
 fn starts_with() {
     "".chars().next() == Some(' ');
     Some(' ') != "".chars().next();
+
+    // Ensure that suggestion is escaped correctly
+    "".chars().next() == Some('\n');
+    Some('\n') != "".chars().next();
 }
 
 fn chars_cmp_with_unwrap() {
@@ -31,7 +35,7 @@ fn chars_cmp_with_unwrap() {
         // !s.ends_with('o')
         // Nothing here
     }
-    if s.chars().last().unwrap() != 'o' {
+    if s.chars().last().unwrap() != '\n' {
         // !s.ends_with('o')
         // Nothing here
     }
@@ -43,4 +47,8 @@ fn ends_with() {
     Some(' ') != "".chars().last();
     "".chars().next_back() == Some(' ');
     Some(' ') != "".chars().next_back();
+
+    // Ensure that suggestion is escaped correctly
+    "".chars().last() == Some('\n');
+    Some('\n') != "".chars().last();
 }
index 7c726d0e010263ffca9352d1c41325cb042e9e86..2dd9f53b8026afd215c7fdd3b436fab8e61bad21 100644 (file)
@@ -13,13 +13,25 @@ LL |     Some(' ') != "".chars().next();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".starts_with(' ')`
 
 error: you should use the `starts_with` method
-  --> $DIR/starts_ends_with.rs:14:8
+  --> $DIR/starts_ends_with.rs:12:5
+   |
+LL |     "".chars().next() == Some('/n');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".starts_with('/n')`
+
+error: you should use the `starts_with` method
+  --> $DIR/starts_ends_with.rs:13:5
+   |
+LL |     Some('/n') != "".chars().next();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".starts_with('/n')`
+
+error: you should use the `starts_with` method
+  --> $DIR/starts_ends_with.rs:18:8
    |
 LL |     if s.chars().next().unwrap() == 'f' {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.starts_with('f')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:18:8
+  --> $DIR/starts_ends_with.rs:22:8
    |
 LL |     if s.chars().next_back().unwrap() == 'o' {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')`
@@ -27,52 +39,64 @@ LL |     if s.chars().next_back().unwrap() == 'o' {
    = note: `-D clippy::chars-last-cmp` implied by `-D warnings`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:22:8
+  --> $DIR/starts_ends_with.rs:26:8
    |
 LL |     if s.chars().last().unwrap() == 'o' {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `s.ends_with('o')`
 
 error: you should use the `starts_with` method
-  --> $DIR/starts_ends_with.rs:26:8
+  --> $DIR/starts_ends_with.rs:30:8
    |
 LL |     if s.chars().next().unwrap() != 'f' {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.starts_with('f')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:30:8
+  --> $DIR/starts_ends_with.rs:34:8
    |
 LL |     if s.chars().next_back().unwrap() != 'o' {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:34:8
+  --> $DIR/starts_ends_with.rs:38:8
    |
-LL |     if s.chars().last().unwrap() != 'o' {
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('o')`
+LL |     if s.chars().last().unwrap() != '/n' {
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!s.ends_with('/n')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:42:5
+  --> $DIR/starts_ends_with.rs:46:5
    |
 LL |     "".chars().last() == Some(' ');
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:43:5
+  --> $DIR/starts_ends_with.rs:47:5
    |
 LL |     Some(' ') != "".chars().last();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:44:5
+  --> $DIR/starts_ends_with.rs:48:5
    |
 LL |     "".chars().next_back() == Some(' ');
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with(' ')`
 
 error: you should use the `ends_with` method
-  --> $DIR/starts_ends_with.rs:45:5
+  --> $DIR/starts_ends_with.rs:49:5
    |
 LL |     Some(' ') != "".chars().next_back();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with(' ')`
 
-error: aborting due to 12 previous errors
+error: you should use the `ends_with` method
+  --> $DIR/starts_ends_with.rs:52:5
+   |
+LL |     "".chars().last() == Some('/n');
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `"".ends_with('/n')`
+
+error: you should use the `ends_with` method
+  --> $DIR/starts_ends_with.rs:53:5
+   |
+LL |     Some('/n') != "".chars().last();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: like this: `!"".ends_with('/n')`
+
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.rs b/src/tools/clippy/tests/ui/transmute_undefined_repr.rs
new file mode 100644 (file)
index 0000000..7153994
--- /dev/null
@@ -0,0 +1,44 @@
+#![warn(clippy::transmute_undefined_repr)]
+#![allow(clippy::unit_arg)]
+
+fn value<T>() -> T {
+    unimplemented!()
+}
+
+struct Empty;
+struct Ty<T>(T);
+struct Ty2<T, U>(T, U);
+
+#[repr(C)]
+struct Ty2C<T, U>(T, U);
+
+fn main() {
+    unsafe {
+        let _: () = core::mem::transmute(value::<Empty>());
+        let _: Empty = core::mem::transmute(value::<()>());
+
+        let _: Ty<u32> = core::mem::transmute(value::<u32>());
+        let _: Ty<u32> = core::mem::transmute(value::<u32>());
+
+        let _: Ty2C<u32, i32> = core::mem::transmute(value::<Ty2<u32, i32>>()); // Lint, Ty2 is unordered
+        let _: Ty2<u32, i32> = core::mem::transmute(value::<Ty2C<u32, i32>>()); // Lint, Ty2 is unordered
+
+        let _: Ty2<u32, i32> = core::mem::transmute(value::<Ty<Ty2<u32, i32>>>()); // Ok, Ty2 types are the same
+        let _: Ty<Ty2<u32, i32>> = core::mem::transmute(value::<Ty2<u32, i32>>()); // Ok, Ty2 types are the same
+
+        let _: Ty2<u32, f32> = core::mem::transmute(value::<Ty<Ty2<u32, i32>>>()); // Lint, different Ty2 instances
+        let _: Ty<Ty2<u32, i32>> = core::mem::transmute(value::<Ty2<u32, f32>>()); // Lint, different Ty2 instances
+
+        let _: Ty<&()> = core::mem::transmute(value::<&()>());
+        let _: &() = core::mem::transmute(value::<Ty<&()>>());
+
+        let _: &Ty2<u32, f32> = core::mem::transmute(value::<Ty<&Ty2<u32, i32>>>()); // Lint, different Ty2 instances
+        let _: Ty<&Ty2<u32, i32>> = core::mem::transmute(value::<&Ty2<u32, f32>>()); // Lint, different Ty2 instances
+
+        let _: Ty<usize> = core::mem::transmute(value::<&Ty2<u32, i32>>()); // Ok, pointer to usize conversion
+        let _: &Ty2<u32, i32> = core::mem::transmute(value::<Ty<usize>>()); // Ok, pointer to usize conversion
+
+        let _: Ty<[u8; 8]> = core::mem::transmute(value::<Ty2<u32, i32>>()); // Ok, transmute to byte array
+        let _: Ty2<u32, i32> = core::mem::transmute(value::<Ty<[u8; 8]>>()); // Ok, transmute from byte array
+    }
+}
diff --git a/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr b/src/tools/clippy/tests/ui/transmute_undefined_repr.stderr
new file mode 100644 (file)
index 0000000..040c63c
--- /dev/null
@@ -0,0 +1,44 @@
+error: transmute from `Ty2<u32, i32>` which has an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:23:33
+   |
+LL |         let _: Ty2C<u32, i32> = core::mem::transmute(value::<Ty2<u32, i32>>()); // Lint, Ty2 is unordered
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::transmute-undefined-repr` implied by `-D warnings`
+
+error: transmute into `Ty2<u32, i32>` which has an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:24:32
+   |
+LL |         let _: Ty2<u32, i32> = core::mem::transmute(value::<Ty2C<u32, i32>>()); // Lint, Ty2 is unordered
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `Ty<Ty2<u32, i32>>` to `Ty2<u32, f32>`, both of which have an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:29:32
+   |
+LL |         let _: Ty2<u32, f32> = core::mem::transmute(value::<Ty<Ty2<u32, i32>>>()); // Lint, different Ty2 instances
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: two instances of the same generic type (`Ty2`) may have different layouts
+
+error: transmute from `Ty2<u32, f32>` to `Ty<Ty2<u32, i32>>`, both of which have an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:30:36
+   |
+LL |         let _: Ty<Ty2<u32, i32>> = core::mem::transmute(value::<Ty2<u32, f32>>()); // Lint, different Ty2 instances
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: two instances of the same generic type (`Ty2`) may have different layouts
+
+error: transmute to `&Ty2<u32, f32>` which has an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:35:33
+   |
+LL |         let _: &Ty2<u32, f32> = core::mem::transmute(value::<Ty<&Ty2<u32, i32>>>()); // Lint, different Ty2 instances
+   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: transmute from `&Ty2<u32, f32>` which has an undefined layout
+  --> $DIR/transmute_undefined_repr.rs:36:37
+   |
+LL |         let _: Ty<&Ty2<u32, i32>> = core::mem::transmute(value::<&Ty2<u32, f32>>()); // Lint, different Ty2 instances
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui_test/eq_op.rs b/src/tools/clippy/tests/ui_test/eq_op.rs
deleted file mode 100644 (file)
index f2f5f1e..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-#[warn(clippy::eq_op)]
-#[test]
-fn eq_op_shouldnt_trigger_in_tests() {
-    let a = 1;
-    let result = a + 1 == 1 + a;
-    assert!(result);
-}
-
-#[test]
-fn eq_op_macros_shouldnt_trigger_in_tests() {
-    let a = 1;
-    let b = 2;
-    assert_eq!(a, a);
-    assert_eq!(a + b, b + a);
-}
index 27d59bc01f22a23f8a876862709df4ae464d8f69..da7a19139c65b3f28d019b33fbeef5ad883a7e0e 100644 (file)
@@ -922,10 +922,11 @@ pub fn make_test_description<R: Read>(
         name,
         ignore,
         should_panic,
-        allow_fail: false,
         compile_fail: false,
         no_run: false,
         test_type: test::TestType::Unknown,
+        #[cfg(bootstrap)]
+        allow_fail: false,
     }
 }
 
index 00221b07f7464182cedede3312fc7b41b0f55793..f6ddac3a65e06f74887c67d9b7f29dab79bb5075 100644 (file)
@@ -2424,7 +2424,10 @@ fn run_rustdoc_json_test(&self) {
         );
 
         if !res.status.success() {
-            self.fatal_proc_rec("jsondocck failed!", &res)
+            self.fatal_proc_rec_with_ctx("jsondocck failed!", &res, |_| {
+                println!("Rustdoc Output:");
+                proc_res.print_info();
+            })
         }
 
         let mut json_out = out_dir.join(self.testpaths.file.file_stem().unwrap());
@@ -3738,10 +3741,7 @@ pub struct ProcRes {
 }
 
 impl ProcRes {
-    pub fn fatal(&self, err: Option<&str>, on_failure: impl FnOnce()) -> ! {
-        if let Some(e) = err {
-            println!("\nerror: {}", e);
-        }
+    pub fn print_info(&self) {
         print!(
             "\
              status: {}\n\
@@ -3760,6 +3760,13 @@ pub fn fatal(&self, err: Option<&str>, on_failure: impl FnOnce()) -> ! {
             json::extract_rendered(&self.stdout),
             json::extract_rendered(&self.stderr),
         );
+    }
+
+    pub fn fatal(&self, err: Option<&str>, on_failure: impl FnOnce()) -> ! {
+        if let Some(e) = err {
+            println!("\nerror: {}", e);
+        }
+        self.print_info();
         on_failure();
         // Use resume_unwind instead of panic!() to prevent a panic message + backtrace from
         // compiletest, which is unnecessary noise.
index b8ea10f3d22778e6a96032bdecc729f8ba1b2376..d0f476955e1f79dbd2ded1263c3b2c67c8d80897 100644 (file)
@@ -231,7 +231,21 @@ fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
 
             let val = cache.get_value(&command.args[0])?;
             let results = select(&val, &command.args[1]).unwrap();
-            results.len() == expected
+            let eq = results.len() == expected;
+            if !command.negated && !eq {
+                return Err(CkError::FailedCheck(
+                    format!(
+                        "`{}` matched to `{:?}` with length {}, but expected length {}",
+                        &command.args[1],
+                        results,
+                        results.len(),
+                        expected
+                    ),
+                    command,
+                ));
+            } else {
+                eq
+            }
         }
         CommandKind::Is => {
             // @has <path> <jsonpath> <value> = check *exactly one* item matched by path, and it equals value
@@ -317,6 +331,6 @@ fn string_to_value<'a>(s: &str, cache: &'a Cache) -> Cow<'a, Value> {
             panic!("No variable: `{}`. Current state: `{:?}`", &s[1..], cache.variables)
         }))
     } else {
-        Cow::Owned(serde_json::from_str(s).unwrap())
+        Cow::Owned(serde_json::from_str(s).expect(&format!("Cannot convert `{}` to json", s)))
     }
 }
index 94e82e3d9f7664f993ea6fcb2db1e0a9a156d1df..46daaf42883f026a2e675247ae3fd3c4c6f79d12 100644 (file)
@@ -182,8 +182,9 @@ impl Checker {
     fn walk(&mut self, dir: &Path, report: &mut Report) {
         for entry in t!(dir.read_dir()).map(|e| t!(e)) {
             let path = entry.path();
-            let kind = t!(entry.file_type());
-            if kind.is_dir() {
+            // Goes through symlinks
+            let metadata = t!(fs::metadata(&path));
+            if metadata.is_dir() {
                 self.walk(&path, report);
             } else {
                 self.check(&path, report);
index deb9bfd24648d50142ab29b810175837c4718885..0db40903769f38669936c5ebb0b882b18c27f449 160000 (submodule)
@@ -1 +1 @@
-Subproject commit deb9bfd24648d50142ab29b810175837c4718885
+Subproject commit 0db40903769f38669936c5ebb0b882b18c27f449
index f37425e33c864c697af06df66e7473444605c149..3df74381f37617ec800537c11fb0c3130f5f3616 160000 (submodule)
@@ -1 +1 @@
-Subproject commit f37425e33c864c697af06df66e7473444605c149
+Subproject commit 3df74381f37617ec800537c11fb0c3130f5f3616
index 9700addc82111200a2150b9a796f62dd8e600ddf..02904e99acc3daf39b56ed18aa07e62aeb9492c5 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9700addc82111200a2150b9a796f62dd8e600ddf
+Subproject commit 02904e99acc3daf39b56ed18aa07e62aeb9492c5
index 4f73a7f634098f2f7d6846e593a083c24877fcb4..dbf5cf9650c5f4f16098a2d11979b1bf423531c3 100644 (file)
@@ -357,6 +357,8 @@ function runChecks(testFile, loaded, index) {
     var testFileContent = readFile(testFile) + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;';
     if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
         testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";
+    } else {
+        testFileContent += "exports.FILTER_CRATE = null;";
     }
     var loadedFile = loadContent(testFileContent);
 
index 69c8063f42e26693c441251b65210961d50feb88..96ab42b4719a2d2a6b3d3f798e5de2dcd60c339d 100644 (file)
@@ -5,7 +5,7 @@ edition = "2021"
 autobins = false
 
 [dependencies]
-cargo_metadata = "0.12"
+cargo_metadata = "0.14"
 regex = "1"
 lazy_static = "1"
 walkdir = "2"
index f83a5b1a2ba13f4a24a90d88df1b5d245bd77c74..52429fee46150f9c4f1acea967a6d63794fde3f3 100644 (file)
     "chrono",
     "cmake",
     "compiler_builtins",
-    "cpuid-bool",
+    "cpufeatures",
     "crc32fast",
     "crossbeam-deque",
     "crossbeam-epoch",
     "crossbeam-utils",
+    "crypto-common",
     "cstr",
     "datafrog",
     "difference",
     "scoped-tls",
     "scopeguard",
     "semver",
-    "semver-parser",
     "serde",
     "serde_derive",
     "serde_json",
index 8ea6bb308b7bac4a2bad4c12672b0fa9c9810af6..2a23d72edc06409029ebc5f1d631c662f56b833b 100644 (file)
@@ -1,7 +1,7 @@
 //! 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 std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::ffi::OsStr;
 use std::fs::read_to_string;
 use std::path::Path;
@@ -205,6 +205,7 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
     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)
@@ -218,17 +219,27 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
     for path in paths {
         super::walk(path, &mut |path| super::filter_dirs(path), &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")) {
+            } 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")) {
+            } 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", ""));
             }
         });
     }
@@ -240,6 +251,10 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
         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());
 
@@ -282,11 +297,21 @@ pub fn check(paths: &[&Path], bad: &mut bool) {
             }
         }
     }
+    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 codes with no tests", errors.len());
+    println!("Found {} error(s) in error codes", errors.len());
     if !errors.is_empty() {
         *bad = true;
     }
index b484c25ea510f3bdeae3b1f65a16bc4563455b99..276587e7f13fb44357688411c4a2b3f3316bdcf7 100644 (file)
@@ -113,6 +113,9 @@ trigger_files = [
     "src/tools/rustdoc-js",
     "src/tools/rustdoc-themes",
 ]
+exclude_labels = [
+    "T-*",
+]
 
 [autolabel."T-compiler"]
 trigger_files = [
@@ -122,6 +125,9 @@ trigger_files = [
     # Tests
     "src/test/ui",
 ]
+exclude_labels = [
+    "T-*",
+]
 
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts