]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #92487 - dtolnay:traitalias, r=matthewjasper
authorMatthias Krüger <matthias.krueger@famsik.de>
Sun, 16 Jan 2022 15:58:10 +0000 (16:58 +0100)
committerGitHub <noreply@github.com>
Sun, 16 Jan 2022 15:58:10 +0000 (16:58 +0100)
Fix unclosed boxes in pretty printing of TraitAlias

This was causing trait aliases to not even render at all in stringified / pretty printed output.

```rust
macro_rules! repro {
    ($item:item) => {
        stringify!($item)
    };
}

fn main() {
    println!("{:?}", repro!(pub trait Trait<T> = Sized where T: 'a;));
}
```

Before:&ensp;`""`
After:&ensp;`"pub trait Trait<T> = Sized where T: 'a;"`

The fix is copied from how `head`/`end` for `ItemKind::Use`, `ItemKind::ExternCrate`, and `ItemKind::Mod` are all done in the pretty printer:

https://github.com/rust-lang/rust/blob/dd3ac41495e85a9b7b5cb3186379d02ce17e51fe/compiler/rustc_ast_pretty/src/pprust/state.rs#L1178-L1184

921 files changed:
.mailmap
Cargo.lock
RELEASES.md
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/ast_like.rs
compiler/rustc_ast/src/lib.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/util/comments.rs
compiler/rustc_ast_lowering/src/expr.rs
compiler/rustc_ast_lowering/src/index.rs
compiler/rustc_ast_lowering/src/item.rs
compiler/rustc_ast_lowering/src/lib.rs
compiler/rustc_ast_lowering/src/pat.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_ast_pretty/src/pprust/mod.rs
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
compiler/rustc_borrowck/src/diagnostics/mod.rs
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
compiler/rustc_borrowck/src/diagnostics/region_name.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/type_check/liveness/trace.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_builtin_macros/src/asm.rs
compiler/rustc_builtin_macros/src/concat_bytes.rs
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/constant.rs
compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
compiler/rustc_codegen_gcc/config.sh
compiler/rustc_codegen_gcc/src/type_of.rs
compiler/rustc_codegen_gcc/test.sh
compiler/rustc_codegen_llvm/src/back/write.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/type_of.rs
compiler/rustc_codegen_ssa/Cargo.toml
compiler/rustc_codegen_ssa/src/back/link.rs
compiler/rustc_codegen_ssa/src/back/metadata.rs
compiler/rustc_codegen_ssa/src/back/symbol_export.rs
compiler/rustc_codegen_ssa/src/back/write.rs
compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_codegen_ssa/src/mir/mod.rs
compiler/rustc_codegen_ssa/src/mir/rvalue.rs
compiler/rustc_const_eval/src/const_eval/eval_queries.rs
compiler/rustc_const_eval/src/const_eval/fn_queries.rs
compiler/rustc_const_eval/src/const_eval/machine.rs
compiler/rustc_const_eval/src/interpret/eval_context.rs
compiler/rustc_const_eval/src/interpret/machine.rs
compiler/rustc_const_eval/src/interpret/operand.rs
compiler/rustc_const_eval/src/interpret/step.rs
compiler/rustc_const_eval/src/interpret/util.rs
compiler/rustc_const_eval/src/interpret/validity.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
compiler/rustc_const_eval/src/transform/promote_consts.rs
compiler/rustc_data_structures/Cargo.toml
compiler/rustc_data_structures/src/sip128.rs
compiler/rustc_data_structures/src/stable_hasher.rs
compiler/rustc_data_structures/src/thin_vec.rs
compiler/rustc_data_structures/src/thin_vec/tests.rs
compiler/rustc_data_structures/src/vec_map/tests.rs
compiler/rustc_driver/Cargo.toml
compiler/rustc_driver/src/lib.rs
compiler/rustc_errors/src/json.rs
compiler/rustc_errors/src/snippet.rs
compiler/rustc_expand/src/config.rs
compiler/rustc_expand/src/expand.rs
compiler/rustc_expand/src/lib.rs
compiler/rustc_expand/src/placeholders.rs
compiler/rustc_expand/src/proc_macro_server.rs
compiler/rustc_graphviz/src/tests.rs
compiler/rustc_hir/src/hir.rs
compiler/rustc_hir/src/hir_id.rs
compiler/rustc_hir/src/intravisit.rs
compiler/rustc_hir/src/lang_items.rs
compiler/rustc_hir/src/stable_hash_impls.rs
compiler/rustc_hir/src/weak_lang_items.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_incremental/src/persist/dirty_clean.rs
compiler/rustc_incremental/src/persist/fs/tests.rs
compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
compiler/rustc_infer/src/infer/combine.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/static_impl_trait.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
compiler/rustc_infer/src/infer/freshen.rs
compiler/rustc_infer/src/infer/mod.rs
compiler/rustc_infer/src/infer/nll_relate/mod.rs
compiler/rustc_infer/src/infer/opaque_types.rs
compiler/rustc_infer/src/infer/outlives/components.rs
compiler/rustc_infer/src/infer/outlives/verify.rs
compiler/rustc_infer/src/infer/resolve.rs
compiler/rustc_infer/src/traits/util.rs
compiler/rustc_interface/Cargo.toml
compiler/rustc_interface/src/interface.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/tests.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/noop_method_call.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
compiler/rustc_log/Cargo.toml [new file with mode: 0644]
compiler/rustc_log/src/lib.rs [new file with mode: 0644]
compiler/rustc_macros/src/serialize.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_metadata/src/rmeta/table.rs
compiler/rustc_middle/Cargo.toml
compiler/rustc_middle/src/dep_graph/mod.rs
compiler/rustc_middle/src/hir/exports.rs [deleted file]
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/hir/mod.rs
compiler/rustc_middle/src/lib.rs
compiler/rustc_middle/src/metadata.rs [new file with mode: 0644]
compiler/rustc_middle/src/middle/privacy.rs
compiler/rustc_middle/src/middle/stability.rs
compiler/rustc_middle/src/mir/generic_graph.rs
compiler/rustc_middle/src/mir/interpret/queries.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/mono.rs
compiler/rustc_middle/src/mir/pretty.rs
compiler/rustc_middle/src/mir/spanview.rs
compiler/rustc_middle/src/mir/tcx.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/traits/specialization_graph.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/consts.rs
compiler/rustc_middle/src/ty/consts/kind.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_middle/src/ty/erase_regions.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/fast_reject.rs
compiler/rustc_middle/src/ty/flags.rs
compiler/rustc_middle/src/ty/fold.rs
compiler/rustc_middle/src/ty/generics.rs
compiler/rustc_middle/src/ty/impls_ty.rs
compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs
compiler/rustc_middle/src/ty/inhabitedness/mod.rs
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_middle/src/ty/mod.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_place.rs
compiler/rustc_mir_build/src/build/matches/test.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/lints.rs
compiler/rustc_mir_build/src/thir/cx/expr.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
compiler/rustc_mir_dataflow/src/elaborate_drops.rs
compiler/rustc_mir_dataflow/src/move_paths/builder.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/coverage/mod.rs
compiler/rustc_mir_transform/src/coverage/query.rs
compiler/rustc_mir_transform/src/elaborate_drops.rs
compiler/rustc_mir_transform/src/function_item_references.rs
compiler/rustc_mir_transform/src/generator.rs
compiler/rustc_mir_transform/src/inline/cycle.rs
compiler/rustc_mir_transform/src/lib.rs
compiler/rustc_mir_transform/src/shim.rs
compiler/rustc_monomorphize/src/collector.rs
compiler/rustc_monomorphize/src/partitioning/default.rs
compiler/rustc_monomorphize/src/partitioning/mod.rs
compiler/rustc_monomorphize/src/polymorphize.rs
compiler/rustc_monomorphize/src/util.rs
compiler/rustc_parse/src/parser/diagnostics.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/check_const.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/entry.rs
compiler/rustc_passes/src/hir_id_validator.rs
compiler/rustc_passes/src/lang_items.rs
compiler/rustc_passes/src/lib.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_passes/src/reachable.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_passes/src/weak_lang_items.rs
compiler/rustc_privacy/src/lib.rs
compiler/rustc_query_impl/Cargo.toml
compiler/rustc_query_system/Cargo.toml
compiler/rustc_query_system/src/dep_graph/graph.rs
compiler/rustc_query_system/src/dep_graph/mod.rs
compiler/rustc_query_system/src/ich/hcx.rs
compiler/rustc_query_system/src/ich/impls_hir.rs
compiler/rustc_query_system/src/ich/mod.rs
compiler/rustc_query_system/src/query/plumbing.rs
compiler/rustc_resolve/src/access_levels.rs [new file with mode: 0644]
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/def_collector.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/imports.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/lifetimes.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_save_analysis/src/dump_visitor.rs
compiler/rustc_save_analysis/src/lib.rs
compiler/rustc_save_analysis/src/sig.rs
compiler/rustc_serialize/src/leb128.rs
compiler/rustc_serialize/src/opaque.rs
compiler/rustc_serialize/tests/leb128.rs
compiler/rustc_session/src/config.rs
compiler/rustc_session/src/options.rs
compiler/rustc_span/src/def_id.rs
compiler/rustc_span/src/hygiene.rs
compiler/rustc_span/src/lib.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_symbol_mangling/src/legacy.rs
compiler/rustc_symbol_mangling/src/lib.rs
compiler/rustc_symbol_mangling/src/v0.rs
compiler/rustc_target/src/spec/avr_gnu_base.rs
compiler/rustc_target/src/spec/mod.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/suggestions.rs
compiler/rustc_trait_selection/src/traits/fulfill.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/select/mod.rs
compiler/rustc_trait_selection/src/traits/structural_match.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_ty_utils/src/assoc.rs [new file with mode: 0644]
compiler/rustc_ty_utils/src/instance.rs
compiler/rustc_ty_utils/src/lib.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/errors.rs
compiler/rustc_typeck/src/astconv/generics.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/check/callee.rs
compiler/rustc_typeck/src/check/check.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/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/fn_ctxt/suggestions.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/mod.rs
compiler/rustc_typeck/src/check/op.rs
compiler/rustc_typeck/src/check/pat.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/mod.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/expr_use_visitor.rs
compiler/rustc_typeck/src/impl_wf_check.rs
compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs
compiler/rustc_typeck/src/lib.rs
compiler/rustc_typeck/src/outlives/implicit_infer.rs
compiler/rustc_typeck/src/outlives/mod.rs
compiler/rustc_typeck/src/variance/constraints.rs
compiler/rustc_typeck/src/variance/terms.rs
library/alloc/Cargo.toml
library/alloc/src/alloc.rs
library/alloc/src/boxed.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/map/tests.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/lib.rs
library/alloc/src/slice.rs
library/alloc/src/string.rs
library/alloc/src/vec/into_iter.rs
library/alloc/src/vec/mod.rs
library/alloc/tests/boxed.rs
library/alloc/tests/lib.rs
library/alloc/tests/linked_list.rs
library/alloc/tests/slice.rs
library/alloc/tests/string.rs
library/alloc/tests/vec.rs
library/alloc/tests/vec_deque.rs
library/core/Cargo.toml
library/core/src/array/mod.rs
library/core/src/char/convert.rs
library/core/src/char/mod.rs
library/core/src/convert/mod.rs
library/core/src/fmt/mod.rs
library/core/src/hint.rs
library/core/src/intrinsics.rs
library/core/src/iter/adapters/map.rs
library/core/src/iter/adapters/mod.rs
library/core/src/iter/sources.rs
library/core/src/iter/traits/collect.rs
library/core/src/iter/traits/iterator.rs
library/core/src/iter/traits/mod.rs
library/core/src/macros/mod.rs
library/core/src/mem/maybe_uninit.rs
library/core/src/mem/mod.rs
library/core/src/num/bignum.rs
library/core/src/num/f32.rs
library/core/src/num/f64.rs
library/core/src/num/int_macros.rs
library/core/src/num/saturating.rs
library/core/src/num/uint_macros.rs
library/core/src/ops/unsize.rs
library/core/src/option.rs
library/core/src/panicking.rs
library/core/src/prelude/v1.rs
library/core/src/ptr/const_ptr.rs
library/core/src/ptr/mut_ptr.rs
library/core/src/result.rs
library/core/src/slice/mod.rs
library/core/src/slice/sort.rs
library/core/src/sync/atomic.rs
library/core/tests/iter/adapters/intersperse.rs
library/core/tests/iter/adapters/peekable.rs
library/core/tests/iter/traits/iterator.rs
library/core/tests/lib.rs
library/core/tests/num/bignum.rs
library/panic_abort/Cargo.toml
library/panic_unwind/Cargo.toml
library/proc_macro/Cargo.toml
library/proc_macro/src/bridge/client.rs
library/proc_macro/src/lib.rs
library/profiler_builtins/Cargo.toml
library/rustc-std-workspace-alloc/Cargo.toml
library/rustc-std-workspace-core/Cargo.toml
library/rustc-std-workspace-std/Cargo.toml
library/std/src/collections/hash/map.rs
library/std/src/collections/hash/map/tests.rs
library/std/src/collections/hash/set.rs
library/std/src/collections/mod.rs
library/std/src/error.rs
library/std/src/error/tests.rs
library/std/src/fs.rs
library/std/src/io/buffered/mod.rs
library/std/src/io/mod.rs
library/std/src/keyword_docs.rs
library/std/src/lib.rs
library/std/src/net/ip/tests.rs
library/std/src/net/mod.rs
library/std/src/os/linux/raw.rs
library/std/src/os/unix/ffi/os_str.rs
library/std/src/os/unix/io/raw.rs
library/std/src/panic.rs
library/std/src/panicking.rs
library/std/src/prelude/v1.rs
library/std/src/sync/mpsc/mod.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/thread/mod.rs
library/std/src/time.rs
library/stdarch
library/test/Cargo.toml
library/test/src/lib.rs
library/test/src/stats.rs
library/test/src/tests.rs
library/test/src/types.rs
library/unwind/Cargo.toml
rustfmt.toml
src/bootstrap/Cargo.toml
src/bootstrap/bin/rustc.rs
src/bootstrap/bin/rustdoc.rs
src/bootstrap/bootstrap.py
src/bootstrap/builder.rs
src/bootstrap/cache.rs
src/bootstrap/compile.rs
src/bootstrap/config.rs
src/bootstrap/dist.rs
src/bootstrap/dylib_util.rs [new file with mode: 0644]
src/bootstrap/flags.rs
src/bootstrap/lib.rs
src/bootstrap/util.rs
src/ci/docker/host-x86_64/mingw-check/Dockerfile
src/ci/docker/scripts/musl-toolchain.sh
src/doc/book
src/doc/reference
src/doc/rustc-dev-guide
src/doc/rustdoc/src/documentation-tests.md
src/doc/rustdoc/src/unstable-features.md
src/doc/unstable-book/src/compiler-flags/instrument-coverage.md
src/librustdoc/Cargo.toml
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/config.rs
src/librustdoc/core.rs
src/librustdoc/formats/cache.rs
src/librustdoc/html/format.rs
src/librustdoc/html/layout.rs
src/librustdoc/html/render/context.rs
src/librustdoc/html/render/mod.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/html/render/search_index.rs
src/librustdoc/html/render/templates.rs [deleted file]
src/librustdoc/html/render/write_shared.rs
src/librustdoc/html/sources.rs
src/librustdoc/html/static/css/rustdoc.css
src/librustdoc/html/static/css/themes/ayu.css
src/librustdoc/html/static/css/themes/dark.css
src/librustdoc/html/static/css/themes/light.css
src/librustdoc/html/static/images/favicon-16x16.png
src/librustdoc/html/static/images/favicon-32x32.png
src/librustdoc/html/static/images/rust-logo.png [deleted file]
src/librustdoc/html/static/images/rust-logo.svg [new file with mode: 0644]
src/librustdoc/html/static/js/main.js
src/librustdoc/html/static/js/search.js
src/librustdoc/html/static_files.rs
src/librustdoc/html/templates/STYLE.md [deleted file]
src/librustdoc/html/templates/page.html [deleted file]
src/librustdoc/html/templates/print_item.html [deleted file]
src/librustdoc/html/tests.rs
src/librustdoc/html/url_parts_builder.rs
src/librustdoc/html/url_parts_builder/tests.rs
src/librustdoc/json/mod.rs
src/librustdoc/lib.rs
src/librustdoc/passes/check_doc_test_visibility.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/collect_intra_doc_links/early.rs
src/librustdoc/passes/collect_trait_impls.rs
src/librustdoc/passes/stripper.rs
src/librustdoc/scrape_examples.rs
src/librustdoc/templates/STYLE.md [new file with mode: 0644]
src/librustdoc/templates/page.html [new file with mode: 0644]
src/librustdoc/templates/print_item.html [new file with mode: 0644]
src/librustdoc/visit_ast.rs
src/librustdoc/visit_lib.rs
src/llvm-project
src/test/codegen/async-fn-debug-msvc.rs
src/test/codegen/async-fn-debug.rs
src/test/codegen/inline-hint.rs
src/test/debuginfo/function-names.rs
src/test/incremental/change_private_fn/struct_point.rs
src/test/incremental/hash-module-order.rs [new file with mode: 0644]
src/test/incremental/hashes/trait_defs.rs
src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff
src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff
src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff
src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff
src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff
src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff
src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff
src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff
src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff
src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff
src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff
src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir
src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff
src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir
src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir
src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir
src/test/run-make-fulldeps/a-b-a-linker-guard/Makefile
src/test/run-make-fulldeps/coverage-reports/Makefile
src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt [new file with mode: 0644]
src/test/run-make-fulldeps/coverage/lib/unused_mod_helper.rs [new file with mode: 0644]
src/test/run-make-fulldeps/coverage/unused_mod.rs [new file with mode: 0644]
src/test/run-make-fulldeps/share-generics-dylib/Makefile
src/test/run-make-fulldeps/split-debuginfo/Makefile
src/test/run-make-fulldeps/split-debuginfo/bar.rs [new file with mode: 0644]
src/test/run-make-fulldeps/split-debuginfo/foo.rs
src/test/run-make-fulldeps/split-debuginfo/main.rs [new file with mode: 0644]
src/test/run-make-fulldeps/split-dwarf/Makefile [deleted file]
src/test/run-make-fulldeps/split-dwarf/foo.rs [deleted file]
src/test/rustdoc-gui/anchors.goml
src/test/rustdoc-gui/escape-key.goml
src/test/rustdoc-gui/headings.goml
src/test/rustdoc-gui/run-on-hover.goml [new file with mode: 0644]
src/test/rustdoc-gui/rust-logo.goml [new file with mode: 0644]
src/test/rustdoc-gui/search-filter.goml
src/test/rustdoc-gui/src-font-size.goml [new file with mode: 0644]
src/test/rustdoc-gui/src/test_docs/lib.rs
src/test/rustdoc-gui/toggle-docs-mobile.goml
src/test/rustdoc-gui/toggle-docs.goml
src/test/rustdoc-ui/intra-doc/non-path-primitives.rs
src/test/rustdoc-ui/intra-doc/non-path-primitives.stderr
src/test/rustdoc-ui/private-public-item-doc-test.rs [new file with mode: 0644]
src/test/rustdoc-ui/private-public-item-doc-test.stderr [new file with mode: 0644]
src/test/rustdoc-ui/public-reexported-item-doc-test.rs [new file with mode: 0644]
src/test/rustdoc/decl_macro.rs
src/test/rustdoc/ensure-src-link.rs
src/test/rustdoc/external-macro-src.rs
src/test/rustdoc/intra-doc/prim-associated-traits.rs [new file with mode: 0644]
src/test/rustdoc/issue-16265-1.rs
src/test/rustdoc/issue-16265-2.rs
src/test/rustdoc/issue-26606.rs
src/test/rustdoc/issue-88600.rs
src/test/rustdoc/macro-generated-macro.rs [new file with mode: 0644]
src/test/rustdoc/macros.rs
src/test/rustdoc/mixing-doc-comments-and-attrs.S1_top-doc.html
src/test/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html [new file with mode: 0644]
src/test/rustdoc/mixing-doc-comments-and-attrs.rs
src/test/rustdoc/reexports-priv.rs
src/test/rustdoc/reexports.rs
src/test/rustdoc/src-links-auto-impls.rs
src/test/rustdoc/structfields.rs
src/test/rustdoc/thread-local-src.rs
src/test/rustdoc/toggle-item-contents.rs
src/test/rustdoc/trait-src-link.rs
src/test/rustdoc/tuple-struct-fields-doc.rs
src/test/rustdoc/union.rs
src/test/rustdoc/where-clause-order.rs [new file with mode: 0644]
src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
src/test/ui/associated-types/substs-ppaux.rs
src/test/ui/associated-types/substs-ppaux.verbose.stderr
src/test/ui/ast-json/ast-json-noexpand-output.stdout
src/test/ui/ast-json/ast-json-output.stdout
src/test/ui/async-await/interior-with-const-generic-expr.rs [new file with mode: 0644]
src/test/ui/borrowck/issue-92015.rs [new file with mode: 0644]
src/test/ui/borrowck/issue-92015.stderr [new file with mode: 0644]
src/test/ui/c-variadic/variadic-unreachable-arg-error.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs
src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr
src/test/ui/closures/2229_closure_analysis/destructure_patterns.rs
src/test/ui/closures/2229_closure_analysis/destructure_patterns.stderr
src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/nested-closure.rs
src/test/ui/closures/2229_closure_analysis/nested-closure.stderr
src/test/ui/closures/2229_closure_analysis/repr_packed.rs
src/test/ui/closures/2229_closure_analysis/repr_packed.stderr
src/test/ui/conditional-compilation/cfg-arg-invalid-8.rs [new file with mode: 0644]
src/test/ui/conditional-compilation/cfg-arg-invalid-8.stderr [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/infer_arg_and_const_arg.rs [new file with mode: 0644]
src/test/ui/const-generics/issues/issue-62878.full.stderr
src/test/ui/const-generics/issues/issue-62878.rs
src/test/ui/consts/const-block-const-bound.rs [new file with mode: 0644]
src/test/ui/consts/const-block-const-bound.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-generic_arg_infer.normal.stderr
src/test/ui/feature-gates/feature-gate-generic_arg_infer.rs
src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr
src/test/ui/feature-gates/feature-gate-unboxed-closures-manual-impls.stderr
src/test/ui/feature-gates/feature-gate-unboxed-closures.stderr
src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs [new file with mode: 0644]
src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-89352.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/self-outlives-lint.rs
src/test/ui/inference/char-as-str-multi.rs [new file with mode: 0644]
src/test/ui/inference/char-as-str-multi.stderr [new file with mode: 0644]
src/test/ui/inference/char-as-str-single.fixed [new file with mode: 0644]
src/test/ui/inference/char-as-str-single.rs [new file with mode: 0644]
src/test/ui/inference/char-as-str-single.stderr [new file with mode: 0644]
src/test/ui/inference/infer-arg-test.rs [deleted file]
src/test/ui/inference/infer-arg-test.stderr [deleted file]
src/test/ui/inference/str-as-char.fixed [new file with mode: 0644]
src/test/ui/inference/str-as-char.rs [new file with mode: 0644]
src/test/ui/inference/str-as-char.stderr [new file with mode: 0644]
src/test/ui/infinite/infinite-autoderef.stderr
src/test/ui/issues/issue-23589.stderr
src/test/ui/issues/issue-3214.rs
src/test/ui/issues/issue-3214.stderr
src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr
src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr
src/test/ui/lifetimes/issue-84604.rs
src/test/ui/lint/lint-pub-unreachable-for-nested-glob.rs [new file with mode: 0644]
src/test/ui/macros/concat-bytes-error.rs
src/test/ui/macros/concat-bytes-error.stderr
src/test/ui/macros/concat-bytes.rs
src/test/ui/macros/stringify.rs
src/test/ui/match/expr_before_ident_pat.stderr
src/test/ui/mir/drop-elaboration-after-borrowck-error.rs [new file with mode: 0644]
src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr [new file with mode: 0644]
src/test/ui/mismatched_types/method-help-unsatisfied-bound.rs
src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr
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/no-link.rs
src/test/ui/no-link.stderr [deleted file]
src/test/ui/occurs-check-2.stderr
src/test/ui/occurs-check.stderr
src/test/ui/panics/issue-47429-short-backtraces.rs
src/test/ui/panics/panic-handler-chain-update-hook.rs [new file with mode: 0644]
src/test/ui/panics/panic-short-backtrace-windows-x86_64.rs
src/test/ui/pattern/issue-92074-macro-ice.rs [new file with mode: 0644]
src/test/ui/pattern/issue-92074-macro-ice.stderr [new file with mode: 0644]
src/test/ui/polymorphization/closure_in_upvar/fn.rs
src/test/ui/polymorphization/closure_in_upvar/fnmut.rs
src/test/ui/polymorphization/closure_in_upvar/fnonce.rs
src/test/ui/polymorphization/closure_in_upvar/other.rs
src/test/ui/polymorphization/symbol-ambiguity.rs
src/test/ui/privacy/auxiliary/issue-92755.rs [new file with mode: 0644]
src/test/ui/privacy/issue-92755.rs [new file with mode: 0644]
src/test/ui/return/tail-expr-as-potential-return.rs
src/test/ui/return/tail-expr-as-potential-return.stderr
src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs [new file with mode: 0644]
src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr [new file with mode: 0644]
src/test/ui/span/coerce-suggestions.stderr
src/test/ui/span/impl-wrong-item-for-trait.rs
src/test/ui/span/impl-wrong-item-for-trait.stderr
src/test/ui/stability-attribute/generics-default-stability-trait.rs [new file with mode: 0644]
src/test/ui/stability-attribute/generics-default-stability-trait.stderr [new file with mode: 0644]
src/test/ui/stability-attribute/generics-default-stability.rs
src/test/ui/stability-attribute/generics-default-stability.stderr
src/test/ui/suggestions/boxed-variant-field.rs
src/test/ui/suggestions/boxed-variant-field.stderr
src/test/ui/suggestions/while-let-typo.rs [new file with mode: 0644]
src/test/ui/suggestions/while-let-typo.stderr [new file with mode: 0644]
src/test/ui/symbol-names/basic.rs
src/test/ui/symbol-names/const-generics-demangling.rs
src/test/ui/symbol-names/const-generics-str-demangling.rs
src/test/ui/symbol-names/const-generics-structural-demangling.rs
src/test/ui/symbol-names/const-generics.rs
src/test/ui/symbol-names/impl1.rs
src/test/ui/symbol-names/issue-60925.rs
src/test/ui/symbol-names/issue-75326.rs
src/test/ui/symbol-names/issue-76365.rs
src/test/ui/symbol-names/trait-objects.rs
src/test/ui/terr-sorts.stderr
src/test/ui/traits/pointee-deduction.rs [new file with mode: 0644]
src/test/ui/type-alias-impl-trait/bound_reduction2.rs
src/test/ui/type-alias-impl-trait/bound_reduction2.stderr
src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.nll.stderr
src/tools/build-manifest/Cargo.toml
src/tools/cargo
src/tools/clippy/.cargo/config.toml
src/tools/clippy/.github/workflows/clippy.yml
src/tools/clippy/.github/workflows/clippy_bors.yml
src/tools/clippy/.gitignore
src/tools/clippy/CHANGELOG.md
src/tools/clippy/Cargo.toml
src/tools/clippy/README.md
src/tools/clippy/clippy_dev/src/fmt.rs
src/tools/clippy/clippy_dev/src/update_lints.rs
src/tools/clippy/clippy_lints/Cargo.toml
src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
src/tools/clippy/clippy_lints/src/attrs.rs
src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/case_sensitive_file_extension_comparisons.rs
src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
src/tools/clippy/clippy_lints/src/casts/cast_ref_to_mut.rs
src/tools/clippy/clippy_lints/src/casts/char_lit_as_u8.rs
src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
src/tools/clippy/clippy_lints/src/copies.rs
src/tools/clippy/clippy_lints/src/default.rs
src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
src/tools/clippy/clippy_lints/src/dereference.rs
src/tools/clippy/clippy_lints/src/disallowed_methods.rs
src/tools/clippy/clippy_lints/src/disallowed_types.rs
src/tools/clippy/clippy_lints/src/doc.rs
src/tools/clippy/clippy_lints/src/entry.rs
src/tools/clippy/clippy_lints/src/eq_op.rs
src/tools/clippy/clippy_lints/src/equatable_if_let.rs
src/tools/clippy/clippy_lints/src/erasing_op.rs
src/tools/clippy/clippy_lints/src/escape.rs
src/tools/clippy/clippy_lints/src/eta_reduction.rs
src/tools/clippy/clippy_lints/src/exit.rs
src/tools/clippy/clippy_lints/src/explicit_write.rs
src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
src/tools/clippy/clippy_lints/src/format.rs
src/tools/clippy/clippy_lints/src/format_args.rs
src/tools/clippy/clippy_lints/src/from_over_into.rs
src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
src/tools/clippy/clippy_lints/src/functions/must_use.rs
src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
src/tools/clippy/clippy_lints/src/functions/result_unit_err.rs
src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs
src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
src/tools/clippy/clippy_lints/src/implicit_return.rs
src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
src/tools/clippy/clippy_lints/src/inherent_to_string.rs
src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
src/tools/clippy/clippy_lints/src/len_zero.rs
src/tools/clippy/clippy_lints/src/let_underscore.rs
src/tools/clippy/clippy_lints/src/lib.register_all.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_pedantic.rs
src/tools/clippy/clippy_lints/src/lib.register_perf.rs
src/tools/clippy/clippy_lints/src/lib.register_restriction.rs
src/tools/clippy/clippy_lints/src/lib.register_style.rs
src/tools/clippy/clippy_lints/src/lib.rs
src/tools/clippy/clippy_lints/src/lifetimes.rs
src/tools/clippy/clippy_lints/src/loops/empty_loop.rs
src/tools/clippy/clippy_lints/src/loops/explicit_into_iter_loop.rs
src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
src/tools/clippy/clippy_lints/src/loops/needless_collect.rs
src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
src/tools/clippy/clippy_lints/src/loops/never_loop.rs
src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
src/tools/clippy/clippy_lints/src/loops/while_let_loop.rs
src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs
src/tools/clippy/clippy_lints/src/macro_use.rs
src/tools/clippy/clippy_lints/src/manual_assert.rs
src/tools/clippy/clippy_lints/src/manual_bits.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/manual_map.rs
src/tools/clippy/clippy_lints/src/manual_ok_or.rs
src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs
src/tools/clippy/clippy_lints/src/match_str_case_mismatch.rs
src/tools/clippy/clippy_lints/src/matches.rs
src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
src/tools/clippy/clippy_lints/src/misc.rs
src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
src/tools/clippy/clippy_lints/src/mut_key.rs
src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
src/tools/clippy/clippy_lints/src/mutex_atomic.rs
src/tools/clippy/clippy_lints/src/needless_for_each.rs
src/tools/clippy/clippy_lints/src/needless_late_init.rs
src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
src/tools/clippy/clippy_lints/src/new_without_default.rs
src/tools/clippy/clippy_lints/src/no_effect.rs
src/tools/clippy/clippy_lints/src/non_copy_const.rs
src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
src/tools/clippy/clippy_lints/src/octal_escapes.rs
src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
src/tools/clippy/clippy_lints/src/ptr.rs
src/tools/clippy/clippy_lints/src/ptr_eq.rs
src/tools/clippy/clippy_lints/src/redundant_clone.rs
src/tools/clippy/clippy_lints/src/redundant_slicing.rs
src/tools/clippy/clippy_lints/src/reference.rs
src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
src/tools/clippy/clippy_lints/src/returns.rs
src/tools/clippy/clippy_lints/src/self_named_constructors.rs
src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
src/tools/clippy/clippy_lints/src/strings.rs
src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs
src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
src/tools/clippy/clippy_lints/src/trait_bounds.rs
src/tools/clippy/clippy_lints/src/types/mod.rs
src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
src/tools/clippy/clippy_lints/src/undropped_manually_drops.rs
src/tools/clippy/clippy_lints/src/uninit_vec.rs
src/tools/clippy/clippy_lints/src/unit_hash.rs
src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs
src/tools/clippy/clippy_lints/src/unnecessary_sort_by.rs
src/tools/clippy/clippy_lints/src/unused_io_amount.rs
src/tools/clippy/clippy_lints/src/unused_self.rs
src/tools/clippy/clippy_lints/src/use_self.rs
src/tools/clippy/clippy_lints/src/utils/author.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/utils/mod.rs
src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
src/tools/clippy/clippy_utils/Cargo.toml
src/tools/clippy/clippy_utils/src/ast_utils.rs
src/tools/clippy/clippy_utils/src/consts.rs
src/tools/clippy/clippy_utils/src/diagnostics.rs
src/tools/clippy/clippy_utils/src/eager_or_lazy.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 [new file with mode: 0644]
src/tools/clippy/clippy_utils/src/msrvs.rs
src/tools/clippy/clippy_utils/src/paths.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/clippy/clippy_utils/src/source.rs
src/tools/clippy/clippy_utils/src/sugg.rs
src/tools/clippy/clippy_utils/src/ty.rs
src/tools/clippy/clippy_utils/src/visitors.rs
src/tools/clippy/clippy_workspace_tests/Cargo.toml [deleted file]
src/tools/clippy/clippy_workspace_tests/build.rs [deleted file]
src/tools/clippy/clippy_workspace_tests/path_dep/Cargo.toml [deleted file]
src/tools/clippy/clippy_workspace_tests/path_dep/src/lib.rs [deleted file]
src/tools/clippy/clippy_workspace_tests/src/main.rs [deleted file]
src/tools/clippy/clippy_workspace_tests/subcrate/Cargo.toml [deleted file]
src/tools/clippy/clippy_workspace_tests/subcrate/src/lib.rs [deleted file]
src/tools/clippy/doc/common_tools_writing_lints.md
src/tools/clippy/lintcheck/Cargo.toml
src/tools/clippy/lintcheck/src/main.rs
src/tools/clippy/rust-toolchain
src/tools/clippy/src/main.rs
src/tools/clippy/tests/cargo/mod.rs [deleted file]
src/tools/clippy/tests/compile-test.rs
src/tools/clippy/tests/dogfood.rs
src/tools/clippy/tests/fmt.rs
src/tools/clippy/tests/test_utils/mod.rs [new file with mode: 0644]
src/tools/clippy/tests/ui-internal/invalid_paths.stderr
src/tools/clippy/tests/ui-toml/toml_disallowed_methods/clippy.toml
src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs
src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.stderr
src/tools/clippy/tests/ui/as_conversions.rs
src/tools/clippy/tests/ui/as_conversions.stderr
src/tools/clippy/tests/ui/assertions_on_constants.rs
src/tools/clippy/tests/ui/assertions_on_constants.stderr
src/tools/clippy/tests/ui/author/repeat.stdout
src/tools/clippy/tests/ui/borrow_as_ptr.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/borrow_as_ptr.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/borrow_as_ptr.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/cast_alignment.rs
src/tools/clippy/tests/ui/cast_alignment.stderr
src/tools/clippy/tests/ui/cast_ref_to_mut.rs
src/tools/clippy/tests/ui/deref_addrof.fixed
src/tools/clippy/tests/ui/deref_addrof.rs
src/tools/clippy/tests/ui/deref_addrof.stderr
src/tools/clippy/tests/ui/eq_op_macros.stderr
src/tools/clippy/tests/ui/erasing_op.rs
src/tools/clippy/tests/ui/erasing_op.stderr
src/tools/clippy/tests/ui/eta.fixed
src/tools/clippy/tests/ui/eta.rs
src/tools/clippy/tests/ui/identity_op.rs
src/tools/clippy/tests/ui/identity_op.stderr
src/tools/clippy/tests/ui/issue_4266.stderr
src/tools/clippy/tests/ui/iter_not_returning_iterator.rs
src/tools/clippy/tests/ui/iter_not_returning_iterator.stderr
src/tools/clippy/tests/ui/macro_use_imports.fixed
src/tools/clippy/tests/ui/macro_use_imports.rs
src/tools/clippy/tests/ui/manual_bits.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_bits.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_bits.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/manual_memcpy/with_loop_counters.stderr
src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.rs
src/tools/clippy/tests/ui/manual_memcpy/without_loop_counters.stderr
src/tools/clippy/tests/ui/missing_panics_doc.stderr
src/tools/clippy/tests/ui/mutex_atomic.rs
src/tools/clippy/tests/ui/mutex_atomic.stderr
src/tools/clippy/tests/ui/or_fun_call.fixed
src/tools/clippy/tests/ui/or_fun_call.rs
src/tools/clippy/tests/ui/panic_in_result_fn.stderr
src/tools/clippy/tests/ui/panic_in_result_fn_assertions.stderr
src/tools/clippy/tests/ui/panicking_macros.stderr
src/tools/clippy/tests/ui/return_self_not_must_use.stderr
src/tools/clippy/tests/ui/single_char_lifetime_names.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/single_char_lifetime_names.stderr [new file with mode: 0644]
src/tools/clippy/tests/ui/swap.fixed
src/tools/clippy/tests/ui/swap.rs
src/tools/clippy/tests/ui/swap.stderr
src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
src/tools/clippy/tests/ui/transmute.rs
src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs
src/tools/clippy/tests/ui/transmute_ptr_to_ptr.stderr
src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed
src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs
src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.stderr
src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
src/tools/clippy/tests/ui/unit_cmp.stderr
src/tools/clippy/tests/ui/unnecessary_cast_fixable.fixed
src/tools/clippy/tests/ui/unnecessary_cast_fixable.rs
src/tools/clippy/tests/ui/unnecessary_cast_fixable.stderr
src/tools/clippy/tests/ui/unused_io_amount.rs
src/tools/clippy/tests/ui/unused_io_amount.stderr
src/tools/clippy/tests/ui/vtable_address_comparisons.rs
src/tools/clippy/tests/ui/vtable_address_comparisons.stderr
src/tools/clippy/tests/ui/while_let_on_iterator.fixed
src/tools/clippy/tests/ui/while_let_on_iterator.rs
src/tools/clippy/tests/ui/while_let_on_iterator.stderr
src/tools/clippy/tests/ui/wrong_self_convention.rs
src/tools/clippy/tests/ui/wrong_self_convention.stderr
src/tools/clippy/tests/ui/zero_offset.rs
src/tools/clippy/tests/ui/zero_offset.stderr
src/tools/clippy/tests/workspace.rs [new file with mode: 0644]
src/tools/clippy/tests/workspace_test/Cargo.toml [new file with mode: 0644]
src/tools/clippy/tests/workspace_test/build.rs [new file with mode: 0644]
src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml [new file with mode: 0644]
src/tools/clippy/tests/workspace_test/path_dep/src/lib.rs [new file with mode: 0644]
src/tools/clippy/tests/workspace_test/src/main.rs [new file with mode: 0644]
src/tools/clippy/tests/workspace_test/subcrate/Cargo.toml [new file with mode: 0644]
src/tools/clippy/tests/workspace_test/subcrate/src/lib.rs [new file with mode: 0644]
src/tools/miri
src/tools/rust-analyzer
src/tools/rustfmt/Configurations.md
src/tools/rustfmt/src/config/mod.rs
src/tools/rustfmt/src/formatting.rs
src/tools/rustfmt/src/lib.rs
src/tools/rustfmt/src/test/mod.rs
src/tools/tidy/src/deps.rs
src/tools/tidy/src/edition.rs
src/version

index 9366ef383fc6d823f0a8a2090925a5de8b53c952..ac221fa3a60e464ced301ce0e611295510ddbc30 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -129,6 +129,7 @@ Jakub Adam Wieczorek <jakub.adam.wieczorek@gmail.com> <jakub.bukaj@yahoo.com>
 Jakub Adam Wieczorek <jakub.adam.wieczorek@gmail.com> <jakub@jakub.cc>
 Jakub Adam Wieczorek <jakub.adam.wieczorek@gmail.com> <jakubw@jakubw.net>
 James Deng <cnjamesdeng@gmail.com> <cnJamesDeng@gmail.com>
+James Hinshelwood <jameshinshelwood1@gmail.com> <james.hinshelwood@bigpayme.com>
 James Miller <bladeon@gmail.com> <james@aatch.net>
 James Perry <james.austin.perry@gmail.com>
 Jason Fager <jfager@gmail.com>
index 959c8161e984dd9636ef480d9b58ef0a6b503349..8565c075036f237bb648900a03cf913f0035f3df 100644 (file)
@@ -9,7 +9,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
 dependencies = [
  "compiler_builtins",
- "gimli",
+ "gimli 0.25.0",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
@@ -24,6 +24,17 @@ dependencies = [
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "ahash"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
+dependencies = [
+ "getrandom 0.2.0",
+ "once_cell",
+ "version_check",
+]
+
 [[package]]
 name = "aho-corasick"
 version = "0.7.18"
@@ -87,9 +98,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.34"
+version = "1.0.51"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7"
+checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203"
 
 [[package]]
 name = "array_tool"
@@ -103,6 +114,47 @@ version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5a2f58b0bb10c380af2b26e57212856b8c9a59e0925b4c20f4a174a49734eaf7"
 
+[[package]]
+name = "askama"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d8f355701c672c2ba3d718acbd213f740beea577cc4eae66accdffe15be1882"
+dependencies = [
+ "askama_derive",
+ "askama_escape",
+ "askama_shared",
+]
+
+[[package]]
+name = "askama_derive"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84704cab5b7ae0fd3a9f78ee5eb7b27f3749df445f04623db6633459ae283267"
+dependencies = [
+ "askama_shared",
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "askama_escape"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a1bb320f97e6edf9f756bf015900038e43c7700e059688e5724a928c8f3b8d5"
+
+[[package]]
+name = "askama_shared"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dae03eebba55a2697a376e58b573a29fe36893157173ac8df312ad85f3c0e012"
+dependencies = [
+ "askama_escape",
+ "nom",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
 [[package]]
 name = "atty"
 version = "0.2.14"
@@ -175,9 +227,7 @@ dependencies = [
  "filetime",
  "getopts",
  "ignore",
- "lazy_static",
  "libc",
- "merge",
  "num_cpus",
  "once_cell",
  "opener",
@@ -285,9 +335,9 @@ dependencies = [
  "cargo-test-macro",
  "cargo-test-support",
  "cargo-util",
- "clap",
+ "clap 3.0.6",
  "crates-io",
- "crossbeam-utils 0.8.3",
+ "crossbeam-utils",
  "curl",
  "curl-sys",
  "env_logger 0.9.0",
@@ -370,7 +420,7 @@ version = "0.1.0"
 dependencies = [
  "directories",
  "rustc-workspace-hack",
- "rustc_version 0.3.3",
+ "rustc_version",
  "serde",
  "serde_json",
  "vergen",
@@ -565,16 +615,31 @@ dependencies = [
  "ansi_term 0.12.1",
  "atty",
  "bitflags",
- "strsim",
- "textwrap",
+ "strsim 0.8.0",
+ "textwrap 0.11.0",
  "unicode-width",
  "vec_map",
  "yaml-rust 0.3.5",
 ]
 
+[[package]]
+name = "clap"
+version = "3.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1957aa4a5fb388f0a0a73ce7556c5b42025b874e5cdc2c670775e346e97adec0"
+dependencies = [
+ "atty",
+ "bitflags",
+ "indexmap",
+ "os_str_bytes",
+ "strsim 0.10.0",
+ "termcolor",
+ "textwrap 0.14.2",
+]
+
 [[package]]
 name = "clippy"
-version = "0.1.59"
+version = "0.1.60"
 dependencies = [
  "cargo_metadata 0.14.0",
  "clippy_lints",
@@ -582,6 +647,7 @@ dependencies = [
  "compiletest_rs",
  "derive-new",
  "filetime",
+ "futures 0.3.12",
  "if_chain",
  "itertools 0.10.1",
  "parking_lot",
@@ -594,6 +660,7 @@ dependencies = [
  "syn",
  "tempfile",
  "tester",
+ "tokio",
 ]
 
 [[package]]
@@ -602,7 +669,7 @@ version = "0.0.1"
 dependencies = [
  "bytecount",
  "cargo_metadata 0.14.0",
- "clap",
+ "clap 2.34.0",
  "indoc",
  "itertools 0.10.1",
  "opener",
@@ -613,7 +680,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.59"
+version = "0.1.60"
 dependencies = [
  "cargo_metadata 0.14.0",
  "clippy_utils",
@@ -634,8 +701,9 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.59"
+version = "0.1.60"
 dependencies = [
+ "arrayvec",
  "if_chain",
  "rustc-semver",
 ]
@@ -789,69 +857,44 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.0"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dca26ee1f8d361640700bde38b2c37d8c22b3ce2d360e1fc1c74ea4b0aa7d775"
+checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
 dependencies = [
  "cfg-if 1.0.0",
- "crossbeam-utils 0.8.3",
+ "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-deque"
-version = "0.7.4"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed"
+checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
 dependencies = [
+ "cfg-if 1.0.0",
  "crossbeam-epoch",
- "crossbeam-utils 0.7.2",
- "maybe-uninit",
+ "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.8.2"
+version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace"
+checksum = "97242a70df9b89a65d0b6df3c4bf5b9ce03c5b7309019777fbde37e7537f8762"
 dependencies = [
- "autocfg",
- "cfg-if 0.1.10",
- "crossbeam-utils 0.7.2",
+ "cfg-if 1.0.0",
+ "crossbeam-utils",
  "lazy_static",
- "maybe-uninit",
  "memoffset",
  "scopeguard",
 ]
 
-[[package]]
-name = "crossbeam-queue"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
-dependencies = [
- "cfg-if 0.1.10",
- "crossbeam-utils 0.7.2",
- "maybe-uninit",
-]
-
 [[package]]
 name = "crossbeam-utils"
-version = "0.7.2"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
+checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120"
 dependencies = [
- "autocfg",
- "cfg-if 0.1.10",
- "lazy_static",
-]
-
-[[package]]
-name = "crossbeam-utils"
-version = "0.8.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
-dependencies = [
- "autocfg",
  "cfg-if 1.0.0",
  "lazy_static",
 ]
@@ -1160,6 +1203,12 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed"
 
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
 [[package]]
 name = "filetime"
 version = "0.2.14"
@@ -1448,6 +1497,17 @@ dependencies = [
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "gimli"
+version = "0.26.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
+dependencies = [
+ "fallible-iterator",
+ "indexmap",
+ "stable_deref_trait",
+]
+
 [[package]]
 name = "git2"
 version = "0.13.23"
@@ -1494,22 +1554,11 @@ dependencies = [
  "regex",
 ]
 
-[[package]]
-name = "globwalk"
-version = "0.8.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc"
-dependencies = [
- "bitflags",
- "ignore",
- "walkdir",
-]
-
 [[package]]
 name = "gsgdt"
-version = "0.1.3"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb958139bb971f37d2f5423436f137768f88b9c616b4c21d4f634dd129508d60"
+checksum = "a0d876ce7262df96262a2a19531da6ff9a86048224d49580a585fc5c04617825"
 dependencies = [
  "serde",
 ]
@@ -1534,6 +1583,7 @@ version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "362385356d610bd1e5a408ddf8d022041774b683f345a1d2cfcb4f60f8ae2db5"
 dependencies = [
+ "ahash",
  "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
@@ -1650,7 +1700,7 @@ version = "0.4.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "b287fb45c60bb826a0dc68ff08742b9d88a2fea13d6e0c286b3172065aaf878c"
 dependencies = [
- "crossbeam-utils 0.8.3",
+ "crossbeam-utils",
  "globset",
  "lazy_static",
  "log",
@@ -1701,7 +1751,7 @@ name = "installer"
 version = "0.0.0"
 dependencies = [
  "anyhow",
- "clap",
+ "clap 2.34.0",
  "flate2",
  "lazy_static",
  "num_cpus",
@@ -2120,12 +2170,6 @@ version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
 
-[[package]]
-name = "maybe-uninit"
-version = "2.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
-
 [[package]]
 name = "md-5"
 version = "0.9.1"
@@ -2146,7 +2190,7 @@ dependencies = [
  "ammonia",
  "anyhow",
  "chrono",
- "clap",
+ "clap 2.34.0",
  "elasticlunr-rs",
  "env_logger 0.7.1",
  "handlebars",
@@ -2214,35 +2258,13 @@ dependencies = [
 
 [[package]]
 name = "memoffset"
-version = "0.5.5"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f"
+checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
 dependencies = [
  "autocfg",
 ]
 
-[[package]]
-name = "merge"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9"
-dependencies = [
- "merge_derive",
- "num-traits",
-]
-
-[[package]]
-name = "merge_derive"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07"
-dependencies = [
- "proc-macro-error",
- "proc-macro2",
- "quote",
- "syn",
-]
-
 [[package]]
 name = "minifier"
 version = "0.0.41"
@@ -2252,6 +2274,12 @@ dependencies = [
  "macro-utils",
 ]
 
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
 [[package]]
 name = "miniz_oxide"
 version = "0.4.0"
@@ -2300,7 +2328,7 @@ dependencies = [
  "measureme 9.1.2",
  "rand 0.8.4",
  "rustc-workspace-hack",
- "rustc_version 0.4.0",
+ "rustc_version",
  "shell-escape",
  "smallvec",
 ]
@@ -2311,6 +2339,17 @@ version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
 
+[[package]]
+name = "nom"
+version = "7.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+ "version_check",
+]
+
 [[package]]
 name = "ntapi"
 version = "0.3.6"
@@ -2356,13 +2395,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
 dependencies = [
  "compiler_builtins",
- "crc32fast",
- "indexmap",
  "memchr",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "object"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9"
+dependencies = [
+ "crc32fast",
+ "flate2",
+ "indexmap",
+ "memchr",
+]
+
+[[package]]
+name = "object"
+version = "0.28.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ce8b38d41f9f3618fc23f908faae61510f8d8ce2d99cbe910641e8f1971f084"
+dependencies = [
+ "crc32fast",
+ "hashbrown",
+ "indexmap",
+ "memchr",
+]
+
 [[package]]
 name = "odht"
 version = "0.3.1"
@@ -2460,6 +2521,15 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "os_str_bytes"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "output_vt100"
 version = "0.1.2"
@@ -2864,7 +2934,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7fec2e85e7a30f8fd31b7cf288ad363b5e51fd2cb6f53b416b0cfaabd84e1ccb"
 dependencies = [
  "bitflags",
- "clap",
+ "clap 2.34.0",
  "derive_more",
  "env_logger 0.7.1",
  "humantime 2.0.1",
@@ -3000,9 +3070,9 @@ dependencies = [
 
 [[package]]
 name = "rayon"
-version = "1.3.1"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62f02856753d04e03e26929f820d0a0a337ebe71f849801eea335d464b349080"
+checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
 dependencies = [
  "autocfg",
  "crossbeam-deque",
@@ -3012,13 +3082,13 @@ dependencies = [
 
 [[package]]
 name = "rayon-core"
-version = "1.7.1"
+version = "1.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280"
+checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
 dependencies = [
+ "crossbeam-channel",
  "crossbeam-deque",
- "crossbeam-queue",
- "crossbeam-utils 0.7.2",
+ "crossbeam-utils",
  "lazy_static",
  "num_cpus",
 ]
@@ -3219,7 +3289,7 @@ dependencies = [
 name = "rustbook"
 version = "0.1.0"
 dependencies = [
- "clap",
+ "clap 2.34.0",
  "env_logger 0.7.1",
  "mdbook",
 ]
@@ -3271,7 +3341,7 @@ dependencies = [
  "arrayvec",
  "bitflags",
  "cfg-if 0.1.10",
- "crossbeam-utils 0.8.3",
+ "crossbeam-utils",
  "ena",
  "indexmap",
  "jobserver",
@@ -3498,9 +3568,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-rayon"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed7d6a39f8bfd4421ce720918234d1e672b83824c91345b47c93746839cf1629"
+checksum = "9974ab223660e61c1b4e7b43b827379df286736ca988308ce7e16f59f2d89246"
 dependencies = [
  "crossbeam-deque",
  "either",
@@ -3509,13 +3579,12 @@ dependencies = [
 
 [[package]]
 name = "rustc-rayon-core"
-version = "0.3.1"
+version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e94187d9ea3e8c38fafdbc38acb94eafa7ce155867f6ccb13830466a0d0db8c6"
+checksum = "564bfd27be8db888d0fa76aa4335e7851aaed0c2c11ad1e93aeb9349f6b88500"
 dependencies = [
  "crossbeam-deque",
- "crossbeam-queue",
- "crossbeam-utils 0.7.2",
+ "crossbeam-utils",
  "lazy_static",
  "num_cpus",
 ]
@@ -3553,7 +3622,7 @@ version = "1.0.0"
 dependencies = [
  "bstr",
  "byteorder",
- "crossbeam-utils 0.8.3",
+ "crossbeam-utils",
  "libc",
  "libz-sys",
  "proc-macro2",
@@ -3749,10 +3818,11 @@ dependencies = [
  "itertools 0.9.0",
  "jobserver",
  "libc",
- "object",
+ "object 0.28.1",
  "pathdiff",
  "regex",
  "rustc_apfloat",
+ "rustc_arena",
  "rustc_ast",
  "rustc_attr",
  "rustc_data_structures",
@@ -3773,6 +3843,7 @@ dependencies = [
  "smallvec",
  "snap",
  "tempfile",
+ "thorin-dwp",
  "tracing",
 ]
 
@@ -3832,7 +3903,6 @@ dependencies = [
 name = "rustc_driver"
 version = "0.0.0"
 dependencies = [
- "atty",
  "libc",
  "rustc_ast",
  "rustc_ast_pretty",
@@ -3846,6 +3916,7 @@ dependencies = [
  "rustc_hir_pretty",
  "rustc_interface",
  "rustc_lint",
+ "rustc_log",
  "rustc_metadata",
  "rustc_middle",
  "rustc_parse",
@@ -3857,8 +3928,6 @@ dependencies = [
  "rustc_target",
  "rustc_typeck",
  "tracing",
- "tracing-subscriber",
- "tracing-tree",
  "winapi",
 ]
 
@@ -4101,6 +4170,17 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "rustc_log"
+version = "0.0.0"
+dependencies = [
+ "atty",
+ "rustc_span",
+ "tracing",
+ "tracing-subscriber",
+ "tracing-tree",
+]
+
 [[package]]
 name = "rustc_macros"
 version = "0.1.0"
@@ -4601,15 +4681,6 @@ dependencies = [
  "tracing",
 ]
 
-[[package]]
-name = "rustc_version"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
-dependencies = [
- "semver 0.11.0",
-]
-
 [[package]]
 name = "rustc_version"
 version = "0.4.0"
@@ -4624,6 +4695,7 @@ name = "rustdoc"
 version = "0.0.0"
 dependencies = [
  "arrayvec",
+ "askama",
  "expect-test",
  "itertools 0.9.0",
  "minifier",
@@ -4635,7 +4707,6 @@ dependencies = [
  "serde_json",
  "smallvec",
  "tempfile",
- "tera",
  "tracing",
  "tracing-subscriber",
  "tracing-tree",
@@ -5017,7 +5088,7 @@ dependencies = [
  "hermit-abi",
  "libc",
  "miniz_oxide",
- "object",
+ "object 0.26.2",
  "panic_abort",
  "panic_unwind",
  "profiler_builtins",
@@ -5079,22 +5150,28 @@ version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
 
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
 [[package]]
 name = "structopt"
-version = "0.3.16"
+version = "0.3.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de5472fb24d7e80ae84a7801b7978f95a19ec32cb1876faea59ab711eb901976"
+checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
 dependencies = [
- "clap",
+ "clap 2.34.0",
  "lazy_static",
  "structopt-derive",
 ]
 
 [[package]]
 name = "structopt-derive"
-version = "0.4.9"
+version = "0.4.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e0eb37335aeeebe51be42e2dc07f031163fbabfa6ac67d7ea68b5c2f68d5f99"
+checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
 dependencies = [
  "heck",
  "proc-macro-error",
@@ -5180,21 +5257,6 @@ dependencies = [
  "utf-8",
 ]
 
-[[package]]
-name = "tera"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81060acb882480c8793782eb96bc86f5c83d2fc7175ad46c375c6956ef7afa62"
-dependencies = [
- "globwalk",
- "lazy_static",
- "pest",
- "pest_derive",
- "regex",
- "serde",
- "serde_json",
-]
-
 [[package]]
 name = "term"
 version = "0.6.1"
@@ -5271,26 +5333,44 @@ dependencies = [
  "unicode-width",
 ]
 
+[[package]]
+name = "textwrap"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80"
+
 [[package]]
 name = "thiserror"
-version = "1.0.20"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
+checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.20"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
+checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
 dependencies = [
  "proc-macro2",
  "quote",
  "syn",
 ]
 
+[[package]]
+name = "thorin-dwp"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "039d1fc0bfdb73910c2702893515580e38c192f47a987bc98ddd38a36f2d953a"
+dependencies = [
+ "gimli 0.26.1",
+ "indexmap",
+ "object 0.27.1",
+ "tracing",
+]
+
 [[package]]
 name = "thread_local"
 version = "1.0.1"
@@ -5305,7 +5385,7 @@ name = "tidy"
 version = "0.1.0"
 dependencies = [
  "cargo_metadata 0.12.0",
- "crossbeam-utils 0.8.3",
+ "crossbeam-utils",
  "lazy_static",
  "regex",
  "walkdir",
@@ -5418,9 +5498,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6"
 
 [[package]]
 name = "tracing"
-version = "0.1.28"
+version = "0.1.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84f96e095c0c82419687c20ddf5cb3eadb61f4e1405923c9dc8e53a1adacbda8"
+checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105"
 dependencies = [
  "cfg-if 1.0.0",
  "pin-project-lite",
@@ -5430,9 +5510,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.17"
+version = "0.1.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4f915eb6abf914599c200260efced9203504c4c37380af10cdf3b7d36970650"
+checksum = "f4f480b8f81512e825f337ad51e94c1eb5d3bbdf2b363dcd01e2b19a9ffe3f8e"
 dependencies = [
  "proc-macro2",
  "quote",
index 4b9b20f4cba606cd75ecb00ceab7ca2ba7894f6a..460c78b14d13815004f7cfd57a8394a9e3f5cd10 100644 (file)
@@ -1,3 +1,137 @@
+Version 1.58.0 (2022-01-13)
+==========================
+
+Language
+--------
+
+- [Format strings can now capture arguments simply by writing `{ident}` in the string.][90473] This works in all macros accepting format strings. Support for this in `panic!` (`panic!("{ident}")`) requires the 2021 edition; panic invocations in previous editions that appear to be trying to use this will result in a warning lint about not having the intended effect.
+- [`*const T` pointers can now be dereferenced in const contexts.][89551]
+- [The rules for when a generic struct implements `Unsize` have been relaxed.][90417]
+
+Compiler
+--------
+
+- [Add LLVM CFI support to the Rust compiler][89652]
+- [Stabilize -Z strip as -C strip][90058]. Note that while release builds already don't add debug symbols for the code you compile, the compiled standard library that ships with Rust includes debug symbols, so you may want to use the `strip` option to remove these symbols to produce smaller release binaries. Note that this release only includes support in rustc, not directly in cargo.
+- [Add support for LLVM coverage mapping format versions 5 and 6][91207]
+- [Emit LLVM optimization remarks when enabled with `-Cremark`][90833]
+- [Update the minimum external LLVM to 12][90175]
+- [Add `x86_64-unknown-none` at Tier 3*][89062]
+- [Build musl dist artifacts with debuginfo enabled][90733]. When building release binaries using musl, you may want to use the newly stabilized strip option to remove these debug symbols, reducing the size of your binaries.
+- [Don't abort compilation after giving a lint error][87337]
+- [Error messages point at the source of trait bound obligations in more places][89580]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+   information on Rust's tiered platform support.
+
+Libraries
+---------
+
+- [All remaining functions in the standard library have `#[must_use]` annotations where appropriate][89692], producing a warning when ignoring their return value. This helps catch mistakes such as expecting a function to mutate a value in place rather than return a new value.
+- [Paths are automatically canonicalized on Windows for operations that support it][89174]
+- [Re-enable debug checks for `copy` and `copy_nonoverlapping`][90041]
+- [Implement `RefUnwindSafe` for `Rc<T>`][87467]
+- [Make RSplit<T, P>: Clone not require T: Clone][90117]
+- [Implement `Termination` for `Result<Infallible, E>`][88601]. This allows writing `fn main() -> Result<Infallible, ErrorType>`, for a program whose successful exits never involve returning from `main` (for instance, a program that calls `exit`, or that uses `exec` to run another program).
+
+Stabilized APIs
+---------------
+
+- [`Metadata::is_symlink`]
+- [`Path::is_symlink`]
+- [`{integer}::saturating_div`]
+- [`Option::unwrap_unchecked`]
+- [`Result::unwrap_unchecked`]
+- [`Result::unwrap_err_unchecked`]
+- [`File::options`]
+
+These APIs are now usable in const contexts:
+
+- [`Duration::new`]
+- [`Duration::checked_add`]
+- [`Duration::saturating_add`]
+- [`Duration::checked_sub`]
+- [`Duration::saturating_sub`]
+- [`Duration::checked_mul`]
+- [`Duration::saturating_mul`]
+- [`Duration::checked_div`]
+
+Cargo
+-----
+
+- [Add --message-format for install command][cargo/10107]
+- [Warn when alias shadows external subcommand][cargo/10082]
+
+Rustdoc
+-------
+
+- [Show all Deref implementations recursively in rustdoc][90183]
+- [Use computed visibility in rustdoc][88447]
+
+Compatibility Notes
+-------------------
+
+- [Try all stable method candidates first before trying unstable ones][90329]. This change ensures that adding new nightly-only methods to the Rust standard library will not break code invoking methods of the same name from traits outside the standard library.
+- Windows: [`std::process::Command` will no longer search the current directory for executables.][87704]
+- [All proc-macro backward-compatibility lints are now deny-by-default.][88041]
+- [proc_macro: Append .0 to unsuffixed float if it would otherwise become int token][90297]
+- [Refactor weak symbols in std::sys::unix][90846]. This optimizes accesses to glibc functions, by avoiding the use of dlopen. This does not increase the [minimum expected version of glibc](https://doc.rust-lang.org/nightly/rustc/platform-support.html). However, software distributions that use symbol versions to detect library dependencies, and which take weak symbols into account in that analysis, may detect rust binaries as requiring newer versions of glibc.
+- [rustdoc now rejects some unexpected semicolons in doctests][91026]
+
+Internal Changes
+----------------
+
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc
+and related tools.
+
+- [Implement coherence checks for negative trait impls][90104]
+- [Add rustc lint, warning when iterating over hashmaps][89558]
+- [Optimize live point computation][90491]
+- [Enable verification for 1/32nd of queries loaded from disk][90361]
+- [Implement version of normalize_erasing_regions that allows for normalization failure][91255]
+
+[87337]: https://github.com/rust-lang/rust/pull/87337/
+[87467]: https://github.com/rust-lang/rust/pull/87467/
+[87704]: https://github.com/rust-lang/rust/pull/87704/
+[88041]: https://github.com/rust-lang/rust/pull/88041/
+[88447]: https://github.com/rust-lang/rust/pull/88447/
+[88601]: https://github.com/rust-lang/rust/pull/88601/
+[89062]: https://github.com/rust-lang/rust/pull/89062/
+[89174]: https://github.com/rust-lang/rust/pull/89174/
+[89551]: https://github.com/rust-lang/rust/pull/89551/
+[89558]: https://github.com/rust-lang/rust/pull/89558/
+[89580]: https://github.com/rust-lang/rust/pull/89580/
+[89652]: https://github.com/rust-lang/rust/pull/89652/
+[90041]: https://github.com/rust-lang/rust/pull/90041/
+[90058]: https://github.com/rust-lang/rust/pull/90058/
+[90104]: https://github.com/rust-lang/rust/pull/90104/
+[90117]: https://github.com/rust-lang/rust/pull/90117/
+[90175]: https://github.com/rust-lang/rust/pull/90175/
+[90183]: https://github.com/rust-lang/rust/pull/90183/
+[90297]: https://github.com/rust-lang/rust/pull/90297/
+[90329]: https://github.com/rust-lang/rust/pull/90329/
+[90361]: https://github.com/rust-lang/rust/pull/90361/
+[90417]: https://github.com/rust-lang/rust/pull/90417/
+[90473]: https://github.com/rust-lang/rust/pull/90473/
+[90491]: https://github.com/rust-lang/rust/pull/90491/
+[90733]: https://github.com/rust-lang/rust/pull/90733/
+[90833]: https://github.com/rust-lang/rust/pull/90833/
+[90846]: https://github.com/rust-lang/rust/pull/90846/
+[91026]: https://github.com/rust-lang/rust/pull/91026/
+[91207]: https://github.com/rust-lang/rust/pull/91207/
+[91255]: https://github.com/rust-lang/rust/pull/91255/
+[cargo/10082]: https://github.com/rust-lang/cargo/pull/10082/
+[cargo/10107]: https://github.com/rust-lang/cargo/pull/10107/
+[`Metadata::is_symlink`]: https://doc.rust-lang.org/stable/std/fs/struct.Metadata.html#method.is_symlink
+[`Path::is_symlink`]: https://doc.rust-lang.org/stable/std/path/struct.Path.html#method.is_symlink
+[`{integer}::saturating_div`]: https://doc.rust-lang.org/stable/std/primitive.i8.html#method.saturating_div
+[`Option::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.unwrap_unchecked
+[`Result::unwrap_unchecked`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.unwrap_unchecked
+[`Result::unwrap_err_unchecked`]: https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.unwrap_err_unchecked
+[`File::options`]: https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.options
+[`Duration::new`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.new
+
 Version 1.57.0 (2021-12-02)
 ==========================
 
@@ -78,7 +212,6 @@ and related tools.
 [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/
-[88243]: https://github.com/rust-lang/rust/pull/88243/
 [88321]: https://github.com/rust-lang/rust/pull/88321/
 [88529]: https://github.com/rust-lang/rust/pull/88529/
 [88690]: https://github.com/rust-lang/rust/pull/88690/
@@ -234,8 +367,6 @@ and related tools.
   as well as rustdoc.
 
 [`std::os::unix::fs::chroot`]: https://doc.rust-lang.org/stable/std/os/unix/fs/fn.chroot.html
-[`Iterator::intersperse`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.intersperse
-[`Iterator::intersperse_with`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.intersperse
 [`UnsafeCell::raw_get`]: https://doc.rust-lang.org/stable/std/cell/struct.UnsafeCell.html#method.raw_get
 [`BufWriter::into_parts`]: https://doc.rust-lang.org/stable/std/io/struct.BufWriter.html#method.into_parts
 [`core::panic::{UnwindSafe, RefUnwindSafe, AssertUnwindSafe}`]: https://github.com/rust-lang/rust/pull/84662
@@ -257,12 +388,7 @@ and related tools.
 [rust#86183]: https://github.com/rust-lang/rust/pull/86183
 [rust#87385]: https://github.com/rust-lang/rust/pull/87385
 [rust#88100]: https://github.com/rust-lang/rust/pull/88100
-[rust#86860]: https://github.com/rust-lang/rust/pull/86860
-[rust#84039]: https://github.com/rust-lang/rust/pull/84039
-[rust#86492]: https://github.com/rust-lang/rust/pull/86492
-[rust#88363]: https://github.com/rust-lang/rust/pull/88363
 [rust#85305]: https://github.com/rust-lang/rust/pull/85305
-[rust#87832]: https://github.com/rust-lang/rust/pull/87832
 [rust#88069]: https://github.com/rust-lang/rust/pull/88069
 [rust#87472]: https://github.com/rust-lang/rust/pull/87472
 [rust#87699]: https://github.com/rust-lang/rust/pull/87699
@@ -273,31 +399,12 @@ and related tools.
 [rust#87580]: https://github.com/rust-lang/rust/pull/87580
 [rust#83342]: https://github.com/rust-lang/rust/pull/83342
 [rust#83093]: https://github.com/rust-lang/rust/pull/83093
-[rust#88177]: https://github.com/rust-lang/rust/pull/88177
-[rust#88548]: https://github.com/rust-lang/rust/pull/88548
-[rust#88551]: https://github.com/rust-lang/rust/pull/88551
-[rust#88299]: https://github.com/rust-lang/rust/pull/88299
-[rust#88220]: https://github.com/rust-lang/rust/pull/88220
 [rust#85835]: https://github.com/rust-lang/rust/pull/85835
-[rust#86879]: https://github.com/rust-lang/rust/pull/86879
 [rust#86744]: https://github.com/rust-lang/rust/pull/86744
-[rust#84662]: https://github.com/rust-lang/rust/pull/84662
-[rust#86593]: https://github.com/rust-lang/rust/pull/86593
-[rust#81050]: https://github.com/rust-lang/rust/pull/81050
 [rust#81363]: https://github.com/rust-lang/rust/pull/81363
 [rust#84111]: https://github.com/rust-lang/rust/pull/84111
 [rust#85769]: https://github.com/rust-lang/rust/pull/85769#issuecomment-854363720
-[rust#88490]: https://github.com/rust-lang/rust/pull/88490
-[rust#88269]: https://github.com/rust-lang/rust/pull/88269
-[rust#84176]: https://github.com/rust-lang/rust/pull/84176
 [rust#88399]: https://github.com/rust-lang/rust/pull/88399
-[rust#88227]: https://github.com/rust-lang/rust/pull/88227
-[rust#88200]: https://github.com/rust-lang/rust/pull/88200
-[rust#82776]: https://github.com/rust-lang/rust/pull/82776
-[rust#88077]: https://github.com/rust-lang/rust/pull/88077
-[rust#87728]: https://github.com/rust-lang/rust/pull/87728
-[rust#87050]: https://github.com/rust-lang/rust/pull/87050
-[rust#87619]: https://github.com/rust-lang/rust/pull/87619
 [rust#81825]: https://github.com/rust-lang/rust/pull/81825#issuecomment-808406918
 [rust#88019]: https://github.com/rust-lang/rust/pull/88019
 [rust#87666]: https://github.com/rust-lang/rust/pull/87666
@@ -388,6 +495,10 @@ Compatibility Notes
   `Command` would cause them to be ASCII-uppercased.
 - [Rustdoc will now warn on using rustdoc lints that aren't prefixed
   with `rustdoc::`][86849]
+- `RUSTFLAGS` is no longer set for build scripts. Build scripts
+  should use `CARGO_ENCODED_RUSTFLAGS` instead. See the
+  [documentation](https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts)
+  for more details.
 
 [86849]: https://github.com/rust-lang/rust/pull/86849
 [86513]: https://github.com/rust-lang/rust/pull/86513
@@ -399,20 +510,14 @@ Compatibility Notes
 [86294]: https://github.com/rust-lang/rust/pull/86294
 [86858]: https://github.com/rust-lang/rust/pull/86858
 [86761]: https://github.com/rust-lang/rust/pull/86761
-[85769]: https://github.com/rust-lang/rust/pull/85769
 [85746]: https://github.com/rust-lang/rust/pull/85746
-[85305]: https://github.com/rust-lang/rust/pull/85305
 [85270]: https://github.com/rust-lang/rust/pull/85270
-[84111]: https://github.com/rust-lang/rust/pull/84111
 [83918]: https://github.com/rust-lang/rust/pull/83918
 [79965]: https://github.com/rust-lang/rust/pull/79965
-[87370]: https://github.com/rust-lang/rust/pull/87370
-[87298]: https://github.com/rust-lang/rust/pull/87298
 [cargo/9663]: https://github.com/rust-lang/cargo/pull/9663
 [cargo/9675]: https://github.com/rust-lang/cargo/pull/9675
 [cargo/9550]: https://github.com/rust-lang/cargo/pull/9550
 [cargo/9680]: https://github.com/rust-lang/cargo/pull/9680
-[cargo/9663]: https://github.com/rust-lang/cargo/pull/9663
 [`array::map`]: https://doc.rust-lang.org/stable/std/primitive.array.html#method.map
 [`Bound::cloned`]: https://doc.rust-lang.org/stable/std/ops/enum.Bound.html#method.cloned
 [`Drain::as_str`]: https://doc.rust-lang.org/stable/std/string/struct.Drain.html#method.as_str
@@ -421,7 +526,6 @@ Compatibility Notes
 [`MaybeUninit::assume_init_mut`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_mut
 [`MaybeUninit::assume_init_ref`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_ref
 [`MaybeUninit::write`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.write
-[`Seek::rewind`]: https://doc.rust-lang.org/stable/std/io/trait.Seek.html#method.rewind
 [`ops::ControlFlow`]: https://doc.rust-lang.org/stable/std/ops/enum.ControlFlow.html
 [`str::from_utf8_unchecked`]: https://doc.rust-lang.org/stable/std/str/fn.from_utf8_unchecked.html
 [`x86::_bittest`]: https://doc.rust-lang.org/stable/core/arch/x86/fn._bittest.html
@@ -525,7 +629,6 @@ Compatibility Notes
 [85574]: https://github.com/rust-lang/rust/issues/85574
 [86831]: https://github.com/rust-lang/rust/issues/86831
 [86063]: https://github.com/rust-lang/rust/issues/86063
-[86831]: https://github.com/rust-lang/rust/issues/86831
 [79608]: https://github.com/rust-lang/rust/pull/79608
 [84988]: https://github.com/rust-lang/rust/pull/84988
 [84701]: https://github.com/rust-lang/rust/pull/84701
@@ -727,7 +830,6 @@ related tools.
 [`Ordering::is_le`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_le
 [`Ordering::is_lt`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_lt
 [`Ordering::is_ne`]: https://doc.rust-lang.org/std/cmp/enum.Ordering.html#method.is_ne
-[`OsStr::eq_ignore_ascii_case`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.eq_ignore_ascii_case
 [`OsStr::is_ascii`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.is_ascii
 [`OsStr::make_ascii_lowercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.make_ascii_lowercase
 [`OsStr::make_ascii_uppercase`]: https://doc.rust-lang.org/std/ffi/struct.OsStr.html#method.make_ascii_uppercase
@@ -1058,7 +1160,6 @@ Internal Only
 [80053]: https://github.com/rust-lang/rust/pull/80053
 [79502]: https://github.com/rust-lang/rust/pull/79502
 [75180]: https://github.com/rust-lang/rust/pull/75180
-[79135]: https://github.com/rust-lang/rust/pull/79135
 [81521]: https://github.com/rust-lang/rust/pull/81521
 [80968]: https://github.com/rust-lang/rust/pull/80968
 [80959]: https://github.com/rust-lang/rust/pull/80959
@@ -1372,7 +1473,6 @@ related tools.
 [`slice::select_nth_unstable`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable
 [`slice::select_nth_unstable_by`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by
 [`slice::select_nth_unstable_by_key`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.select_nth_unstable_by_key
-[`hint::spin_loop`]: https://doc.rust-lang.org/stable/std/hint/fn.spin_loop.html
 [`Poll::is_ready`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_ready
 [`Poll::is_pending`]: https://doc.rust-lang.org/stable/std/task/enum.Poll.html#method.is_pending
 [rustdoc-ws-post]: https://blog.guillaume-gomez.fr/articles/2020-11-11+New+doc+comment+handling+in+rustdoc
@@ -1619,8 +1719,6 @@ Internal Only
 [74869]: https://github.com/rust-lang/rust/pull/74869/
 [73858]: https://github.com/rust-lang/rust/pull/73858/
 [75716]: https://github.com/rust-lang/rust/pull/75716/
-[75908]: https://github.com/rust-lang/rust/pull/75908/
-[75516]: https://github.com/rust-lang/rust/pull/75516/
 [75560]: https://github.com/rust-lang/rust/pull/75560/
 [75568]: https://github.com/rust-lang/rust/pull/75568/
 [75366]: https://github.com/rust-lang/rust/pull/75366/
@@ -1635,7 +1733,6 @@ Internal Only
 [73583]: https://github.com/rust-lang/rust/pull/73583/
 [73084]: https://github.com/rust-lang/rust/pull/73084/
 [73197]: https://github.com/rust-lang/rust/pull/73197/
-[72488]: https://github.com/rust-lang/rust/pull/72488/
 [cargo/8456]: https://github.com/rust-lang/cargo/pull/8456/
 [cargo/8478]: https://github.com/rust-lang/cargo/pull/8478/
 [cargo/8485]: https://github.com/rust-lang/cargo/pull/8485/
@@ -1646,7 +1743,6 @@ Internal Only
 [`RangeInclusive::is_empty`]: https://doc.rust-lang.org/nightly/std/ops/struct.RangeInclusive.html#method.is_empty
 [`Result::as_deref_mut`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#method.as_deref_mut
 [`Result::as_deref`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#method.as_deref
-[`TypeId::of`]: https://doc.rust-lang.org/nightly/std/any/struct.TypeId.html#method.of
 [`Vec::leak`]: https://doc.rust-lang.org/nightly/std/vec/struct.Vec.html#method.leak
 [`f32::TAU`]: https://doc.rust-lang.org/nightly/std/f32/consts/constant.TAU.html
 [`f64::TAU`]: https://doc.rust-lang.org/nightly/std/f64/consts/constant.TAU.html
@@ -2414,6 +2510,11 @@ Language
 - [Visibility modifiers (e.g. `pub`) are now syntactically allowed on trait items and
   enum variants.][66183] These are still rejected semantically, but
   can be seen and parsed by procedural macros and conditional compilation.
+- [You can now define a Rust `extern "C"` function with `Box<T>` and use `T*` as the corresponding
+  type on the C side.][62514] Please see [the documentation][box-memory-layout] for more information,
+  including the important caveat about preferring to avoid `Box<T>` in Rust signatures for functions defined in C.
+
+[box-memory-layout]: https://doc.rust-lang.org/std/boxed/index.html#memory-layout
 
 Compiler
 --------
@@ -2488,6 +2589,7 @@ Compatibility Notes
 
 [54733]: https://github.com/rust-lang/rust/pull/54733/
 [61351]: https://github.com/rust-lang/rust/pull/61351/
+[62514]: https://github.com/rust-lang/rust/pull/62514/
 [67255]: https://github.com/rust-lang/rust/pull/67255/
 [66661]: https://github.com/rust-lang/rust/pull/66661/
 [66771]: https://github.com/rust-lang/rust/pull/66771/
@@ -2624,7 +2726,6 @@ Compatibility Notes
 [63803]: https://github.com/rust-lang/rust/pull/63803/
 [cargo/7450]: https://github.com/rust-lang/cargo/pull/7450/
 [cargo/7507]: https://github.com/rust-lang/cargo/pull/7507/
-[cargo/7525]: https://github.com/rust-lang/cargo/pull/7525/
 [cargo/7333]: https://github.com/rust-lang/cargo/pull/7333/
 [(rfc 2008)]: https://rust-lang.github.io/rfcs/2008-non-exhaustive.html
 [`f32::to_be_bytes`]: https://doc.rust-lang.org/std/primitive.f32.html#method.to_be_bytes
@@ -2757,13 +2858,6 @@ Compatibility Notes
 [63786]: https://github.com/rust-lang/rust/pull/63786/
 [63827]: https://github.com/rust-lang/rust/pull/63827/
 [63834]: https://github.com/rust-lang/rust/pull/63834/
-[63927]: https://github.com/rust-lang/rust/pull/63927/
-[63933]: https://github.com/rust-lang/rust/pull/63933/
-[63934]: https://github.com/rust-lang/rust/pull/63934/
-[63938]: https://github.com/rust-lang/rust/pull/63938/
-[63940]: https://github.com/rust-lang/rust/pull/63940/
-[63941]: https://github.com/rust-lang/rust/pull/63941/
-[63945]: https://github.com/rust-lang/rust/pull/63945/
 [64010]: https://github.com/rust-lang/rust/pull/64010/
 [64028]: https://github.com/rust-lang/rust/pull/64028/
 [64334]: https://github.com/rust-lang/rust/pull/64334/
@@ -2992,7 +3086,6 @@ Compatibility Notes
 [`Cell<slice>::as_slice_of_cells`]: https://doc.rust-lang.org/std/cell/struct.Cell.html#method.as_slice_of_cells
 [`DoubleEndedIterator::nth_back`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.nth_back
 [`Option::xor`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.xor
-[`RefCell::try_borrow_unguarded`]: https://doc.rust-lang.org/std/cell/struct.RefCell.html#method.try_borrow_unguarded
 [`Wrapping::reverse_bits`]: https://doc.rust-lang.org/std/num/struct.Wrapping.html#method.reverse_bits
 [`i128::reverse_bits`]: https://doc.rust-lang.org/std/primitive.i128.html#method.reverse_bits
 [`i16::reverse_bits`]: https://doc.rust-lang.org/std/primitive.i16.html#method.reverse_bits
@@ -3491,7 +3584,6 @@ Compatibility Notes
 - [Libtest no longer creates a new thread for each test when
   `--test-threads=1`.  It also runs the tests in deterministic order][56243]
 
-[55982]: https://github.com/rust-lang/rust/pull/55982/
 [56243]: https://github.com/rust-lang/rust/pull/56243
 [56303]: https://github.com/rust-lang/rust/pull/56303/
 [56351]: https://github.com/rust-lang/rust/pull/56351/
@@ -3891,7 +3983,6 @@ Cargo
 
 [52813]: https://github.com/rust-lang/rust/pull/52813/
 [53218]: https://github.com/rust-lang/rust/pull/53218/
-[53555]: https://github.com/rust-lang/rust/issues/53555/
 [54057]: https://github.com/rust-lang/rust/pull/54057/
 [54240]: https://github.com/rust-lang/rust/pull/54240/
 [54430]: https://github.com/rust-lang/rust/pull/54430/
@@ -4013,7 +4104,6 @@ Misc
 [53044]: https://github.com/rust-lang/rust/pull/53044/
 [53165]: https://github.com/rust-lang/rust/pull/53165/
 [53611]: https://github.com/rust-lang/rust/pull/53611/
-[53213]: https://github.com/rust-lang/rust/pull/53213/
 [53236]: https://github.com/rust-lang/rust/pull/53236/
 [53272]: https://github.com/rust-lang/rust/pull/53272/
 [53370]: https://github.com/rust-lang/rust/pull/53370/
@@ -4021,7 +4111,6 @@ Misc
 [53774]: https://github.com/rust-lang/rust/pull/53774/
 [53822]: https://github.com/rust-lang/rust/pull/53822/
 [54057]: https://github.com/rust-lang/rust/pull/54057/
-[54146]: https://github.com/rust-lang/rust/pull/54146/
 [54404]: https://github.com/rust-lang/rust/pull/54404/
 [cargo/5877]: https://github.com/rust-lang/cargo/pull/5877/
 [cargo/5878]: https://github.com/rust-lang/cargo/pull/5878/
@@ -4129,12 +4218,10 @@ Compatibility Notes
 [52330]: https://github.com/rust-lang/rust/pull/52330/
 [52354]: https://github.com/rust-lang/rust/pull/52354/
 [52402]: https://github.com/rust-lang/rust/pull/52402/
-[52103]: https://github.com/rust-lang/rust/pull/52103/
 [52197]: https://github.com/rust-lang/rust/pull/52197/
 [51807]: https://github.com/rust-lang/rust/pull/51807/
 [51899]: https://github.com/rust-lang/rust/pull/51899/
 [51912]: https://github.com/rust-lang/rust/pull/51912/
-[51511]: https://github.com/rust-lang/rust/pull/51511/
 [51619]: https://github.com/rust-lang/rust/pull/51619/
 [51656]: https://github.com/rust-lang/rust/pull/51656/
 [51178]: https://github.com/rust-lang/rust/pull/51178/
@@ -4274,7 +4361,6 @@ Compatibility Notes
 [50855]: https://github.com/rust-lang/rust/pull/50855/
 [51050]: https://github.com/rust-lang/rust/pull/51050/
 [51196]: https://github.com/rust-lang/rust/pull/51196/
-[51200]: https://github.com/rust-lang/rust/pull/51200/
 [51241]: https://github.com/rust-lang/rust/pull/51241/
 [51276]: https://github.com/rust-lang/rust/pull/51276/
 [51298]: https://github.com/rust-lang/rust/pull/51298/
@@ -4455,15 +4541,12 @@ Compatibility Notes
 [49664]: https://github.com/rust-lang/rust/pull/49664/
 [49699]: https://github.com/rust-lang/rust/pull/49699/
 [49707]: https://github.com/rust-lang/rust/pull/49707/
-[49719]: https://github.com/rust-lang/rust/pull/49719/
 [49896]: https://github.com/rust-lang/rust/pull/49896/
 [49968]: https://github.com/rust-lang/rust/pull/49968/
 [50163]: https://github.com/rust-lang/rust/pull/50163
 [50177]: https://github.com/rust-lang/rust/pull/50177/
 [50378]: https://github.com/rust-lang/rust/pull/50378/
-[50398]: https://github.com/rust-lang/rust/pull/50398/
 [50423]: https://github.com/rust-lang/rust/pull/50423/
-[cargo/5203]: https://github.com/rust-lang/cargo/pull/5203/
 [cargo/5335]: https://github.com/rust-lang/cargo/pull/5335/
 [cargo/5359]: https://github.com/rust-lang/cargo/pull/5359/
 [cargo/5360]: https://github.com/rust-lang/cargo/pull/5360/
@@ -4665,7 +4748,6 @@ Compatibility Notes
 [47813]: https://github.com/rust-lang/rust/pull/47813
 [48056]: https://github.com/rust-lang/rust/pull/48056
 [48125]: https://github.com/rust-lang/rust/pull/48125
-[48166]: https://github.com/rust-lang/rust/pull/48166
 [48235]: https://github.com/rust-lang/rust/pull/48235
 [48274]: https://github.com/rust-lang/rust/pull/48274
 [48281]: https://github.com/rust-lang/rust/pull/48281
@@ -4682,10 +4764,7 @@ Compatibility Notes
 [48978]: https://github.com/rust-lang/rust/pull/48978
 [49101]: https://github.com/rust-lang/rust/pull/49101
 [49109]: https://github.com/rust-lang/rust/pull/49109
-[49121]: https://github.com/rust-lang/rust/pull/49121
 [49162]: https://github.com/rust-lang/rust/pull/49162
-[49184]: https://github.com/rust-lang/rust/pull/49184
-[49234]: https://github.com/rust-lang/rust/pull/49234
 [49255]: https://github.com/rust-lang/rust/pull/49255
 [49299]: https://github.com/rust-lang/rust/pull/49299
 [49305]: https://github.com/rust-lang/rust/pull/49305
@@ -4932,7 +5011,6 @@ Compatibility Notes
 [44884]: https://github.com/rust-lang/rust/pull/44884
 [45198]: https://github.com/rust-lang/rust/pull/45198
 [45506]: https://github.com/rust-lang/rust/pull/45506
-[45904]: https://github.com/rust-lang/rust/pull/45904
 [45990]: https://github.com/rust-lang/rust/pull/45990
 [46012]: https://github.com/rust-lang/rust/pull/46012
 [46077]: https://github.com/rust-lang/rust/pull/46077
@@ -4944,7 +5022,6 @@ Compatibility Notes
 [46671]: https://github.com/rust-lang/rust/pull/46671
 [46713]: https://github.com/rust-lang/rust/pull/46713
 [46735]: https://github.com/rust-lang/rust/pull/46735
-[46749]: https://github.com/rust-lang/rust/pull/46749
 [46760]: https://github.com/rust-lang/rust/pull/46760
 [46798]: https://github.com/rust-lang/rust/pull/46798
 [46828]: https://github.com/rust-lang/rust/pull/46828
@@ -5115,7 +5192,6 @@ Compatibility Notes
 
 
 [42526]: https://github.com/rust-lang/rust/pull/42526
-[43017]: https://github.com/rust-lang/rust/pull/43017
 [43716]: https://github.com/rust-lang/rust/pull/43716
 [43949]: https://github.com/rust-lang/rust/pull/43949
 [44015]: https://github.com/rust-lang/rust/pull/44015
@@ -5345,8 +5421,6 @@ Cargo
 - [Added `--no-fail-fast` flag to cargo to run all benchmarks regardless of
   failure.][cargo/4248]
 - [Changed the convention around which file is the crate root.][cargo/4259]
-- [The `include`/`exclude` property in `Cargo.toml` now accepts gitignore paths
-  instead of glob patterns][cargo/4270]. Glob patterns are now deprecated.
 
 Compatibility Notes
 -------------------
@@ -5389,7 +5463,6 @@ Compatibility Notes
 [cargo/4229]: https://github.com/rust-lang/cargo/pull/4229
 [cargo/4248]: https://github.com/rust-lang/cargo/pull/4248
 [cargo/4259]: https://github.com/rust-lang/cargo/pull/4259
-[cargo/4270]: https://github.com/rust-lang/cargo/pull/4270
 [`CStr::into_c_string`]: https://doc.rust-lang.org/std/ffi/struct.CStr.html#method.into_c_string
 [`CString::as_c_str`]: https://doc.rust-lang.org/std/ffi/struct.CString.html#method.as_c_str
 [`CString::into_boxed_c_str`]: https://doc.rust-lang.org/std/ffi/struct.CString.html#method.into_boxed_c_str
@@ -5682,7 +5755,6 @@ Misc
 ----
 
 - [rustdoc can now use pulldown-cmark with the `--enable-commonmark` flag][40338]
-- [Added rust-windbg script for better debugging on Windows][39983]
 - [Rust now uses the official cross compiler for NetBSD][40612]
 - [rustdoc now accepts `#` at the start of files][40828]
 - [Fixed jemalloc support for musl][41168]
@@ -5717,7 +5789,6 @@ Compatibility Notes
 [38165]: https://github.com/rust-lang/rust/pull/38165
 [39799]: https://github.com/rust-lang/rust/pull/39799
 [39891]: https://github.com/rust-lang/rust/pull/39891
-[39983]: https://github.com/rust-lang/rust/pull/39983
 [40043]: https://github.com/rust-lang/rust/pull/40043
 [40241]: https://github.com/rust-lang/rust/pull/40241
 [40338]: https://github.com/rust-lang/rust/pull/40338
@@ -6013,7 +6084,6 @@ Compatibility Notes
 [cargo/3691]: https://github.com/rust-lang/cargo/pull/3691
 [cargo/3699]: https://github.com/rust-lang/cargo/pull/3699
 [cargo/3731]: https://github.com/rust-lang/cargo/pull/3731
-[mdbook]: https://crates.io/crates/mdbook
 [ubook]: https://doc.rust-lang.org/unstable-book/
 
 
@@ -6084,7 +6154,7 @@ Libraries
 * [Ctrl-Z returns from `Stdin.read()` when reading from the console on
   Windows][38274]
 * [std: Fix partial writes in `LineWriter`][38062]
-* [std: Clamp max read/write sizes on Unix][38062]
+* [std: Clamp max read/write sizes on Unix][38622]
 * [Use more specific panic message for `&str` slicing errors][38066]
 * [`TcpListener::set_only_v6` is deprecated][38304]. This
   functionality cannot be achieved in std currently.
@@ -6150,7 +6220,7 @@ Compatibility Notes
 [38006]: https://github.com/rust-lang/rust/pull/38006
 [38051]: https://github.com/rust-lang/rust/pull/38051
 [38062]: https://github.com/rust-lang/rust/pull/38062
-[38062]: https://github.com/rust-lang/rust/pull/38622
+[38622]: https://github.com/rust-lang/rust/pull/38622
 [38066]: https://github.com/rust-lang/rust/pull/38066
 [38069]: https://github.com/rust-lang/rust/pull/38069
 [38131]: https://github.com/rust-lang/rust/pull/38131
@@ -6158,7 +6228,6 @@ Compatibility Notes
 [38274]: https://github.com/rust-lang/rust/pull/38274
 [38304]: https://github.com/rust-lang/rust/pull/38304
 [38313]: https://github.com/rust-lang/rust/pull/38313
-[38314]: https://github.com/rust-lang/rust/pull/38314
 [38327]: https://github.com/rust-lang/rust/pull/38327
 [38401]: https://github.com/rust-lang/rust/pull/38401
 [38413]: https://github.com/rust-lang/rust/pull/38413
@@ -6208,7 +6277,6 @@ Compatibility Notes
 [cargo/3546]: https://github.com/rust-lang/cargo/pull/3546
 [cargo/3557]: https://github.com/rust-lang/cargo/pull/3557
 [cargo/3604]: https://github.com/rust-lang/cargo/pull/3604
-[RFC 1623]: https://github.com/rust-lang/rfcs/blob/master/text/1623-static.md
 
 
 Version 1.15.1 (2017-02-09)
@@ -6423,7 +6491,6 @@ Compatibility Notes
 [38192]: https://github.com/rust-lang/rust/pull/38192
 [38279]: https://github.com/rust-lang/rust/pull/38279
 [38835]: https://github.com/rust-lang/rust/pull/38835
-[RFC 1492]: https://github.com/rust-lang/rfcs/blob/master/text/1492-dotdot-in-patterns.md
 [RFC 1506]: https://github.com/rust-lang/rfcs/blob/master/text/1506-adt-kinds.md
 [RFC 1560]: https://github.com/rust-lang/rfcs/blob/master/text/1560-name-resolution.md
 [RFC 1681]: https://github.com/rust-lang/rfcs/blob/master/text/1681-macros-1.1.md
@@ -6612,7 +6679,6 @@ Compatibility Notes
 [1.14wasm]: https://users.rust-lang.org/t/compiling-to-the-web-with-rust-and-emscripten/7627
 [36430]: https://github.com/rust-lang/rust/pull/36430
 [36595]: https://github.com/rust-lang/rust/pull/36595
-[36595]: https://github.com/rust-lang/rust/pull/36595
 [36692]: https://github.com/rust-lang/rust/pull/36692
 [36767]: https://github.com/rust-lang/rust/pull/36767
 [36794]: https://github.com/rust-lang/rust/pull/36794
@@ -6840,7 +6906,6 @@ Compatibility Notes
 [34623]: https://github.com/rust-lang/rust/pull/34623
 [34923]: https://github.com/rust-lang/rust/pull/34923
 [34942]: https://github.com/rust-lang/rust/pull/34942
-[34982]: https://github.com/rust-lang/rust/pull/34982
 [35021]: https://github.com/rust-lang/rust/pull/35021
 [35048]: https://github.com/rust-lang/rust/pull/35048
 [35074]: https://github.com/rust-lang/rust/pull/35074
@@ -6897,7 +6962,6 @@ Compatibility Notes
 [36586]: https://github.com/rust-lang/rust/pull/36586
 [36592]: https://github.com/rust-lang/rust/pull/36592
 [36631]: https://github.com/rust-lang/rust/pull/36631
-[36639]: https://github.com/rust-lang/rust/pull/36639
 [36721]: https://github.com/rust-lang/rust/pull/36721
 [36727]: https://github.com/rust-lang/rust/pull/36727
 [36730]: https://github.com/rust-lang/rust/pull/36730
@@ -6929,7 +6993,6 @@ Compatibility Notes
 [cargo/3205]: https://github.com/rust-lang/cargo/pull/3205
 [cargo/3241]: https://github.com/rust-lang/cargo/pull/3241
 [cargo/3242]: https://github.com/rust-lang/cargo/pull/3242
-[rustup]: https://www.rustup.rs
 [`checked_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.checked_abs
 [`wrapping_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.wrapping_abs
 [`overflowing_abs`]: https://doc.rust-lang.org/std/primitive.i32.html#method.overflowing_abs
@@ -7847,7 +7910,7 @@ Cargo
   targets can be specified together. [RFC 1361].
 * [The environment variables `CARGO_TARGET_ROOT`, `RUSTC`, and
   `RUSTDOC` take precedence over the `build.target-dir`,
-  `build.rustc`, and `build.rustdoc` configuration values][1.8cv].
+  `build.rustc`, and `build.rustdoc` configuration values][1.8cfv].
 * [The child process tree is killed on Windows when Cargo is
   killed][1.8ck].
 * [The `build.target` configuration value sets the target platform,
@@ -7897,7 +7960,7 @@ Compatibility Notes
 [1.8ck]: https://github.com/rust-lang/cargo/pull/2370
 [1.8ct]: https://github.com/rust-lang/cargo/pull/2335
 [1.8cu]: https://github.com/rust-lang/rust/pull/31390
-[1.8cv]: https://github.com/rust-lang/cargo/issues/2365
+[1.8cfv]: https://github.com/rust-lang/cargo/issues/2365
 [1.8cv]: https://github.com/rust-lang/rust/pull/30998
 [1.8h]: https://github.com/rust-lang/rust/pull/31460
 [1.8l]: https://github.com/rust-lang/rust/pull/31668
@@ -8820,13 +8883,13 @@ Misc
 * The compiler gained many new extended error descriptions, which can
   be accessed with the `--explain` flag.
 * The `dropck` pass, which checks that destructors can't access
-  destroyed values, [has been rewritten][dropck]. This fixes some
+  destroyed values, [has been rewritten][27261]. This fixes some
   soundness holes, and as such will cause some previously-compiling
   code to no longer build.
 * `rustc` now uses [LLVM to write archive files where possible][ar].
   Eventually this will eliminate the compiler's dependency on the ar
   utility.
-* Rust has [preliminary support for i686 FreeBSD][fb] (it has long
+* Rust has [preliminary support for i686 FreeBSD][26959] (it has long
   supported FreeBSD on x86_64).
 * The [`unused_mut`][lum], [`unconditional_recursion`][lur],
   [`improper_ctypes`][lic], and [`negate_unsigned`][lnu] lints are
@@ -8865,7 +8928,7 @@ Misc
 [ar]: https://github.com/rust-lang/rust/pull/26926
 [b14]: https://static.rust-lang.org/dist/rust-beta-x86_64-pc-windows-msvc.msi
 [dms]: https://github.com/rust-lang/rust/pull/26241
-[dropck]: https://github.com/rust-lang/rust/pull/27261
+[27261]: https://github.com/rust-lang/rust/pull/27261
 [dropckrfc]: https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md
 [ds]: https://github.com/rust-lang/rust/pull/26818
 [dst1]: http://doc.rust-lang.org/nightly/std/mem/fn.size_of_val.html
@@ -8873,9 +8936,8 @@ Misc
 [dst3]: https://github.com/rust-lang/rust/pull/27351
 [e]: https://github.com/rust-lang/rust/pull/24793
 [f]: https://github.com/rust-lang/rust/pull/26588
-[fb]: https://github.com/rust-lang/rust/pull/26959
+[26959]: https://github.com/rust-lang/rust/pull/26959
 [fl]: https://github.com/rust-lang/rust-installer/pull/41
-[hs]: http://doc.rust-lang.org/nightly/std/hash/trait.Hash.html#method.hash_slice
 [ie]: http://doc.rust-lang.org/nightly/std/io/struct.Error.html
 [iec]: http://doc.rust-lang.org/nightly/std/io/struct.Error.html#method.cause
 [iegm]: http://doc.rust-lang.org/nightly/std/io/struct.Error.html#method.get_mut
@@ -9146,7 +9208,7 @@ Misc
   to rustc.
 * [Android executables are always position independent][pie].
 * [The `drop_with_repr_extern` lint warns about mixing `repr(C)`
-  with `Drop`][drop].
+  with `Drop`][24935].
 
 [`str::split_whitespace`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_whitespace
 [`FromRawFd`]: https://doc.rust-lang.org/nightly/std/os/unix/io/trait.FromRawFd.html
@@ -9176,7 +9238,7 @@ Misc
 [`BinaryHeap`]: https://doc.rust-lang.org/nightly/std/collections/struct.BinaryHeap.html
 [ll]: https://github.com/rust-lang/rust/pull/26022
 [`split_off`]: https://doc.rust-lang.org/nightly/collections/linked_list/struct.LinkedList.html#method.split_off
-[drop]: https://github.com/rust-lang/rust/pull/24935
+[24935]: https://github.com/rust-lang/rust/pull/24935
 
 Version 1.0.0 (2015-05-15)
 ========================
@@ -9229,7 +9291,7 @@ Language
   property: generic code cannot behave differently for different type
   arguments except in minor ways.
 * The `unsafe_destructor` feature is now deprecated in favor of the
-  [new `dropck`][dropck]. This change is a major reduction in unsafe
+  [new `dropck`][rfc769]. This change is a major reduction in unsafe
   code.
 
 Libraries
@@ -9237,7 +9299,7 @@ Libraries
 
 * The `thread_local` module [has been renamed to `std::thread`][th].
 * The methods of `IteratorExt` [have been moved to the `Iterator`
-  trait itself][ie].
+  trait itself][23300].
 * Several traits that implement Rust's conventions for type
   conversions, `AsMut`, `AsRef`, `From`, and `Into` have been
   [centralized in the `std::convert` module][con].
@@ -9256,7 +9318,7 @@ Libraries
 * [In method resolution, object methods are resolved before inherent
   methods][meth].
 * [`String::from_str` has been deprecated in favor of the `From` impl,
-  `String::from`][sf].
+  `String::from`][24517].
 * [`io::Error` implements `Sync`][ios].
 * [The `words` method on `&str` has been replaced with
   `split_whitespace`][sw], to avoid answering the tricky question, 'what is
@@ -9304,7 +9366,7 @@ Misc
 [con]: https://github.com/rust-lang/rust/pull/23875
 [cr]: https://github.com/rust-lang/rust/pull/23419
 [fe]: https://github.com/rust-lang/rust/pull/23879
-[ie]: https://github.com/rust-lang/rust/pull/23300
+[23300]: https://github.com/rust-lang/rust/pull/23300
 [inv]: https://github.com/rust-lang/rust/pull/23938
 [ios]: https://github.com/rust-lang/rust/pull/24133
 [lex]: https://github.com/rust-lang/rfcs/blob/master/text/0879-small-base-lexing.md
@@ -9312,7 +9374,7 @@ Misc
 [meth]: https://github.com/rust-lang/rust/pull/24056
 [pat]: https://github.com/rust-lang/rfcs/blob/master/text/0528-string-patterns.md
 [po]: https://github.com/rust-lang/rust/pull/24270
-[sf]: https://github.com/rust-lang/rust/pull/24517
+[24517]: https://github.com/rust-lang/rust/pull/24517
 [slp]: https://github.com/rust-lang/rust/pull/23949
 [spl]: https://github.com/rust-lang/rfcs/blob/master/text/0979-align-splitn-with-other-languages.md
 [sw]: https://github.com/rust-lang/rfcs/blob/master/text/1054-str-words.md
@@ -9330,7 +9392,7 @@ Misc
 [conversion]: https://github.com/rust-lang/rfcs/pull/529
 [num-traits]: https://github.com/rust-lang/rust/pull/23549
 [index-value]: https://github.com/rust-lang/rust/pull/23601
-[dropck]: https://github.com/rust-lang/rfcs/pull/769
+[rfc769]: https://github.com/rust-lang/rfcs/pull/769
 [ci-compare]: https://gist.github.com/brson/a30a77836fbec057cbee
 [fn-inherit]: https://github.com/rust-lang/rust/pull/23282
 [fn-blanket]: https://github.com/rust-lang/rust/pull/23895
index 4f55f37e2e964a0f74a0bc1d4240eeb6c3a1a148..a2d32cdc00fb001b2c03077f9d99ccdf78bd4935 100644 (file)
@@ -510,8 +510,10 @@ pub struct Crate {
     pub attrs: Vec<Attribute>,
     pub items: Vec<P<Item>>,
     pub span: Span,
-    // Placeholder ID if the crate node is a macro placeholder.
-    pub is_placeholder: Option<NodeId>,
+    /// Must be equal to `CRATE_NODE_ID` after the crate root is expanded, but may hold
+    /// expansion placeholders or an unassigned value (`DUMMY_NODE_ID`) before that.
+    pub id: NodeId,
+    pub is_placeholder: bool,
 }
 
 /// Possible values inside of compile-time attribute lists.
index b9c397974a163b5330014dd2247e6916c4be0c65..9a24158ba35d9e76a8c0e700cfb914737eb440eb 100644 (file)
@@ -6,12 +6,13 @@
 use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility};
 use super::{AttrVec, Attribute, Stmt, StmtKind};
 
-use std::fmt::Debug;
+use std::fmt;
+use std::marker::PhantomData;
 
 /// An `AstLike` represents an AST node (or some wrapper around
 /// and AST node) which stores some combination of attributes
 /// and tokens.
-pub trait AstLike: Sized + Debug {
+pub trait AstLike: Sized + fmt::Debug {
     /// This is `true` if this `AstLike` might support 'custom' (proc-macro) inner
     /// attributes. Attributes like `#![cfg]` and `#![cfg_attr]` are not
     /// considered 'custom' attributes
@@ -285,3 +286,37 @@ fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
 derive_has_tokens_no_attrs! {
     Ty, Block, AttrItem, Pat, Path, Visibility
 }
+
+/// A newtype around an `AstLike` node that implements `AstLike` itself.
+pub struct AstLikeWrapper<Wrapped, Tag> {
+    pub wrapped: Wrapped,
+    pub tag: PhantomData<Tag>,
+}
+
+impl<Wrapped, Tag> AstLikeWrapper<Wrapped, Tag> {
+    pub fn new(wrapped: Wrapped, _tag: Tag) -> AstLikeWrapper<Wrapped, Tag> {
+        AstLikeWrapper { wrapped, tag: Default::default() }
+    }
+}
+
+impl<Wrapped: fmt::Debug, Tag> fmt::Debug for AstLikeWrapper<Wrapped, Tag> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("AstLikeWrapper")
+            .field("wrapped", &self.wrapped)
+            .field("tag", &self.tag)
+            .finish()
+    }
+}
+
+impl<Wrapped: AstLike, Tag> AstLike for AstLikeWrapper<Wrapped, Tag> {
+    const SUPPORTS_CUSTOM_INNER_ATTRS: bool = Wrapped::SUPPORTS_CUSTOM_INNER_ATTRS;
+    fn attrs(&self) -> &[Attribute] {
+        self.wrapped.attrs()
+    }
+    fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
+        self.wrapped.visit_attrs(f)
+    }
+    fn tokens_mut(&mut self) -> Option<&mut Option<LazyTokenStream>> {
+        self.wrapped.tokens_mut()
+    }
+}
index ff3b501a0bdc25a8a6793ad13f240a1b8005d7d9..84fe9ad26720ee9ad459fe725cdebf46735833e8 100644 (file)
@@ -41,7 +41,7 @@ pub mod util {
 pub mod visit;
 
 pub use self::ast::*;
-pub use self::ast_like::AstLike;
+pub use self::ast_like::{AstLike, AstLikeWrapper};
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 
index 0fd515750ab49e019c8014cf124bed718a694bd0..9ef78aaf6673aaec316d006fa25ac37cf552fbc6 100644 (file)
@@ -1109,7 +1109,8 @@ pub fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
 }
 
 pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
-    let Crate { attrs, items, span, is_placeholder: _ } = krate;
+    let Crate { attrs, items, span, id, is_placeholder: _ } = krate;
+    vis.visit_id(id);
     visit_attrs(attrs, vis);
     items.flat_map_in_place(|item| vis.flat_map_item(item));
     vis.visit_span(span);
@@ -1554,6 +1555,7 @@ fn dummy() -> Self {
             attrs: Default::default(),
             items: Default::default(),
             span: Default::default(),
+            id: DUMMY_NODE_ID,
             is_placeholder: Default::default(),
         }
     }
index 80a06fa594366de0492471300308e7ab4048e02d..0a391123dd381da28d81bc0be306ef6c74280014 100644 (file)
@@ -34,18 +34,11 @@ fn get_vertical_trim(lines: &[&str]) -> Option<(usize, usize)> {
             i += 1;
         }
 
-        while i < j && lines[i].trim().is_empty() {
-            i += 1;
-        }
         // like the first, a last line of all stars should be omitted
         if j > i && !lines[j - 1].is_empty() && lines[j - 1].chars().all(|c| c == '*') {
             j -= 1;
         }
 
-        while j > i && lines[j - 1].trim().is_empty() {
-            j -= 1;
-        }
-
         if i != 0 || j != lines.len() { Some((i, j)) } else { None }
     }
 
index 6ee1dbe4ae3eebee5781aedd0d3454379c811d16..885537a212fe10197adc6f4f14c04815f38e9220 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_hir::definitions::DefPathData;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Ident};
 use rustc_span::DUMMY_SP;
 
 impl<'hir> LoweringContext<'_, 'hir> {
@@ -34,7 +34,7 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                 }
                 ExprKind::Repeat(ref expr, ref count) => {
                     let expr = self.lower_expr(expr);
-                    let count = self.lower_anon_const(count);
+                    let count = self.lower_array_length(count);
                     hir::ExprKind::Repeat(expr, count)
                 }
                 ExprKind::Tup(ref elts) => hir::ExprKind::Tup(self.lower_exprs(elts)),
@@ -1204,11 +1204,13 @@ fn lower_expr_range(
         };
 
         let fields = self.arena.alloc_from_iter(
-            e1.iter().map(|e| ("start", e)).chain(e2.iter().map(|e| ("end", e))).map(|(s, e)| {
-                let expr = self.lower_expr(&e);
-                let ident = Ident::new(Symbol::intern(s), self.lower_span(e.span));
-                self.expr_field(ident, expr, e.span)
-            }),
+            e1.iter().map(|e| (sym::start, e)).chain(e2.iter().map(|e| (sym::end, e))).map(
+                |(s, e)| {
+                    let expr = self.lower_expr(&e);
+                    let ident = Ident::new(s, self.lower_span(e.span));
+                    self.expr_field(ident, expr, e.span)
+                },
+            ),
         );
 
         hir::ExprKind::Struct(
index 8a9dad2cdd7d86635425ed9853b012abe1003f37..39a8cd405de33a81f765fcdd1bc295f4d242eed9 100644 (file)
@@ -335,7 +335,8 @@ fn visit_trait_item_ref(&mut self, ii: &'hir TraitItemRef) {
     fn visit_impl_item_ref(&mut self, ii: &'hir ImplItemRef) {
         // Do not visit the duplicate information in ImplItemRef. We want to
         // map the actual nodes, not the duplicate ones in the *Ref.
-        let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _ } = *ii;
+        let ImplItemRef { id, ident: _, kind: _, span: _, defaultness: _, trait_item_def_id: _ } =
+            *ii;
 
         self.visit_nested_impl_item(id);
     }
index 92cae4da89ab50059902811575dc9a049ce470f2..ed3abbd5b4d3dfce4874811252bc5c2cacfa70e1 100644 (file)
@@ -925,6 +925,7 @@ fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
                 }
                 AssocItemKind::MacCall(..) => unimplemented!(),
             },
+            trait_item_def_id: self.resolver.get_partial_res(i.id).map(|r| r.base_res().def_id()),
         }
     }
 
index 77738b2c5cc75dce4969cea76fa81cee12ec31e5..35eb716949a13ccf38368ef890119a70e14a3854 100644 (file)
@@ -56,6 +56,7 @@
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::lint::LintBuffer;
+use rustc_session::parse::feature_err;
 use rustc_session::utils::{FlattenNonterminals, NtToTokenstream};
 use rustc_session::Session;
 use rustc_span::hygiene::ExpnId;
@@ -1248,7 +1249,7 @@ fn lower_ty_direct(&mut self, t: &Ty, mut itctx: ImplTraitContext<'_, 'hir>) ->
                 ))
             }
             TyKind::Array(ref ty, ref length) => {
-                hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_anon_const(length))
+                hir::TyKind::Array(self.lower_ty(ty, itctx), self.lower_array_length(length))
             }
             TyKind::Typeof(ref expr) => hir::TyKind::Typeof(self.lower_anon_const(expr)),
             TyKind::TraitObject(ref bounds, kind) => {
@@ -2039,6 +2040,26 @@ fn lower_block_expr(&mut self, b: &Block) -> hir::Expr<'hir> {
         self.expr_block(block, AttrVec::new())
     }
 
+    fn lower_array_length(&mut self, c: &AnonConst) -> hir::ArrayLen {
+        match c.value.kind {
+            ExprKind::Underscore => {
+                if self.sess.features_untracked().generic_arg_infer {
+                    hir::ArrayLen::Infer(self.lower_node_id(c.id), c.value.span)
+                } else {
+                    feature_err(
+                        &self.sess.parse_sess,
+                        sym::generic_arg_infer,
+                        c.value.span,
+                        "using `_` for array lengths is unstable",
+                    )
+                    .emit();
+                    hir::ArrayLen::Body(self.lower_anon_const(c))
+                }
+            }
+            _ => hir::ArrayLen::Body(self.lower_anon_const(c)),
+        }
+    }
+
     fn lower_anon_const(&mut self, c: &AnonConst) -> hir::AnonConst {
         self.with_new_scopes(|this| hir::AnonConst {
             hir_id: this.lower_node_id(c.id),
index 0a9b264aa42636a319b48bca8f2c0a3e2c736c44..ebae77984330ffeec58114301f859be28d39017c 100644 (file)
@@ -24,7 +24,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
                         break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub);
                     }
-                    PatKind::Lit(ref e) => break hir::PatKind::Lit(self.lower_expr(e)),
+                    PatKind::Lit(ref e) => {
+                        break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
+                    }
                     PatKind::TupleStruct(ref qself, ref path, ref pats) => {
                         let qpath = self.lower_qpath(
                             pattern.id,
@@ -81,8 +83,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     }
                     PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => {
                         break hir::PatKind::Range(
-                            e1.as_deref().map(|e| self.lower_expr(e)),
-                            e2.as_deref().map(|e| self.lower_expr(e)),
+                            e1.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
+                            e2.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
                             self.lower_range_end(end, e2.is_some()),
                         );
                     }
@@ -314,4 +316,33 @@ fn lower_range_end(&mut self, e: &RangeEnd, has_end: bool) -> hir::RangeEnd {
             RangeEnd::Excluded | RangeEnd::Included(_) => hir::RangeEnd::Included,
         }
     }
+
+    /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
+    /// or paths for ranges.
+    //
+    // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
+    // That means making this work:
+    //
+    // ```rust,ignore (FIXME)
+    // struct S;
+    // macro_rules! m {
+    //     ($a:expr) => {
+    //         let $a = S;
+    //     }
+    // }
+    // m!(S);
+    // ```
+    fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
+        match expr.kind {
+            ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
+            ExprKind::Path(..) if allow_paths => {}
+            ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
+            _ => {
+                self.diagnostic()
+                    .span_err(expr.span, "arbitrary expressions aren't allowed in patterns");
+                return self.arena.alloc(self.expr_err(expr.span));
+            }
+        }
+        self.lower_expr(expr)
+    }
 }
index 3c3ea2bfd3591fa3dee9beab824508882c1c8fb4..6237a01f6943539fa7e1a3cadc725d6447e4af83 100644 (file)
@@ -302,34 +302,6 @@ fn no_questions_in_bounds(&self, bounds: &GenericBounds, where_: &str, is_trait:
         }
     }
 
-    /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
-    /// or paths for ranges.
-    //
-    // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
-    // That means making this work:
-    //
-    // ```rust,ignore (FIXME)
-    // struct S;
-    // macro_rules! m {
-    //     ($a:expr) => {
-    //         let $a = S;
-    //     }
-    // }
-    // m!(S);
-    // ```
-    fn check_expr_within_pat(&self, expr: &Expr, allow_paths: bool) {
-        match expr.kind {
-            ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
-            ExprKind::Path(..) if allow_paths => {}
-            ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
-            _ => self.err_handler().span_err(
-                expr.span,
-                "arbitrary expressions aren't allowed \
-                                                         in patterns",
-            ),
-        }
-    }
-
     fn check_late_bound_lifetime_defs(&self, params: &[GenericParam]) {
         // Check only lifetime parameters are present and that the lifetime
         // parameters that are present have no bounds.
@@ -1426,25 +1398,6 @@ fn visit_param_bound(&mut self, bound: &'a GenericBound) {
         visit::walk_param_bound(self, bound)
     }
 
-    fn visit_pat(&mut self, pat: &'a Pat) {
-        match &pat.kind {
-            PatKind::Lit(expr) => {
-                self.check_expr_within_pat(expr, false);
-            }
-            PatKind::Range(start, end, _) => {
-                if let Some(expr) = start {
-                    self.check_expr_within_pat(expr, true);
-                }
-                if let Some(expr) = end {
-                    self.check_expr_within_pat(expr, true);
-                }
-            }
-            _ => {}
-        }
-
-        visit::walk_pat(self, pat)
-    }
-
     fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
         self.check_late_bound_lifetime_defs(&t.bound_generic_params);
         visit::walk_poly_trait_ref(self, t, m);
index 4b5703a429e718cc7db732f884fa080783bb27ab..ac9e7d06c4e4006fb9563cd55fe0af516869272b 100644 (file)
@@ -73,11 +73,11 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String {
 }
 
 pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
-    State::new().to_string(f)
+    State::to_string(f)
 }
 
 pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String {
-    State::new().to_string(|s| {
+    State::to_string(|s| {
         s.print_inner_attributes(&krate.attrs);
         for item in &krate.items {
             s.print_item(item);
index b5b87c0b48af1425bc43641ade84e108dddeb024..32a4a0751d8d2d1145953f98c080ea9cdf8e6c29 100644 (file)
@@ -211,7 +211,7 @@ pub fn literal_to_string(lit: token::Lit) -> String {
 }
 
 fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
-    format!("{}{}", State::new().to_string(|s| s.print_visibility(vis)), s)
+    format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
 }
 
 impl std::ops::Deref for State<'_> {
@@ -793,55 +793,55 @@ fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> Cow<
     }
 
     fn ty_to_string(&self, ty: &ast::Ty) -> String {
-        self.to_string(|s| s.print_type(ty))
+        Self::to_string(|s| s.print_type(ty))
     }
 
     fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String {
-        self.to_string(|s| s.print_type_bounds("", bounds))
+        Self::to_string(|s| s.print_type_bounds("", bounds))
     }
 
     fn pat_to_string(&self, pat: &ast::Pat) -> String {
-        self.to_string(|s| s.print_pat(pat))
+        Self::to_string(|s| s.print_pat(pat))
     }
 
     fn expr_to_string(&self, e: &ast::Expr) -> String {
-        self.to_string(|s| s.print_expr(e))
+        Self::to_string(|s| s.print_expr(e))
     }
 
     fn tt_to_string(&self, tt: &TokenTree) -> String {
-        self.to_string(|s| s.print_tt(tt, false))
+        Self::to_string(|s| s.print_tt(tt, false))
     }
 
     fn tts_to_string(&self, tokens: &TokenStream) -> String {
-        self.to_string(|s| s.print_tts(tokens, false))
+        Self::to_string(|s| s.print_tts(tokens, false))
     }
 
     fn stmt_to_string(&self, stmt: &ast::Stmt) -> String {
-        self.to_string(|s| s.print_stmt(stmt))
+        Self::to_string(|s| s.print_stmt(stmt))
     }
 
     fn item_to_string(&self, i: &ast::Item) -> String {
-        self.to_string(|s| s.print_item(i))
+        Self::to_string(|s| s.print_item(i))
     }
 
     fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String {
-        self.to_string(|s| s.print_generic_params(generic_params))
+        Self::to_string(|s| s.print_generic_params(generic_params))
     }
 
     fn path_to_string(&self, p: &ast::Path) -> String {
-        self.to_string(|s| s.print_path(p, false, 0))
+        Self::to_string(|s| s.print_path(p, false, 0))
     }
 
     fn path_segment_to_string(&self, p: &ast::PathSegment) -> String {
-        self.to_string(|s| s.print_path_segment(p, false))
+        Self::to_string(|s| s.print_path_segment(p, false))
     }
 
     fn vis_to_string(&self, v: &ast::Visibility) -> String {
-        self.to_string(|s| s.print_visibility(v))
+        Self::to_string(|s| s.print_visibility(v))
     }
 
     fn block_to_string(&self, blk: &ast::Block) -> String {
-        self.to_string(|s| {
+        Self::to_string(|s| {
             // Containing cbox, will be closed by `print_block` at `}`.
             s.cbox(INDENT_UNIT);
             // Head-ibox, will be closed by `print_block` after `{`.
@@ -851,22 +851,22 @@ fn block_to_string(&self, blk: &ast::Block) -> String {
     }
 
     fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String {
-        self.to_string(|s| s.print_meta_list_item(li))
+        Self::to_string(|s| s.print_meta_list_item(li))
     }
 
     fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String {
-        self.to_string(|s| s.print_attr_item(ai, ai.path.span))
+        Self::to_string(|s| s.print_attr_item(ai, ai.path.span))
     }
 
     fn attribute_to_string(&self, attr: &ast::Attribute) -> String {
-        self.to_string(|s| s.print_attribute(attr))
+        Self::to_string(|s| s.print_attribute(attr))
     }
 
     fn param_to_string(&self, arg: &ast::Param) -> String {
-        self.to_string(|s| s.print_param(arg, false))
+        Self::to_string(|s| s.print_param(arg, false))
     }
 
-    fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String {
+    fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
         let mut printer = State::new();
         f(&mut printer);
         printer.s.eof()
@@ -1202,7 +1202,7 @@ fn print_associated_type(
                 );
             }
             ast::ItemKind::Mod(unsafety, ref mod_kind) => {
-                self.head(self.to_string(|s| {
+                self.head(Self::to_string(|s| {
                     s.print_visibility(&item.vis);
                     s.print_unsafety(unsafety);
                     s.word("mod");
@@ -1228,7 +1228,7 @@ fn print_associated_type(
                 }
             }
             ast::ItemKind::ForeignMod(ref nmod) => {
-                self.head(self.to_string(|s| {
+                self.head(Self::to_string(|s| {
                     s.print_unsafety(nmod.unsafety);
                     s.word("extern");
                 }));
@@ -1287,14 +1287,17 @@ fn print_associated_type(
                 self.print_visibility(&item.vis);
                 self.print_defaultness(defaultness);
                 self.print_unsafety(unsafety);
-                self.word_nbsp("impl");
-                self.print_constness(constness);
+                self.word("impl");
 
-                if !generics.params.is_empty() {
+                if generics.params.is_empty() {
+                    self.nbsp();
+                } else {
                     self.print_generic_params(&generics.params);
                     self.space();
                 }
 
+                self.print_constness(constness);
+
                 if let ast::ImplPolarity::Negative(_) = polarity {
                     self.word("!");
                 }
@@ -1447,7 +1450,7 @@ fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
                 ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
             },
             ast::VisibilityKind::Restricted { ref path, .. } => {
-                let path = self.to_string(|s| s.print_path(path, false, 0));
+                let path = Self::to_string(|s| s.print_path(path, false, 0));
                 if path == "self" || path == "super" {
                     self.word_nbsp(format!("pub({})", path))
                 } else {
@@ -2461,7 +2464,11 @@ fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_pa
                     self.print_path(path, true, 0);
                 }
                 self.nbsp();
-                self.word_space("{");
+                self.word("{");
+                let empty = fields.is_empty() && !etc;
+                if !empty {
+                    self.space();
+                }
                 self.commasep_cmnt(
                     Consistent,
                     &fields,
@@ -2482,7 +2489,9 @@ fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_pa
                     }
                     self.word("..");
                 }
-                self.space();
+                if !empty {
+                    self.space();
+                }
                 self.word("}");
             }
             PatKind::Tuple(ref elts) => {
index a24b7cff9e75c0c2227d029c036c41103c0affba..ba111d394ec26bc20dd81ddd1ae4aa2a5f5d200a 100644 (file)
@@ -409,8 +409,9 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
                     let generics = tcx.generics_of(self.mir_def_id());
                     let param = generics.type_param(&param_ty, tcx);
                     if let Some(generics) = tcx
-                        .hir()
-                        .get_generics(tcx.typeck_root_def_id(self.mir_def_id().to_def_id()))
+                        .typeck_root_def_id(self.mir_def_id().to_def_id())
+                        .as_local()
+                        .and_then(|def_id| tcx.hir().get_generics(def_id))
                     {
                         suggest_constraining_type_param(
                             tcx,
index e2eb125981f138b718742eaab4a5ca1bd6eab131..84acfbf941d05ee0298c520c0f9291326c037956 100644 (file)
@@ -372,7 +372,7 @@ fn describe_field_from_ty(
                     } else {
                         def.non_enum_variant()
                     };
-                    variant.fields[field.index()].ident.to_string()
+                    variant.fields[field.index()].name.to_string()
                 }
                 ty::Tuple(_) => field.index().to_string(),
                 ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
index b5dad5ccdea8ead7f3054015f95d2dc9a42eda7f..8f4e574fbd6188dfb83a607901c378e3cacde23c 100644 (file)
@@ -628,42 +628,39 @@ fn is_error_in_trait(&self, local: Local) -> (bool, Option<Span>) {
         };
         (
             true,
-            td.as_local().and_then(|tld| {
-                let h = hir_map.local_def_id_to_hir_id(tld);
-                match hir_map.find(h) {
-                    Some(Node::Item(hir::Item {
-                        kind: hir::ItemKind::Trait(_, _, _, _, items),
-                        ..
-                    })) => {
-                        let mut f_in_trait_opt = None;
-                        for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
-                            let hi = fi.hir_id();
-                            if !matches!(k, hir::AssocItemKind::Fn { .. }) {
-                                continue;
-                            }
-                            if hir_map.name(hi) != hir_map.name(my_hir) {
-                                continue;
-                            }
-                            f_in_trait_opt = Some(hi);
-                            break;
+            td.as_local().and_then(|tld| match hir_map.find_by_def_id(tld) {
+                Some(Node::Item(hir::Item {
+                    kind: hir::ItemKind::Trait(_, _, _, _, items),
+                    ..
+                })) => {
+                    let mut f_in_trait_opt = None;
+                    for hir::TraitItemRef { id: fi, kind: k, .. } in *items {
+                        let hi = fi.hir_id();
+                        if !matches!(k, hir::AssocItemKind::Fn { .. }) {
+                            continue;
                         }
-                        f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) {
-                            Some(Node::TraitItem(hir::TraitItem {
-                                kind:
-                                    hir::TraitItemKind::Fn(
-                                        hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
-                                        _,
-                                    ),
-                                ..
-                            })) => {
-                                let hir::Ty { span, .. } = inputs[local.index() - 1];
-                                Some(span)
-                            }
-                            _ => None,
-                        })
+                        if hir_map.name(hi) != hir_map.name(my_hir) {
+                            continue;
+                        }
+                        f_in_trait_opt = Some(hi);
+                        break;
                     }
-                    _ => None,
+                    f_in_trait_opt.and_then(|f_in_trait| match hir_map.find(f_in_trait) {
+                        Some(Node::TraitItem(hir::TraitItem {
+                            kind:
+                                hir::TraitItemKind::Fn(
+                                    hir::FnSig { decl: hir::FnDecl { inputs, .. }, .. },
+                                    _,
+                                ),
+                            ..
+                        })) => {
+                            let hir::Ty { span, .. } = inputs[local.index() - 1];
+                            Some(span)
+                        }
+                        _ => None,
+                    })
                 }
+                _ => None,
             }),
         )
     }
@@ -706,13 +703,12 @@ fn show_mutating_upvar(
                         &origin_projection,
                     ) {
                         match captured_place.info.capture_kind {
-                            ty::UpvarCapture::ByRef(ty::UpvarBorrow {
-                                kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
-                                ..
-                            }) => {
+                            ty::UpvarCapture::ByRef(
+                                ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
+                            ) => {
                                 capture_reason = format!("mutable borrow of `{}`", upvar);
                             }
-                            ty::UpvarCapture::ByValue(_) => {
+                            ty::UpvarCapture::ByValue => {
                                 capture_reason = format!("possible mutation of `{}`", upvar);
                             }
                             _ => bug!("upvar `{}` borrowed, but not mutably", upvar),
@@ -897,7 +893,7 @@ fn expected_fn_found_fn_mut_call(&self, err: &mut DiagnosticBuilder<'_>, sp: Spa
         if look_at_return && hir.get_return_block(closure_id).is_some() {
             // ...otherwise we are probably in the tail expression of the function, point at the
             // return type.
-            match hir.get(hir.get_parent_item(fn_call_id)) {
+            match hir.get_by_def_id(hir.get_parent_item(fn_call_id)) {
                 hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. })
                 | hir::Node::TraitItem(hir::TraitItem {
                     ident,
@@ -1076,8 +1072,7 @@ fn get_mut_span_in_struct_field<'tcx>(
         if let ty::Adt(def, _) = ty.kind() {
             let field = def.all_fields().nth(field.index())?;
             // Use the HIR types to construct the diagnostic message.
-            let hir_id = tcx.hir().local_def_id_to_hir_id(field.did.as_local()?);
-            let node = tcx.hir().find(hir_id)?;
+            let node = tcx.hir().find_by_def_id(field.did.as_local()?)?;
             // Now we're dealing with the actual struct that we're going to suggest a change to,
             // we can expect a field that is an immutable reference to a type.
             if let hir::Node::Field(field) = node {
index 80f5f77a025507b320151597b8f75804c4fac261..9aa58f05a8e65e5e55ce8ed0d643c7a123d5f23c 100644 (file)
@@ -704,7 +704,7 @@ fn give_name_if_anonymous_region_appears_in_output(&self, fr: RegionVid) -> Opti
                         hir::AsyncGeneratorKind::Block => " of async block",
                         hir::AsyncGeneratorKind::Closure => " of async closure",
                         hir::AsyncGeneratorKind::Fn => {
-                            let parent_item = hir.get(hir.get_parent_item(mir_hir_id));
+                            let parent_item = hir.get_by_def_id(hir.get_parent_item(mir_hir_id));
                             let output = &parent_item
                                 .fn_decl()
                                 .expect("generator lowered from async fn should be in fn")
index 63ffcb3ec45879c649ef887584b6e98bcefc1e41..7e961e1e750be9a3fb970442b87774ffe24f0129 100644 (file)
@@ -186,7 +186,7 @@ fn do_mir_borrowck<'a, 'tcx>(
         .map(|captured_place| {
             let capture = captured_place.info.capture_kind;
             let by_ref = match capture {
-                ty::UpvarCapture::ByValue(_) => false,
+                ty::UpvarCapture::ByValue => false,
                 ty::UpvarCapture::ByRef(..) => true,
             };
             Upvar { place: captured_place.clone(), by_ref }
@@ -1394,10 +1394,6 @@ fn consume_rvalue(
 
             Rvalue::NullaryOp(_op, _ty) => {
                 // nullary ops take no dynamic input; no borrowck effect.
-                //
-                // FIXME: is above actually true? Do we want to track
-                // the fact that uninitialized data can be created via
-                // `NullOp::Box`?
             }
 
             Rvalue::Aggregate(ref aggregate_kind, ref operands) => {
index 094af20f52efc9ad5573973169e7901284baac78..169de23facce2336cac470575c5245fbb38f1f61 100644 (file)
@@ -171,7 +171,7 @@ fn add_extra_drop_facts(
         for (local, location) in drop_used {
             if !live_locals.contains(&local) {
                 let local_ty = self.cx.body.local_decls[local].ty;
-                if local_ty.has_free_regions(self.cx.typeck.tcx()) {
+                if local_ty.has_free_regions() {
                     self.cx.add_drop_live_facts_for(local, local_ty, &[location], &locations);
                 }
             }
index 1f745f977d4c41b998ba44ccbd31ab1d5d56d560..54365c3279b4af88721817e8b22cbf8192c1855c 100644 (file)
@@ -312,6 +312,7 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
     }
 }
 
+#[track_caller]
 fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: &str) {
     // We sometimes see MIR failures (notably predicate failures) due to
     // the fact that we check rvalue sized predicates here. So use `delay_span_bug`
@@ -425,7 +426,7 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
                         self.cx.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(
                             constant.literal.ty(),
                             uv.def.did,
-                            UserSubsts { substs: uv.substs(self.tcx()), user_self_ty: None },
+                            UserSubsts { substs: uv.substs, user_self_ty: None },
                         )),
                     ) {
                         span_mirbug!(
@@ -1969,7 +1970,7 @@ fn check_operand(&mut self, op: &Operand<'tcx>, location: Location) {
                         let predicates = self.prove_closure_bounds(
                             tcx,
                             def_id.expect_local(),
-                            uv.substs(tcx),
+                            uv.substs,
                             location,
                         );
                         self.normalize_and_prove_instantiated_predicates(
index 1a93b9be99ead615d643ed35704c0230b81b2ca1..caf8ac77df187d1ac75bb1203c03c4153192c981 100644 (file)
 use smallvec::smallvec;
 
 pub struct AsmArgs {
-    templates: Vec<P<ast::Expr>>,
-    operands: Vec<(ast::InlineAsmOperand, Span)>,
+    pub templates: Vec<P<ast::Expr>>,
+    pub operands: Vec<(ast::InlineAsmOperand, Span)>,
     named_args: FxHashMap<Symbol, usize>,
     reg_args: FxHashSet<usize>,
-    clobber_abis: Vec<(Symbol, Span)>,
+    pub clobber_abis: Vec<(Symbol, Span)>,
     options: ast::InlineAsmOptions,
-    options_spans: Vec<Span>,
+    pub options_spans: Vec<Span>,
 }
 
 fn parse_args<'a>(
index a107f5993b546312d74d791f308568a15640ea00..eb08170959bfb1e5f9bd63e08cb33255f037b67d 100644 (file)
@@ -72,6 +72,52 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P<rustc_ast::Expr>, is_ne
     }
 }
 
+fn handle_array_element(
+    cx: &mut base::ExtCtxt<'_>,
+    has_errors: &mut bool,
+    missing_literals: &mut Vec<rustc_span::Span>,
+    expr: &P<rustc_ast::Expr>,
+) -> Option<u8> {
+    match expr.kind {
+        ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
+            if !*has_errors {
+                cx.span_err(expr.span, "cannot concatenate doubly nested array");
+            }
+            *has_errors = true;
+            None
+        }
+        ast::ExprKind::Lit(ref lit) => match lit.kind {
+            ast::LitKind::Int(
+                val,
+                ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
+            ) if val <= u8::MAX.into() => Some(val as u8),
+
+            ast::LitKind::Byte(val) => Some(val),
+            ast::LitKind::ByteStr(_) => {
+                if !*has_errors {
+                    cx.struct_span_err(expr.span, "cannot concatenate doubly nested array")
+                        .note("byte strings are treated as arrays of bytes")
+                        .help("try flattening the array")
+                        .emit();
+                }
+                *has_errors = true;
+                None
+            }
+            _ => {
+                if !*has_errors {
+                    invalid_type_err(cx, expr, true);
+                }
+                *has_errors = true;
+                None
+            }
+        },
+        _ => {
+            missing_literals.push(expr.span);
+            None
+        }
+    }
+}
+
 pub fn expand_concat_bytes(
     cx: &mut base::ExtCtxt<'_>,
     sp: rustc_span::Span,
@@ -88,48 +134,27 @@ pub fn expand_concat_bytes(
         match e.kind {
             ast::ExprKind::Array(ref exprs) => {
                 for expr in exprs {
-                    match expr.kind {
-                        ast::ExprKind::Array(_) => {
-                            if !has_errors {
-                                cx.span_err(expr.span, "cannot concatenate doubly nested array");
-                            }
-                            has_errors = true;
-                        }
-                        ast::ExprKind::Lit(ref lit) => match lit.kind {
-                            ast::LitKind::Int(
-                                val,
-                                ast::LitIntType::Unsuffixed
-                                | ast::LitIntType::Unsigned(ast::UintTy::U8),
-                            ) if val <= u8::MAX.into() => {
-                                accumulator.push(val as u8);
-                            }
-
-                            ast::LitKind::Byte(val) => {
-                                accumulator.push(val);
-                            }
-                            ast::LitKind::ByteStr(_) => {
-                                if !has_errors {
-                                    cx.struct_span_err(
-                                        expr.span,
-                                        "cannot concatenate doubly nested array",
-                                    )
-                                    .note("byte strings are treated as arrays of bytes")
-                                    .help("try flattening the array")
-                                    .emit();
-                                }
-                                has_errors = true;
-                            }
-                            _ => {
-                                if !has_errors {
-                                    invalid_type_err(cx, expr, true);
-                                }
-                                has_errors = true;
-                            }
-                        },
-                        _ => {
-                            missing_literals.push(expr.span);
+                    if let Some(elem) =
+                        handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
+                    {
+                        accumulator.push(elem);
+                    }
+                }
+            }
+            ast::ExprKind::Repeat(ref expr, ref count) => {
+                if let ast::ExprKind::Lit(ast::Lit {
+                    kind: ast::LitKind::Int(count_val, _), ..
+                }) = count.value.kind
+                {
+                    if let Some(elem) =
+                        handle_array_element(cx, &mut has_errors, &mut missing_literals, expr)
+                    {
+                        for _ in 0..count_val {
+                            accumulator.push(elem);
                         }
                     }
+                } else {
+                    cx.span_err(count.value.span, "repeat count is not a positive number");
                 }
             }
             ast::ExprKind::Lit(ref lit) => match lit.kind {
index fc2f04f146e9d3d52deec4049c41d85807c30604..b16f5af66f249b5b80588ad452eca32ddd282cbc 100644 (file)
@@ -715,30 +715,6 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
                     let operand = operand.load_scalar(fx);
                     lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
                 }
-                Rvalue::NullaryOp(NullOp::Box, content_ty) => {
-                    let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap();
-                    let content_ty = fx.monomorphize(content_ty);
-                    let layout = fx.layout_of(content_ty);
-                    let llsize = fx.bcx.ins().iconst(usize_type, layout.size.bytes() as i64);
-                    let llalign = fx.bcx.ins().iconst(usize_type, layout.align.abi.bytes() as i64);
-                    let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
-
-                    // Allocate space:
-                    let def_id =
-                        match fx.tcx.lang_items().require(rustc_hir::LangItem::ExchangeMalloc) {
-                            Ok(id) => id,
-                            Err(s) => {
-                                fx.tcx
-                                    .sess
-                                    .fatal(&format!("allocation of `{}` {}", box_layout.ty, s));
-                            }
-                        };
-                    let instance = ty::Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
-                    let func_ref = fx.get_function_ref(instance);
-                    let call = fx.bcx.ins().call(func_ref, &[llsize, llalign]);
-                    let ptr = fx.bcx.inst_results(call)[0];
-                    lval.write_cvalue(fx, CValue::by_val(ptr, box_layout));
-                }
                 Rvalue::NullaryOp(null_op, ty) => {
                     assert!(
                         lval.layout()
@@ -749,7 +725,6 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
                     let val = match null_op {
                         NullOp::SizeOf => layout.size.bytes(),
                         NullOp::AlignOf => layout.align.abi.bytes(),
-                        NullOp::Box => unreachable!(),
                     };
                     let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into());
                     lval.write_cvalue(fx, val);
index 9a6c45ae98d5f5aeffeb09dd2c16f36fb6ecacef..0c06c77472b9170e41ed462026877e374355542f 100644 (file)
@@ -129,11 +129,13 @@ pub(crate) fn codegen_constant<'tcx>(
     };
     let const_val = match const_.val {
         ConstKind::Value(const_val) => const_val,
-        ConstKind::Unevaluated(uv) if fx.tcx.is_static(uv.def.did) => {
-            assert!(uv.substs(fx.tcx).is_empty());
-            assert!(uv.promoted.is_none());
+        ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
+            if fx.tcx.is_static(def.did) =>
+        {
+            assert!(substs.is_empty());
+            assert!(promoted.is_none());
 
-            return codegen_static_ref(fx, uv.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) {
index 638b025be229d57170e607b15fc0508def83986b..8e203b8cfa0637eb761c1af0b8cc1915caf79529 100644 (file)
@@ -174,7 +174,7 @@ fn dwarf_ty(&mut self, ty: Ty<'tcx>) -> UnitEntryId {
 
                     field_entry.set(
                         gimli::DW_AT_name,
-                        AttributeValue::String(field_def.ident.as_str().to_string().into_bytes()),
+                        AttributeValue::String(field_def.name.as_str().to_string().into_bytes()),
                     );
                     field_entry.set(
                         gimli::DW_AT_data_member_location,
index 87df2f2102bcd42dd3ede437a72a30552ff147e3..a932c1c8372b488dc479bbba4d8fd85f864d14f5 100644 (file)
@@ -38,7 +38,7 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
    fi
 fi
 
-export RUSTFLAGS="$linker -Cpanic=abort -Zsymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot"
+export RUSTFLAGS="$linker -Cpanic=abort -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot"
 
 # FIXME(antoyo): remove once the atomic shim is gone
 if [[ `uname` == 'Darwin' ]]; then
index 9c39c8f91a1ff54ece1fdccfd27b92adef4602eb..281e49fa8a35ed4b6344c58688b792236b42fa3d 100644 (file)
@@ -57,7 +57,7 @@ pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLa
                 (layout.ty.kind(), &layout.variants)
             {
                 if def.is_enum() && !def.variants.is_empty() {
-                    write!(&mut name, "::{}", def.variants[index].ident).unwrap();
+                    write!(&mut name, "::{}", def.variants[index].name).unwrap();
                 }
             }
             if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
index 944d0ce516e0f553b4e2f1a10471a85212eae9f3..b9aeee795504780d4a1355019eeee0bfa5832243 100755 (executable)
@@ -183,7 +183,7 @@ EOF
     git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs
     rm src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs || true # TODO(antoyo): Enable back this test if I ever implement the llvm_asm! macro.
 
-    RUSTC_ARGS="-Zpanic-abort-tests -Zsymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort"
+    RUSTC_ARGS="-Zpanic-abort-tests -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort"
 
     echo "[TEST] rustc test suite"
     COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 src/test/ui/ --rustc-args "$RUSTC_ARGS"
index fd7c58c8e32e2b7b22f2a25c5380cd489f3da595..384596dfff5033c3e010d3bc27f634f00bfc5f1b 100644 (file)
@@ -23,7 +23,7 @@
 use rustc_fs_util::{link_or_copy, path_to_c_string};
 use rustc_middle::bug;
 use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{self, Lto, OutputType, Passes, SwitchWithOptPath};
+use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::InnerSpan;
@@ -106,7 +106,11 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm:
 
 pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
     let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
-        tcx.output_filenames(()).split_dwarf_path(tcx.sess.split_debuginfo(), Some(mod_name))
+        tcx.output_filenames(()).split_dwarf_path(
+            tcx.sess.split_debuginfo(),
+            tcx.sess.opts.debugging_opts.split_dwarf_kind,
+            Some(mod_name),
+        )
     } else {
         None
     };
@@ -892,17 +896,18 @@ extern "C" fn demangle_callback(
                     .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &*module.name);
 
                 let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name);
-                let dwo_out = match cgcx.split_debuginfo {
-                    // Don't change how DWARF is emitted in single mode (or when disabled).
-                    SplitDebuginfo::Off | SplitDebuginfo::Packed => None,
-                    // Emit (a subset of the) DWARF into a separate file in split mode.
-                    SplitDebuginfo::Unpacked => {
-                        if cgcx.target_can_use_split_dwarf {
-                            Some(dwo_out.as_path())
-                        } else {
-                            None
-                        }
-                    }
+                let dwo_out = match (cgcx.split_debuginfo, cgcx.split_dwarf_kind) {
+                    // Don't change how DWARF is emitted when disabled.
+                    (SplitDebuginfo::Off, _) => None,
+                    // Don't provide a DWARF object path if split debuginfo is enabled but this is
+                    // a platform that doesn't support Split DWARF.
+                    _ if !cgcx.target_can_use_split_dwarf => None,
+                    // Don't provide a DWARF object path in single mode, sections will be written
+                    // into the object as normal but ignored by linker.
+                    (_, SplitDwarfKind::Single) => None,
+                    // Emit (a subset of the) DWARF into a separate dwarf object file in split
+                    // mode.
+                    (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()),
                 };
 
                 with_codegen(tm, llmod, config.no_builtins, |cpm| {
@@ -939,7 +944,9 @@ extern "C" fn demangle_callback(
 
     Ok(module.into_compiled_module(
         config.emit_obj != EmitObj::None,
-        cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
+        cgcx.target_can_use_split_dwarf
+            && cgcx.split_debuginfo != SplitDebuginfo::Off
+            && cgcx.split_dwarf_kind == SplitDwarfKind::Split,
         config.emit_bc,
         &cgcx.output_filenames,
     ))
index e0af5653753b664e4f946b1f808ab2ba4a916e4a..32f18419753e9827fb02ab6966c4ad2b246e163f 100644 (file)
@@ -5,12 +5,13 @@
 use llvm::coverageinfo::CounterMappingRegion;
 use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression};
 use rustc_codegen_ssa::traits::{ConstMethods, CoverageInfoMethods};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
-use rustc_hir::def_id::{DefId, DefIdSet};
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefIdSet;
 use rustc_llvm::RustString;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::CodeRegion;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::Symbol;
 
 use std::ffi::CString;
 
@@ -46,7 +47,7 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
     // functions exist. Generate synthetic functions with a (required) single counter, and add the
     // MIR `Coverage` code regions to the `function_coverage_map`, before calling
     // `ctx.take_function_coverage_map()`.
-    if !tcx.sess.instrument_coverage_except_unused_functions() {
+    if cx.codegen_unit.is_code_coverage_dead_code_cgu() {
         add_unused_functions(cx);
     }
 
@@ -271,26 +272,35 @@ fn save_function_record(
 /// `DefId`s (`tcx` query `mir_keys`) minus the codegenned `DefId`s (`tcx` query
 /// `codegened_and_inlined_items`).
 ///
-/// *HOWEVER* the codegenned `DefId`s are partitioned across multiple `CodegenUnit`s (CGUs), and
-/// this function is processing a `function_coverage_map` for the functions (`Instance`/`DefId`)
-/// allocated to only one of those CGUs. We must NOT inject any unused functions's `CodeRegion`s
-/// more than once, so we have to pick a CGUs `function_coverage_map` into which the unused
-/// function will be inserted.
+/// These unused functions are then codegen'd in one of the CGUs which is marked as the
+/// "code coverage dead code cgu" during the partitioning process. This prevents us from generating
+/// code regions for the same function more than once which can lead to linker errors regarding
+/// duplicate symbols.
 fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
-    let tcx = cx.tcx;
+    assert!(cx.codegen_unit.is_code_coverage_dead_code_cgu());
 
-    // FIXME(#79622): Can this solution be simplified and/or improved? Are there other sources
-    // of compiler state data that might help (or better sources that could be exposed, but
-    // aren't yet)?
+    let tcx = cx.tcx;
 
     let ignore_unused_generics = tcx.sess.instrument_coverage_except_unused_generics();
 
-    let all_def_ids: DefIdSet = tcx
+    let eligible_def_ids: DefIdSet = tcx
         .mir_keys(())
         .iter()
         .filter_map(|local_def_id| {
             let def_id = local_def_id.to_def_id();
-            if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) {
+            let kind = tcx.def_kind(def_id);
+            // `mir_keys` will give us `DefId`s for all kinds of things, not
+            // just "functions", like consts, statics, etc. Filter those out.
+            // If `ignore_unused_generics` was specified, filter out any
+            // generic functions from consideration as well.
+            if !matches!(
+                kind,
+                DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator
+            ) {
+                return None;
+            } else if ignore_unused_generics
+                && tcx.generics_of(def_id).requires_monomorphization(tcx)
+            {
                 return None;
             }
             Some(local_def_id.to_def_id())
@@ -299,79 +309,17 @@ fn add_unused_functions<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
 
     let codegenned_def_ids = tcx.codegened_and_inlined_items(());
 
-    let mut unused_def_ids_by_file: FxHashMap<Symbol, Vec<DefId>> = FxHashMap::default();
-    for &non_codegenned_def_id in all_def_ids.difference(codegenned_def_ids) {
-        // Make sure the non-codegenned (unused) function has at least one MIR
-        // `Coverage` statement with a code region, and return its file name.
-        if let Some(non_codegenned_file_name) = tcx.covered_file_name(non_codegenned_def_id) {
-            let def_ids =
-                unused_def_ids_by_file.entry(*non_codegenned_file_name).or_insert_with(Vec::new);
-            def_ids.push(non_codegenned_def_id);
-        }
-    }
+    for &non_codegenned_def_id in eligible_def_ids.difference(codegenned_def_ids) {
+        let codegen_fn_attrs = tcx.codegen_fn_attrs(non_codegenned_def_id);
 
-    if unused_def_ids_by_file.is_empty() {
-        // There are no unused functions with file names to add (in any CGU)
-        return;
-    }
-
-    // Each `CodegenUnit` (CGU) has its own function_coverage_map, and generates a specific binary
-    // with its own coverage map.
-    //
-    // Each covered function `Instance` can be included in only one coverage map, produced from a
-    // specific function_coverage_map, from a specific CGU.
-    //
-    // Since unused functions did not generate code, they are not associated with any CGU yet.
-    //
-    // To avoid injecting the unused functions in multiple coverage maps (for multiple CGUs)
-    // determine which function_coverage_map has the responsibility for publishing unreachable
-    // coverage, based on file name: For each unused function, find the CGU that generates the
-    // first function (based on sorted `DefId`) from the same file.
-    //
-    // Add a new `FunctionCoverage` to the `function_coverage_map`, with unreachable code regions
-    // for each region in it's MIR.
-
-    // Convert the `HashSet` of `codegenned_def_ids` to a sortable vector, and sort them.
-    let mut sorted_codegenned_def_ids: Vec<DefId> = codegenned_def_ids.iter().copied().collect();
-    sorted_codegenned_def_ids.sort_unstable();
-
-    let mut first_covered_def_id_by_file: FxHashMap<Symbol, DefId> = FxHashMap::default();
-    for &def_id in sorted_codegenned_def_ids.iter() {
-        if let Some(covered_file_name) = tcx.covered_file_name(def_id) {
-            // Only add files known to have unused functions
-            if unused_def_ids_by_file.contains_key(covered_file_name) {
-                first_covered_def_id_by_file.entry(*covered_file_name).or_insert(def_id);
-            }
+        // If a function is marked `#[no_coverage]`, then skip generating a
+        // dead code stub for it.
+        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
+            debug!("skipping unused fn marked #[no_coverage]: {:?}", non_codegenned_def_id);
+            continue;
         }
-    }
-
-    // Get the set of def_ids with coverage regions, known by *this* CoverageContext.
-    let cgu_covered_def_ids: DefIdSet = match cx.coverage_context() {
-        Some(ctx) => ctx
-            .function_coverage_map
-            .borrow()
-            .keys()
-            .map(|&instance| instance.def.def_id())
-            .collect(),
-        None => return,
-    };
 
-    let cgu_covered_files: FxHashSet<Symbol> = first_covered_def_id_by_file
-        .iter()
-        .filter_map(
-            |(&file_name, def_id)| {
-                if cgu_covered_def_ids.contains(def_id) { Some(file_name) } else { None }
-            },
-        )
-        .collect();
-
-    // For each file for which this CGU is responsible for adding unused function coverage,
-    // get the `def_id`s for each unused function (if any), define a synthetic function with a
-    // single LLVM coverage counter, and add the function's coverage `CodeRegion`s. to the
-    // function_coverage_map.
-    for covered_file_name in cgu_covered_files {
-        for def_id in unused_def_ids_by_file.remove(&covered_file_name).into_iter().flatten() {
-            cx.define_unused_fn(def_id);
-        }
+        debug!("generating unused fn: {:?}", non_codegenned_def_id);
+        cx.define_unused_fn(non_codegenned_def_id);
     }
 }
index 5f9c41891685b0833cc50f84f70d186682f641cf..5c02e3d0fa7c79408889b658b80d2bcffe37cdc3 100644 (file)
@@ -18,6 +18,7 @@
 use crate::value::Value;
 
 use cstr::cstr;
+use rustc_codegen_ssa::debuginfo::type_names::cpp_like_debuginfo;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
@@ -933,16 +934,16 @@ fn basic_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'l
 
     // When targeting MSVC, emit MSVC style type names for compatibility with
     // .natvis visualizers (and perhaps other existing native debuggers?)
-    let msvc_like_names = cx.tcx.sess.target.is_like_msvc;
+    let cpp_like_debuginfo = cpp_like_debuginfo(cx.tcx);
 
     let (name, encoding) = match t.kind() {
         ty::Never => ("!", DW_ATE_unsigned),
         ty::Tuple(elements) if elements.is_empty() => ("()", DW_ATE_unsigned),
         ty::Bool => ("bool", DW_ATE_boolean),
         ty::Char => ("char", DW_ATE_unsigned_char),
-        ty::Int(int_ty) if msvc_like_names => (int_ty.msvc_basic_name(), DW_ATE_signed),
-        ty::Uint(uint_ty) if msvc_like_names => (uint_ty.msvc_basic_name(), DW_ATE_unsigned),
-        ty::Float(float_ty) if msvc_like_names => (float_ty.msvc_basic_name(), DW_ATE_float),
+        ty::Int(int_ty) if cpp_like_debuginfo => (int_ty.msvc_basic_name(), DW_ATE_signed),
+        ty::Uint(uint_ty) if cpp_like_debuginfo => (uint_ty.msvc_basic_name(), DW_ATE_unsigned),
+        ty::Float(float_ty) if cpp_like_debuginfo => (float_ty.msvc_basic_name(), DW_ATE_float),
         ty::Int(int_ty) => (int_ty.name_str(), DW_ATE_signed),
         ty::Uint(uint_ty) => (uint_ty.name_str(), DW_ATE_unsigned),
         ty::Float(float_ty) => (float_ty.name_str(), DW_ATE_float),
@@ -959,7 +960,7 @@ fn basic_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'l
         )
     };
 
-    if !msvc_like_names {
+    if !cpp_like_debuginfo {
         return ty_metadata;
     }
 
@@ -1072,7 +1073,11 @@ pub fn compile_unit_metadata<'ll, 'tcx>(
     let output_filenames = tcx.output_filenames(());
     let split_name = if tcx.sess.target_can_use_split_dwarf() {
         output_filenames
-            .split_dwarf_path(tcx.sess.split_debuginfo(), Some(codegen_unit_name))
+            .split_dwarf_path(
+                tcx.sess.split_debuginfo(),
+                tcx.sess.opts.debugging_opts.split_dwarf_kind,
+                Some(codegen_unit_name),
+            )
             // We get a path relative to the working directory from split_dwarf_path
             .map(|f| tcx.sess.source_map().path_mapping().map_prefix(f).0)
     } else {
@@ -1295,7 +1300,7 @@ fn create_member_descriptions<'ll>(
                 let name = if self.variant.ctor_kind == CtorKind::Fn {
                     format!("__{}", i)
                 } else {
-                    f.ident.to_string()
+                    f.name.to_string()
                 };
                 let field = layout.field(cx, i);
                 MemberDescription {
@@ -1475,7 +1480,7 @@ fn create_member_descriptions<'ll>(
             .map(|(i, f)| {
                 let field = self.layout.field(cx, i);
                 MemberDescription {
-                    name: f.ident.to_string(),
+                    name: f.name.to_string(),
                     type_metadata: type_metadata(cx, field.ty, self.span),
                     offset: Size::ZERO,
                     size: field.size,
@@ -1521,13 +1526,6 @@ fn prepare_union_metadata<'ll, 'tcx>(
 // Enums
 //=-----------------------------------------------------------------------------
 
-/// DWARF variant support is only available starting in LLVM 8, but
-/// on MSVC we have to use the fallback mode, because LLVM doesn't
-/// lower variant parts to PDB.
-fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool {
-    cx.sess().target.is_like_msvc
-}
-
 // FIXME(eddyb) maybe precompute this? Right now it's computed once
 // per generator monomorphization, but it doesn't depend on substs.
 fn generator_layout_and_saved_local_names<'tcx>(
@@ -1602,7 +1600,10 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
             _ => bug!(),
         };
 
-        let fallback = use_enum_fallback(cx);
+        // While LLVM supports generating debuginfo for variant types (enums), it doesn't support
+        // lowering that debuginfo to CodeView records for msvc targets. So if we are targeting
+        // msvc, then we need to use a different, fallback encoding of the debuginfo.
+        let fallback = cpp_like_debuginfo(cx.tcx);
         // This will always find the metadata in the type map.
         let self_metadata = type_metadata(cx, self.enum_type, self.span);
 
@@ -1949,7 +1950,7 @@ enum VariantInfo<'a, 'tcx> {
 impl<'tcx> VariantInfo<'_, 'tcx> {
     fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
         match self {
-            VariantInfo::Adt(variant) => f(variant.ident.as_str()),
+            VariantInfo::Adt(variant) => f(variant.name.as_str()),
             VariantInfo::Generator { variant_index, .. } => {
                 f(&GeneratorSubsts::variant_name(*variant_index))
             }
@@ -1958,7 +1959,7 @@ fn map_struct_name<R>(&self, f: impl FnOnce(&str) -> R) -> R {
 
     fn variant_name(&self) -> String {
         match self {
-            VariantInfo::Adt(variant) => variant.ident.to_string(),
+            VariantInfo::Adt(variant) => variant.name.to_string(),
             VariantInfo::Generator { variant_index, .. } => {
                 // Since GDB currently prints out the raw discriminant along
                 // with every variant, make each variant name be just the value
@@ -1972,7 +1973,7 @@ fn variant_name(&self) -> String {
     fn field_name(&self, i: usize) -> String {
         let field_name = match *self {
             VariantInfo::Adt(variant) if variant.ctor_kind != CtorKind::Fn => {
-                Some(variant.fields[i].ident.name)
+                Some(variant.fields[i].name)
             }
             VariantInfo::Generator {
                 generator_layout,
@@ -2062,7 +2063,7 @@ fn prepare_enum_metadata<'ll, 'tcx>(
         let enumerators_metadata: Vec<_> = match enum_type.kind() {
             ty::Adt(def, _) => iter::zip(def.discriminants(tcx), &def.variants)
                 .map(|((_, discr), v)| {
-                    let name = v.ident.as_str();
+                    let name = v.name.as_str();
                     let is_unsigned = match discr.ty.kind() {
                         ty::Int(_) => false,
                         ty::Uint(_) => true,
@@ -2155,7 +2156,10 @@ fn prepare_enum_metadata<'ll, 'tcx>(
         return FinalMetadata(discriminant_type_metadata(tag.value));
     }
 
-    if use_enum_fallback(cx) {
+    // While LLVM supports generating debuginfo for variant types (enums), it doesn't support
+    // lowering that debuginfo to CodeView records for msvc targets. So if we are targeting
+    // msvc, then we need to use a different encoding of the debuginfo.
+    if cpp_like_debuginfo(tcx) {
         let discriminant_type_metadata = match layout.variants {
             Variants::Single { .. } => None,
             Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, tag, .. }
index 3e7371179cc7270d13d360e0a9ad1cd7896b7dc5..d1cea147a7a709b653e9e6283313dcba9ac26050 100644 (file)
@@ -160,17 +160,17 @@ fn dbg_var_addr(
         // the values should match the ones in the DWARF standard anyway.
         let op_deref = || unsafe { llvm::LLVMRustDIBuilderCreateOpDeref() };
         let op_plus_uconst = || unsafe { llvm::LLVMRustDIBuilderCreateOpPlusUconst() };
-        let mut addr_ops = SmallVec::<[_; 8]>::new();
+        let mut addr_ops = SmallVec::<[u64; 8]>::new();
 
         if direct_offset.bytes() > 0 {
             addr_ops.push(op_plus_uconst());
-            addr_ops.push(direct_offset.bytes() as i64);
+            addr_ops.push(direct_offset.bytes() as u64);
         }
         for &offset in indirect_offsets {
             addr_ops.push(op_deref());
             if offset.bytes() > 0 {
                 addr_ops.push(op_plus_uconst());
-                addr_ops.push(offset.bytes() as i64);
+                addr_ops.push(offset.bytes() as u64);
             }
         }
 
@@ -507,7 +507,7 @@ fn get_containing_scope<'ll, 'tcx>(
                         ty::Adt(def, ..) if !def.is_box() => {
                             // Again, only create type information if full debuginfo is enabled
                             if cx.sess().opts.debuginfo == DebugInfo::Full
-                                && !impl_self_ty.definitely_needs_subst(cx.tcx)
+                                && !impl_self_ty.needs_subst()
                             {
                                 Some(type_metadata(cx, impl_self_ty, rustc_span::DUMMY_SP))
                             } else {
index 07d49b6e72996d47f126f89e9fda1f1602e98c57..1e795efa2e1bf1a8e0b69247a0207bdc841b1f12 100644 (file)
@@ -791,7 +791,7 @@ fn get_rust_try_fn<'ll, 'tcx>(
     )));
     // `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32`
     let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig(
-        vec![try_fn_ty, i8p, catch_fn_ty].into_iter(),
+        [try_fn_ty, i8p, catch_fn_ty].into_iter(),
         tcx.types.i32,
         false,
         hir::Unsafety::Unsafe,
index 6450b7490bd2bdb800336cb2c47cb4f83f5b47fc..f2782f84f557bde27a416bc6bb1b19d3716109b3 100644 (file)
@@ -2108,7 +2108,7 @@ pub fn LLVMRustDIBuilderInsertDeclareAtEnd<'a>(
         Builder: &DIBuilder<'a>,
         Val: &'a Value,
         VarInfo: &'a DIVariable,
-        AddrOps: *const i64,
+        AddrOps: *const u64,
         AddrOpsCount: c_uint,
         DL: &'a DILocation,
         InsertAtEnd: &'a BasicBlock,
@@ -2199,8 +2199,8 @@ pub fn LLVMRustDIBuilderCreateDebugLocation<'a>(
         Scope: &'a DIScope,
         InlinedAt: Option<&'a DILocation>,
     ) -> &'a DILocation;
-    pub fn LLVMRustDIBuilderCreateOpDeref() -> i64;
-    pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> i64;
+    pub fn LLVMRustDIBuilderCreateOpDeref() -> u64;
+    pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
 
     #[allow(improper_ctypes)]
     pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
index f8c919ec2aa33a38af80f3b90be2c5b3877418d7..81d0603bc5200f16c10637bcf205d50d8286d29a 100644 (file)
@@ -49,7 +49,7 @@ fn uncached_llvm_type<'a, 'tcx>(
                 (layout.ty.kind(), &layout.variants)
             {
                 if def.is_enum() && !def.variants.is_empty() {
-                    write!(&mut name, "::{}", def.variants[index].ident).unwrap();
+                    write!(&mut name, "::{}", def.variants[index].name).unwrap();
                 }
             }
             if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
index 18dbcd8e52da8798d935dc515a3e00de41c52c80..6c6ee363ea310c1480c3208d2c3596793a4167cd 100644 (file)
@@ -14,12 +14,14 @@ tracing = "0.1"
 libc = "0.2.50"
 jobserver = "0.1.22"
 tempfile = "3.2"
+thorin-dwp = "0.1.1"
 pathdiff = "0.2.0"
 snap = "1"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 regex = "1.4"
 
 rustc_serialize = { path = "../rustc_serialize" }
+rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_span = { path = "../rustc_span" }
 rustc_middle = { path = "../rustc_middle" }
@@ -39,6 +41,6 @@ rustc_target = { path = "../rustc_target" }
 rustc_session = { path = "../rustc_session" }
 
 [dependencies.object]
-version = "0.26.2"
+version = "0.28.0"
 default-features = false
 features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
index 42a28f9429845a0c00e55f250bd3cb0e427e724b..f7fe194d207d31faf611f23d877195b93bd83ba6 100644 (file)
@@ -1,11 +1,13 @@
+use rustc_arena::TypedArena;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
+use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{ErrorReported, Handler};
 use rustc_fs_util::fix_windows_verbatim_for_gcc;
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
-use rustc_session::config::{OutputFilenames, OutputType, PrintRequest};
+use rustc_session::config::{OutputFilenames, OutputType, PrintRequest, SplitDwarfKind};
 use rustc_session::cstore::DllImport;
 use rustc_session::output::{check_file_is_writeable, invalid_output_for_target, out_filename};
 use rustc_session::search_paths::PathKind;
 use regex::Regex;
 use tempfile::Builder as TempFileBuilder;
 
-use std::ffi::{OsStr, OsString};
+use std::borrow::Borrow;
+use std::ffi::OsString;
+use std::fs::{File, OpenOptions};
+use std::io::{BufWriter, Write};
 use std::lazy::OnceCell;
 use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
@@ -134,31 +139,47 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
         }
     }
 
-    // Remove the temporary object file and metadata if we aren't saving temps
+    // Remove the temporary object file and metadata if we aren't saving temps.
     sess.time("link_binary_remove_temps", || {
-        if !sess.opts.cg.save_temps {
-            let remove_temps_from_module = |module: &CompiledModule| {
-                if let Some(ref obj) = module.object {
-                    ensure_removed(sess.diagnostic(), obj);
-                }
-
-                if let Some(ref obj) = module.dwarf_object {
-                    ensure_removed(sess.diagnostic(), obj);
-                }
-            };
+        // If the user requests that temporaries are saved, don't delete any.
+        if sess.opts.cg.save_temps {
+            return;
+        }
 
-            if sess.opts.output_types.should_link() && !preserve_objects_for_their_debuginfo(sess) {
-                for module in &codegen_results.modules {
-                    remove_temps_from_module(module);
-                }
+        let remove_temps_from_module = |module: &CompiledModule| {
+            if let Some(ref obj) = module.object {
+                ensure_removed(sess.diagnostic(), obj);
             }
+        };
+
+        // Otherwise, always remove the metadata and allocator module temporaries.
+        if let Some(ref metadata_module) = codegen_results.metadata_module {
+            remove_temps_from_module(metadata_module);
+        }
+
+        if let Some(ref allocator_module) = codegen_results.allocator_module {
+            remove_temps_from_module(allocator_module);
+        }
 
-            if let Some(ref metadata_module) = codegen_results.metadata_module {
-                remove_temps_from_module(metadata_module);
+        // If no requested outputs require linking, then the object temporaries should
+        // be kept.
+        if !sess.opts.output_types.should_link() {
+            return;
+        }
+
+        // Potentially keep objects for their debuginfo.
+        let (preserve_objects, preserve_dwarf_objects) = preserve_objects_for_their_debuginfo(sess);
+        debug!(?preserve_objects, ?preserve_dwarf_objects);
+
+        for module in &codegen_results.modules {
+            if !preserve_objects {
+                remove_temps_from_module(module);
             }
 
-            if let Some(ref allocator_module) = codegen_results.allocator_module {
-                remove_temps_from_module(allocator_module);
+            if !preserve_dwarf_objects {
+                if let Some(ref obj) = module.dwarf_object {
+                    ensure_removed(sess.diagnostic(), obj);
+                }
             }
         }
     });
@@ -245,8 +266,14 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>(
 
     let mut ab = <B as ArchiveBuilder>::new(sess, out_filename, None);
 
-    for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) {
-        ab.add_file(obj);
+    for m in &codegen_results.modules {
+        if let Some(obj) = m.object.as_ref() {
+            ab.add_file(obj);
+        }
+
+        if let Some(dwarf_obj) = m.dwarf_object.as_ref() {
+            ab.add_file(dwarf_obj);
+        }
     }
 
     // Note that in this loop we are ignoring the value of `lib.cfg`. That is,
@@ -502,59 +529,108 @@ fn escape_stdout_stderr_string(s: &[u8]) -> String {
     })
 }
 
-const LLVM_DWP_EXECUTABLE: &'static str = "rust-llvm-dwp";
-
-/// Invoke `llvm-dwp` (shipped alongside rustc) to link debuginfo in object files into a `dwp`
-/// file.
-fn link_dwarf_object<'a, I>(sess: &'a Session, executable_out_filename: &Path, object_files: I)
-where
-    I: IntoIterator<Item: AsRef<OsStr>>,
-{
-    info!("preparing dwp to {}.dwp", executable_out_filename.to_str().unwrap());
-
+/// Use `thorin` (rust implementation of a dwarf packaging utility) to link DWARF objects into a
+/// DWARF package.
+fn link_dwarf_object<'a>(
+    sess: &'a Session,
+    cg_results: &CodegenResults,
+    executable_out_filename: &Path,
+) {
     let dwp_out_filename = executable_out_filename.with_extension("dwp");
-    let mut cmd = Command::new(LLVM_DWP_EXECUTABLE);
-    cmd.arg("-o");
-    cmd.arg(&dwp_out_filename);
-    cmd.args(object_files);
+    debug!(?dwp_out_filename, ?executable_out_filename);
 
-    let mut new_path = sess.get_tools_search_paths(false);
-    if let Some(path) = env::var_os("PATH") {
-        new_path.extend(env::split_paths(&path));
+    #[derive(Default)]
+    struct ThorinSession<Relocations> {
+        arena_data: TypedArena<Vec<u8>>,
+        arena_mmap: TypedArena<Mmap>,
+        arena_relocations: TypedArena<Relocations>,
     }
-    let new_path = env::join_paths(new_path).unwrap();
-    cmd.env("PATH", new_path);
 
-    info!("{:?}", &cmd);
-    match sess.time("run_dwp", || cmd.output()) {
-        Ok(prog) if !prog.status.success() => {
-            sess.struct_err(&format!(
-                "linking dwarf objects with `{}` failed: {}",
-                LLVM_DWP_EXECUTABLE, prog.status
-            ))
-            .note(&format!("{:?}", &cmd))
-            .note(&escape_stdout_stderr_string(&prog.stdout))
-            .note(&escape_stdout_stderr_string(&prog.stderr))
-            .emit();
-            info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr));
-            info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout));
+    impl<Relocations> ThorinSession<Relocations> {
+        fn alloc_mmap<'arena>(&'arena self, data: Mmap) -> &'arena Mmap {
+            (*self.arena_mmap.alloc(data)).borrow()
         }
-        Ok(_) => {}
-        Err(e) => {
-            let dwp_not_found = e.kind() == io::ErrorKind::NotFound;
-            let mut err = if dwp_not_found {
-                sess.struct_err(&format!("linker `{}` not found", LLVM_DWP_EXECUTABLE))
-            } else {
-                sess.struct_err(&format!("could not exec the linker `{}`", LLVM_DWP_EXECUTABLE))
-            };
+    }
 
-            err.note(&e.to_string());
+    impl<Relocations> thorin::Session<Relocations> for ThorinSession<Relocations> {
+        fn alloc_data<'arena>(&'arena self, data: Vec<u8>) -> &'arena [u8] {
+            (*self.arena_data.alloc(data)).borrow()
+        }
 
-            if !dwp_not_found {
-                err.note(&format!("{:?}", &cmd));
+        fn alloc_relocation<'arena>(&'arena self, data: Relocations) -> &'arena Relocations {
+            (*self.arena_relocations.alloc(data)).borrow()
+        }
+
+        fn read_input<'arena>(&'arena self, path: &Path) -> std::io::Result<&'arena [u8]> {
+            let file = File::open(&path)?;
+            let mmap = (unsafe { Mmap::map(file) })?;
+            Ok(self.alloc_mmap(mmap))
+        }
+    }
+
+    match sess.time("run_thorin", || -> Result<(), thorin::Error> {
+        let thorin_sess = ThorinSession::default();
+        let mut package = thorin::DwarfPackage::new(&thorin_sess);
+
+        // Input objs contain .o/.dwo files from the current crate.
+        match sess.opts.debugging_opts.split_dwarf_kind {
+            SplitDwarfKind::Single => {
+                for input_obj in cg_results.modules.iter().filter_map(|m| m.object.as_ref()) {
+                    package.add_input_object(input_obj)?;
+                }
             }
+            SplitDwarfKind::Split => {
+                for input_obj in cg_results.modules.iter().filter_map(|m| m.dwarf_object.as_ref()) {
+                    package.add_input_object(input_obj)?;
+                }
+            }
+        }
 
-            err.emit();
+        // Input rlibs contain .o/.dwo files from dependencies.
+        let input_rlibs = cg_results
+            .crate_info
+            .used_crate_source
+            .values()
+            .filter_map(|csource| csource.rlib.as_ref())
+            .map(|(path, _)| path);
+        for input_rlib in input_rlibs {
+            debug!(?input_rlib);
+            package.add_input_object(input_rlib)?;
+        }
+
+        // Failing to read the referenced objects is expected for dependencies where the path in the
+        // executable will have been cleaned by Cargo, but the referenced objects will be contained
+        // within rlibs provided as inputs.
+        //
+        // If paths have been remapped, then .o/.dwo files from the current crate also won't be
+        // found, but are provided explicitly above.
+        //
+        // Adding an executable is primarily done to make `thorin` check that all the referenced
+        // dwarf objects are found in the end.
+        package.add_executable(
+            &executable_out_filename,
+            thorin::MissingReferencedObjectBehaviour::Skip,
+        )?;
+
+        let output = package.finish()?.write()?;
+        let mut output_stream = BufWriter::new(
+            OpenOptions::new()
+                .read(true)
+                .write(true)
+                .create(true)
+                .truncate(true)
+                .open(dwp_out_filename)?,
+        );
+        output_stream.write_all(&output)?;
+        output_stream.flush()?;
+
+        Ok(())
+    }) {
+        Ok(()) => {}
+        Err(e) => {
+            sess.struct_err("linking dwarf objects with thorin failed")
+                .note(&format!("{:?}", e))
+                .emit();
         }
     }
 }
@@ -900,14 +976,11 @@ fn is_illegal_instruction(_status: &ExitStatus) -> bool {
         SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
 
         // ... and otherwise we're processing a `*.dwp` packed dwarf file.
+        //
         // We cannot rely on the .o paths in the exectuable because they may have been
-        // remapped by --remap-path-prefix and therefore invalid. So we need to provide
-        // the .o paths explicitly
-        SplitDebuginfo::Packed => link_dwarf_object(
-            sess,
-            &out_filename,
-            codegen_results.modules.iter().filter_map(|m| m.object.as_ref()),
-        ),
+        // remapped by --remap-path-prefix and therefore invalid, so we need to provide
+        // the .o/.dwo paths explicitly.
+        SplitDebuginfo::Packed => link_dwarf_object(sess, codegen_results, out_filename),
     }
 
     let strip = strip_value(sess);
@@ -1138,26 +1211,36 @@ fn infer_from(
     bug!("Not enough information provided to determine how to invoke the linker");
 }
 
-/// Returns a boolean indicating whether we should preserve the object files on
-/// the filesystem for their debug information. This is often useful with
-/// split-dwarf like schemes.
-fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
+/// Returns a pair of boolean indicating whether we should preserve the object and
+/// dwarf object files on the filesystem for their debug information. This is often
+/// useful with split-dwarf like schemes.
+fn preserve_objects_for_their_debuginfo(sess: &Session) -> (bool, bool) {
     // If the objects don't have debuginfo there's nothing to preserve.
     if sess.opts.debuginfo == config::DebugInfo::None {
-        return false;
+        return (false, false);
     }
 
     // If we're only producing artifacts that are archives, no need to preserve
     // the objects as they're losslessly contained inside the archives.
-    let output_linked =
-        sess.crate_types().iter().any(|&x| x != CrateType::Rlib && x != CrateType::Staticlib);
-    if !output_linked {
-        return false;
+    if sess.crate_types().iter().all(|&x| x.is_archive()) {
+        return (false, false);
+    }
+
+    match (sess.split_debuginfo(), sess.opts.debugging_opts.split_dwarf_kind) {
+        // If there is no split debuginfo then do not preserve objects.
+        (SplitDebuginfo::Off, _) => (false, false),
+        // If there is packed split debuginfo, then the debuginfo in the objects
+        // has been packaged and the objects can be deleted.
+        (SplitDebuginfo::Packed, _) => (false, false),
+        // If there is unpacked split debuginfo and the current target can not use
+        // split dwarf, then keep objects.
+        (SplitDebuginfo::Unpacked, _) if !sess.target_can_use_split_dwarf() => (true, false),
+        // If there is unpacked split debuginfo and the target can use split dwarf, then
+        // keep the object containing that debuginfo (whether that is an object file or
+        // dwarf object file depends on the split dwarf kind).
+        (SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => (true, false),
+        (SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => (false, true),
     }
-
-    // "unpacked" split debuginfo means that we leave object files as the
-    // debuginfo is found in the original object files themselves
-    sess.split_debuginfo() == SplitDebuginfo::Unpacked
 }
 
 fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {
index 7c97143e80780d97e37fdeef45dce86486f55f66..6849533abc049e7098e8ee154b08bb23d1ed3f9d 100644 (file)
@@ -6,8 +6,8 @@
 
 use object::write::{self, StandardSegment, Symbol, SymbolSection};
 use object::{
-    elf, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection, SectionFlags,
-    SectionKind, SymbolFlags, SymbolKind, SymbolScope,
+    elf, pe, Architecture, BinaryFormat, Endianness, FileFlags, Object, ObjectSection,
+    SectionFlags, SectionKind, SymbolFlags, SymbolKind, SymbolScope,
 };
 
 use snap::write::FrameEncoder;
@@ -95,7 +95,7 @@ fn search_for_metadata<'a>(
         .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
 }
 
-fn create_object_file(sess: &Session) -> Option<write::Object> {
+fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
     let endianness = match sess.target.options.endian {
         Endian::Little => Endianness::Little,
         Endian::Big => Endianness::Big,
@@ -135,12 +135,24 @@ fn create_object_file(sess: &Session) -> Option<write::Object> {
         Architecture::Mips => {
             // copied from `mipsel-linux-gnu-gcc foo.c -c` and
             // inspecting the resulting `e_flags` field.
-            let e_flags = elf::EF_MIPS_ARCH_32R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+            let e_flags = elf::EF_MIPS_CPIC
+                | elf::EF_MIPS_PIC
+                | if sess.target.options.cpu.contains("r6") {
+                    elf::EF_MIPS_ARCH_32R6 | elf::EF_MIPS_NAN2008
+                } else {
+                    elf::EF_MIPS_ARCH_32R2
+                };
             file.flags = FileFlags::Elf { e_flags };
         }
         Architecture::Mips64 => {
             // copied from `mips64el-linux-gnuabi64-gcc foo.c -c`
-            let e_flags = elf::EF_MIPS_ARCH_64R2 | elf::EF_MIPS_CPIC | elf::EF_MIPS_PIC;
+            let e_flags = elf::EF_MIPS_CPIC
+                | elf::EF_MIPS_PIC
+                | if sess.target.options.cpu.contains("r6") {
+                    elf::EF_MIPS_ARCH_64R6 | elf::EF_MIPS_NAN2008
+                } else {
+                    elf::EF_MIPS_ARCH_64R2
+                };
             file.flags = FileFlags::Elf { e_flags };
         }
         Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
@@ -216,13 +228,12 @@ pub fn create_rmeta_file(sess: &Session, metadata: &[u8]) -> Vec<u8> {
     );
     match file.format() {
         BinaryFormat::Coff => {
-            const IMAGE_SCN_LNK_REMOVE: u32 = 0;
             file.section_mut(section).flags =
-                SectionFlags::Coff { characteristics: IMAGE_SCN_LNK_REMOVE };
+                SectionFlags::Coff { characteristics: pe::IMAGE_SCN_LNK_REMOVE };
         }
         BinaryFormat::Elf => {
-            const SHF_EXCLUDE: u64 = 0x80000000;
-            file.section_mut(section).flags = SectionFlags::Elf { sh_flags: SHF_EXCLUDE };
+            file.section_mut(section).flags =
+                SectionFlags::Elf { sh_flags: elf::SHF_EXCLUDE as u64 };
         }
         _ => {}
     };
index baafa74b13146b9e5c9254791112df97ac6575d9..aeddd926896e8233cb456ead084ac3ce997262c5 100644 (file)
@@ -76,7 +76,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, cnum: CrateNum) -> DefIdMap<
             //
             // As a result, if this id is an FFI item (foreign item) then we only
             // let it through if it's included statically.
-            match tcx.hir().get(tcx.hir().local_def_id_to_hir_id(def_id)) {
+            match tcx.hir().get_by_def_id(def_id) {
                 Node::ForeignItem(..) => {
                     tcx.is_statically_included_foreign_item(def_id).then_some(def_id)
                 }
index 0281fd929c5fe9234666a205dd49ca4ac58739db..bea454458c4c028170767eac17cd63b29acb43a9 100644 (file)
@@ -286,7 +286,11 @@ pub fn new(
         module_name: &str,
     ) -> TargetMachineFactoryConfig {
         let split_dwarf_file = if cgcx.target_can_use_split_dwarf {
-            cgcx.output_filenames.split_dwarf_path(cgcx.split_debuginfo, Some(module_name))
+            cgcx.output_filenames.split_dwarf_path(
+                cgcx.split_debuginfo,
+                cgcx.split_dwarf_kind,
+                Some(module_name),
+            )
         } else {
             None
         };
@@ -329,6 +333,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub target_arch: String,
     pub debuginfo: config::DebugInfo,
     pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
+    pub split_dwarf_kind: rustc_session::config::SplitDwarfKind,
 
     // Number of cgus excluding the allocator/metadata modules
     pub total_cgus: usize,
@@ -1060,6 +1065,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         target_arch: tcx.sess.target.arch.clone(),
         debuginfo: tcx.sess.opts.debuginfo,
         split_debuginfo: tcx.sess.split_debuginfo(),
+        split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf_kind,
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
index 00e76800d474cc6510a318b90a6c0804f4d4fac0..61322a6e556ed02cd418b28793035f0dc1b649ad 100644 (file)
@@ -53,14 +53,14 @@ fn push_debuginfo_type_name<'tcx>(
 ) {
     // When targeting MSVC, emit C++ style type names for compatibility with
     // .natvis visualizers (and perhaps other existing native debuggers?)
-    let cpp_like_names = cpp_like_names(tcx);
+    let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
 
     match *t.kind() {
         ty::Bool => output.push_str("bool"),
         ty::Char => output.push_str("char"),
         ty::Str => output.push_str("str"),
         ty::Never => {
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 output.push_str("never$");
             } else {
                 output.push('!');
@@ -71,7 +71,7 @@ fn push_debuginfo_type_name<'tcx>(
         ty::Float(float_ty) => output.push_str(float_ty.name_str()),
         ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output),
         ty::Adt(def, substs) => {
-            if def.is_enum() && cpp_like_names {
+            if def.is_enum() && cpp_like_debuginfo {
                 msvc_enum_fallback(tcx, t, def, substs, output, visited);
             } else {
                 push_item_name(tcx, def.did, qualified, output);
@@ -79,7 +79,7 @@ fn push_debuginfo_type_name<'tcx>(
             }
         }
         ty::Tuple(component_types) => {
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 output.push_str("tuple$<");
             } else {
                 output.push('(');
@@ -87,20 +87,20 @@ fn push_debuginfo_type_name<'tcx>(
 
             for component_type in component_types {
                 push_debuginfo_type_name(tcx, component_type.expect_ty(), true, output, visited);
-                push_arg_separator(cpp_like_names, output);
+                push_arg_separator(cpp_like_debuginfo, output);
             }
             if !component_types.is_empty() {
                 pop_arg_separator(output);
             }
 
-            if cpp_like_names {
-                push_close_angle_bracket(cpp_like_names, output);
+            if cpp_like_debuginfo {
+                push_close_angle_bracket(cpp_like_debuginfo, output);
             } else {
                 output.push(')');
             }
         }
         ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => {
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 match mutbl {
                     hir::Mutability::Not => output.push_str("ptr_const$<"),
                     hir::Mutability::Mut => output.push_str("ptr_mut$<"),
@@ -115,8 +115,8 @@ fn push_debuginfo_type_name<'tcx>(
 
             push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
 
-            if cpp_like_names {
-                push_close_angle_bracket(cpp_like_names, output);
+            if cpp_like_debuginfo {
+                push_close_angle_bracket(cpp_like_debuginfo, output);
             }
         }
         ty::Ref(_, inner_type, mutbl) => {
@@ -126,7 +126,7 @@ fn push_debuginfo_type_name<'tcx>(
             // types out to aid debugging in MSVC.
             let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str);
 
-            if !cpp_like_names {
+            if !cpp_like_debuginfo {
                 output.push('&');
                 output.push_str(mutbl.prefix_str());
             } else if !is_slice_or_str {
@@ -138,12 +138,12 @@ fn push_debuginfo_type_name<'tcx>(
 
             push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
 
-            if cpp_like_names && !is_slice_or_str {
-                push_close_angle_bracket(cpp_like_names, output);
+            if cpp_like_debuginfo && !is_slice_or_str {
+                push_close_angle_bracket(cpp_like_debuginfo, output);
             }
         }
         ty::Array(inner_type, len) => {
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 output.push_str("array$<");
                 push_debuginfo_type_name(tcx, inner_type, true, output, visited);
                 match len.val {
@@ -162,7 +162,7 @@ fn push_debuginfo_type_name<'tcx>(
             }
         }
         ty::Slice(inner_type) => {
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 output.push_str("slice$<");
             } else {
                 output.push('[');
@@ -170,8 +170,8 @@ fn push_debuginfo_type_name<'tcx>(
 
             push_debuginfo_type_name(tcx, inner_type, true, output, visited);
 
-            if cpp_like_names {
-                push_close_angle_bracket(cpp_like_names, output);
+            if cpp_like_debuginfo {
+                push_close_angle_bracket(cpp_like_debuginfo, output);
             } else {
                 output.push(']');
             }
@@ -179,7 +179,7 @@ fn push_debuginfo_type_name<'tcx>(
         ty::Dynamic(ref trait_data, ..) => {
             let auto_traits: SmallVec<[DefId; 4]> = trait_data.auto_traits().collect();
 
-            let has_enclosing_parens = if cpp_like_names {
+            let has_enclosing_parens = if cpp_like_debuginfo {
                 output.push_str("dyn$<");
                 false
             } else {
@@ -216,14 +216,14 @@ fn push_debuginfo_type_name<'tcx>(
                     }
 
                     for (item_def_id, ty) in projection_bounds {
-                        push_arg_separator(cpp_like_names, output);
+                        push_arg_separator(cpp_like_debuginfo, output);
 
-                        if cpp_like_names {
+                        if cpp_like_debuginfo {
                             output.push_str("assoc$<");
                             push_item_name(tcx, item_def_id, false, output);
-                            push_arg_separator(cpp_like_names, output);
+                            push_arg_separator(cpp_like_debuginfo, output);
                             push_debuginfo_type_name(tcx, ty, true, output, visited);
-                            push_close_angle_bracket(cpp_like_names, output);
+                            push_close_angle_bracket(cpp_like_debuginfo, output);
                         } else {
                             push_item_name(tcx, item_def_id, false, output);
                             output.push('=');
@@ -231,11 +231,11 @@ fn push_debuginfo_type_name<'tcx>(
                         }
                     }
 
-                    push_close_angle_bracket(cpp_like_names, output);
+                    push_close_angle_bracket(cpp_like_debuginfo, output);
                 }
 
                 if auto_traits.len() != 0 {
-                    push_auto_trait_separator(cpp_like_names, output);
+                    push_auto_trait_separator(cpp_like_debuginfo, output);
                 }
             }
 
@@ -252,14 +252,14 @@ fn push_debuginfo_type_name<'tcx>(
 
                 for auto_trait in auto_traits {
                     output.push_str(&auto_trait);
-                    push_auto_trait_separator(cpp_like_names, output);
+                    push_auto_trait_separator(cpp_like_debuginfo, output);
                 }
 
                 pop_auto_trait_separator(output);
             }
 
-            if cpp_like_names {
-                push_close_angle_bracket(cpp_like_names, output);
+            if cpp_like_debuginfo {
+                push_close_angle_bracket(cpp_like_debuginfo, output);
             } else if has_enclosing_parens {
                 output.push(')');
             }
@@ -279,7 +279,7 @@ fn push_debuginfo_type_name<'tcx>(
             // use a dummy string that should make it clear
             // that something unusual is going on
             if !visited.insert(t) {
-                output.push_str(if cpp_like_names {
+                output.push_str(if cpp_like_debuginfo {
                     "recursive_type$"
                 } else {
                     "<recursive_type>"
@@ -290,7 +290,7 @@ fn push_debuginfo_type_name<'tcx>(
             let sig =
                 tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), t.fn_sig(tcx));
 
-            if cpp_like_names {
+            if cpp_like_debuginfo {
                 // Format as a C++ function pointer: return_type (*)(params...)
                 if sig.output().is_unit() {
                     output.push_str("void");
@@ -313,7 +313,7 @@ fn push_debuginfo_type_name<'tcx>(
             if !sig.inputs().is_empty() {
                 for &parameter_type in sig.inputs() {
                     push_debuginfo_type_name(tcx, parameter_type, true, output, visited);
-                    push_arg_separator(cpp_like_names, output);
+                    push_arg_separator(cpp_like_debuginfo, output);
                 }
                 pop_arg_separator(output);
             }
@@ -328,7 +328,7 @@ fn push_debuginfo_type_name<'tcx>(
 
             output.push(')');
 
-            if !cpp_like_names && !sig.output().is_unit() {
+            if !cpp_like_debuginfo && !sig.output().is_unit() {
                 output.push_str(" -> ");
                 push_debuginfo_type_name(tcx, sig.output(), true, output, visited);
             }
@@ -409,14 +409,14 @@ fn msvc_enum_fallback<'tcx>(
             let max = dataful_discriminant_range.end;
             let max = tag.value.size(&tcx).truncate(max);
 
-            let dataful_variant_name = def.variants[*dataful_variant].ident.as_str();
+            let dataful_variant_name = def.variants[*dataful_variant].name.as_str();
 
             output.push_str(&format!(", {}, {}, {}", min, max, dataful_variant_name));
         } else if let Variants::Single { index: variant_idx } = &layout.variants {
             // Uninhabited enums can't be constructed and should never need to be visualized so
             // skip this step for them.
             if def.variants.len() != 0 {
-                let variant = def.variants[*variant_idx].ident.as_str();
+                let variant = def.variants[*variant_idx].name.as_str();
 
                 output.push_str(&format!(", {}", variant));
             }
@@ -426,9 +426,9 @@ fn msvc_enum_fallback<'tcx>(
 
     const NON_CPP_AUTO_TRAIT_SEPARATOR: &str = " + ";
 
-    fn push_auto_trait_separator(cpp_like_names: bool, output: &mut String) {
-        if cpp_like_names {
-            push_arg_separator(cpp_like_names, output);
+    fn push_auto_trait_separator(cpp_like_debuginfo: bool, output: &mut String) {
+        if cpp_like_debuginfo {
+            push_arg_separator(cpp_like_debuginfo, output);
         } else {
             output.push_str(NON_CPP_AUTO_TRAIT_SEPARATOR);
         }
@@ -457,11 +457,11 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
     t: Ty<'tcx>,
     trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
 ) -> String {
-    let cpp_like_names = cpp_like_names(tcx);
+    let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
 
     let mut vtable_name = String::with_capacity(64);
 
-    if cpp_like_names {
+    if cpp_like_debuginfo {
         vtable_name.push_str("impl$<");
     } else {
         vtable_name.push('<');
@@ -470,7 +470,7 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
     let mut visited = FxHashSet::default();
     push_debuginfo_type_name(tcx, t, true, &mut vtable_name, &mut visited);
 
-    if cpp_like_names {
+    if cpp_like_debuginfo {
         vtable_name.push_str(", ");
     } else {
         vtable_name.push_str(" as ");
@@ -486,9 +486,9 @@ pub fn compute_debuginfo_vtable_name<'tcx>(
         vtable_name.push_str("_");
     }
 
-    push_close_angle_bracket(cpp_like_names, &mut vtable_name);
+    push_close_angle_bracket(cpp_like_debuginfo, &mut vtable_name);
 
-    let suffix = if cpp_like_names { "::vtable$" } else { "::{vtable}" };
+    let suffix = if cpp_like_debuginfo { "::vtable$" } else { "::{vtable}" };
 
     vtable_name.reserve_exact(suffix.len());
     vtable_name.push_str(suffix);
@@ -519,12 +519,18 @@ fn push_unqualified_item_name(
             output.push_str(tcx.crate_name(def_id.krate).as_str());
         }
         DefPathData::ClosureExpr if tcx.generator_kind(def_id).is_some() => {
+            let key = match tcx.generator_kind(def_id).unwrap() {
+                hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) => "async_block",
+                hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Closure) => "async_closure",
+                hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Fn) => "async_fn",
+                hir::GeneratorKind::Gen => "generator",
+            };
             // Generators look like closures, but we want to treat them differently
             // in the debug info.
-            if cpp_like_names(tcx) {
-                write!(output, "generator${}", disambiguated_data.disambiguator).unwrap();
+            if cpp_like_debuginfo(tcx) {
+                write!(output, "{}${}", key, disambiguated_data.disambiguator).unwrap();
             } else {
-                write!(output, "{{generator#{}}}", disambiguated_data.disambiguator).unwrap();
+                write!(output, "{{{}#{}}}", key, disambiguated_data.disambiguator).unwrap();
             }
         }
         _ => match disambiguated_data.data.name() {
@@ -532,7 +538,7 @@ fn push_unqualified_item_name(
                 output.push_str(name.as_str());
             }
             DefPathDataName::Anon { namespace } => {
-                if cpp_like_names(tcx) {
+                if cpp_like_debuginfo(tcx) {
                     write!(output, "{}${}", namespace, disambiguated_data.disambiguator).unwrap();
                 } else {
                     write!(output, "{{{}#{}}}", namespace, disambiguated_data.disambiguator)
@@ -560,7 +566,7 @@ fn push_generic_params_internal<'tcx>(
 
     debug_assert_eq!(substs, tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substs));
 
-    let cpp_like_names = cpp_like_names(tcx);
+    let cpp_like_debuginfo = cpp_like_debuginfo(tcx);
 
     output.push('<');
 
@@ -575,10 +581,10 @@ fn push_generic_params_internal<'tcx>(
             other => bug!("Unexpected non-erasable generic: {:?}", other),
         }
 
-        push_arg_separator(cpp_like_names, output);
+        push_arg_separator(cpp_like_debuginfo, output);
     }
     pop_arg_separator(output);
-    push_close_angle_bracket(cpp_like_names, output);
+    push_close_angle_bracket(cpp_like_debuginfo, output);
 
     true
 }
@@ -617,7 +623,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: &'tcx ty::Const<'tcx>, output:
                 // avoiding collisions and will make the emitted type names shorter.
                 let hash: u64 = hasher.finish();
 
-                if cpp_like_names(tcx) {
+                if cpp_like_debuginfo(tcx) {
                     write!(output, "CONST${:x}", hash)
                 } else {
                     write!(output, "{{CONST#{:x}}}", hash)
@@ -634,10 +640,10 @@ pub fn push_generic_params<'tcx>(tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>, out
     push_generic_params_internal(tcx, substs, output, &mut visited);
 }
 
-fn push_close_angle_bracket(cpp_like_names: bool, output: &mut String) {
+fn push_close_angle_bracket(cpp_like_debuginfo: bool, output: &mut String) {
     // MSVC debugger always treats `>>` as a shift, even when parsing templates,
     // so add a space to avoid confusion.
-    if cpp_like_names && output.ends_with('>') {
+    if cpp_like_debuginfo && output.ends_with('>') {
         output.push(' ')
     };
 
@@ -652,11 +658,11 @@ fn pop_close_angle_bracket(output: &mut String) {
     }
 }
 
-fn push_arg_separator(cpp_like_names: bool, output: &mut String) {
+fn push_arg_separator(cpp_like_debuginfo: bool, output: &mut String) {
     // Natvis does not always like having spaces between parts of the type name
     // and this causes issues when we need to write a typename in natvis, for example
     // as part of a cast like the `HashMap` visualizer does.
-    if cpp_like_names {
+    if cpp_like_debuginfo {
         output.push(',');
     } else {
         output.push_str(", ");
@@ -673,6 +679,7 @@ fn pop_arg_separator(output: &mut String) {
     output.pop();
 }
 
-fn cpp_like_names(tcx: TyCtxt<'_>) -> bool {
+/// Check if we should generate C++ like names and debug information.
+pub fn cpp_like_debuginfo(tcx: TyCtxt<'_>) -> bool {
     tcx.sess.target.is_like_msvc
 }
index dcfe5fcc2ca735aeba3339925f06355d4d390e29..5ce4e606fd20b74c5410d5f176951ebad7974611 100644 (file)
@@ -1477,7 +1477,7 @@ fn codegen_transmute(&mut self, bx: &mut Bx, src: &mir::Operand<'tcx>, dst: mir:
                 LocalRef::UnsizedPlace(_) => bug!("transmute must not involve unsized locals"),
                 LocalRef::Operand(None) => {
                     let dst_layout = bx.layout_of(self.monomorphized_place_ty(dst.as_ref()));
-                    assert!(!dst_layout.ty.has_erasable_regions(self.cx.tcx()));
+                    assert!(!dst_layout.ty.has_erasable_regions());
                     let place = PlaceRef::alloca(bx, dst_layout);
                     place.storage_live(bx);
                     self.codegen_transmute_into(bx, src, place);
index 1ef863e84af7fe757b691c6fb0167bcda350f489..814e4d626e119c8602afd886e7f56813a4ad81a9 100644 (file)
@@ -209,7 +209,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         let mut allocate_local = |local| {
             let decl = &mir.local_decls[local];
             let layout = bx.layout_of(fx.monomorphize(decl.ty));
-            assert!(!layout.ty.has_erasable_regions(cx.tcx()));
+            assert!(!layout.ty.has_erasable_regions());
 
             if local == mir::RETURN_PLACE && fx.fn_abi.ret.is_indirect() {
                 debug!("alloc: {:?} (return place) -> place", local);
index 6f960ca44cdd3f298028fe21e7df7bb4c530c899..679c45767018d2810025de4ff761e964b98c3225 100644 (file)
@@ -8,7 +8,6 @@
 use crate::MemFlags;
 
 use rustc_apfloat::{ieee, Float, Round, Status};
-use rustc_hir::lang_items::LangItem;
 use rustc_middle::mir;
 use rustc_middle::ty::cast::{CastTy, IntTy};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
@@ -486,31 +485,6 @@ pub fn codegen_rvalue_operand(
                 )
             }
 
-            mir::Rvalue::NullaryOp(mir::NullOp::Box, content_ty) => {
-                let content_ty = self.monomorphize(content_ty);
-                let content_layout = bx.cx().layout_of(content_ty);
-                let llsize = bx.cx().const_usize(content_layout.size.bytes());
-                let llalign = bx.cx().const_usize(content_layout.align.abi.bytes());
-                let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty));
-                let llty_ptr = bx.cx().backend_type(box_layout);
-
-                // Allocate space:
-                let def_id = match bx.tcx().lang_items().require(LangItem::ExchangeMalloc) {
-                    Ok(id) => id,
-                    Err(s) => {
-                        bx.cx().sess().fatal(&format!("allocation of `{}` {}", box_layout.ty, s));
-                    }
-                };
-                let instance = ty::Instance::mono(bx.tcx(), def_id);
-                let r = bx.cx().get_fn_addr(instance);
-                let ty = bx.type_func(&[bx.type_isize(), bx.type_isize()], bx.type_i8p());
-                let call = bx.call(ty, r, &[llsize, llalign], None);
-                let val = bx.pointercast(call, llty_ptr);
-
-                let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout };
-                (bx, operand)
-            }
-
             mir::Rvalue::NullaryOp(null_op, ty) => {
                 let ty = self.monomorphize(ty);
                 assert!(bx.cx().type_is_sized(ty));
@@ -518,7 +492,6 @@ pub fn codegen_rvalue_operand(
                 let val = match null_op {
                     mir::NullOp::SizeOf => layout.size.bytes(),
                     mir::NullOp::AlignOf => layout.align.abi.bytes(),
-                    mir::NullOp::Box => unreachable!(),
                 };
                 let val = bx.cx().const_usize(val);
                 let tcx = self.cx.tcx();
index c5412affafe231797d1d3579f367a679c702dc5b..3ec9f3ca3b8c2172277ca75f3758670855df9bd3 100644 (file)
@@ -63,7 +63,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
         cid.instance,
         body,
         Some(&ret.into()),
-        StackPopCleanup::None { cleanup: false },
+        StackPopCleanup::Root { cleanup: false },
     )?;
 
     // The main interpreter loop.
index 821b048eb9bcfc80331ce6f46616bcd3b42babc1..05fbbf45d7c24d5e0516ab3bf0c513f0c1c27794 100644 (file)
@@ -1,5 +1,5 @@
 use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::Symbol;
@@ -15,7 +15,8 @@ pub fn is_unstable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
     }
 }
 
-pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
+pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
+    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let parent_id = tcx.hir().get_parent_node(hir_id);
     matches!(
         tcx.hir().get(parent_id),
@@ -29,15 +30,15 @@ pub fn is_parent_const_impl_raw(tcx: TyCtxt<'_>, hir_id: hir::HirId) -> bool {
 /// Checks whether the function has a `const` modifier or, in case it is an intrinsic, whether
 /// said intrinsic has a `rustc_const_{un,}stable` attribute.
 fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-
-    let node = tcx.hir().get(hir_id);
+    let def_id = def_id.expect_local();
+    let node = tcx.hir().get_by_def_id(def_id);
 
     if let hir::Node::ForeignItem(hir::ForeignItem { kind: hir::ForeignItemKind::Fn(..), .. }) =
         node
     {
         // Intrinsics use `rustc_const_{un,}stable` attributes to indicate constness. All other
         // foreign items cannot be evaluated at compile-time.
+        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
         if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = tcx.hir().get_foreign_abi(hir_id) {
             tcx.lookup_const_stability(def_id).is_some()
         } else {
@@ -50,7 +51,7 @@ fn is_const_fn_raw(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 
         // If the function itself is not annotated with `const`, it may still be a `const fn`
         // if it resides in a const trait impl.
-        is_parent_const_impl_raw(tcx, hir_id)
+        is_parent_const_impl_raw(tcx, def_id)
     } else {
         matches!(node, hir::Node::Ctor(_))
     }
index fef0e00e507ebc698f7bd27ea0a85c0c6d0867d4..30e9cbe4403549223410a44981096cc3d875532e 100644 (file)
@@ -398,13 +398,6 @@ fn binary_ptr_op(
         Err(ConstEvalErrKind::NeedsRfc("pointer arithmetic or comparison".to_string()).into())
     }
 
-    fn box_alloc(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _dest: &PlaceTy<'tcx>,
-    ) -> InterpResult<'tcx> {
-        Err(ConstEvalErrKind::NeedsRfc("heap allocations via `box` keyword".to_string()).into())
-    }
-
     fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> {
         // The step limit has already been hit in a previous call to `before_terminator`.
         if ecx.machine.steps_remaining == 0 {
index 246807a112a40b733c4290e44aed653c72898f1a..0a8112da2aba8fbe4ccd596e05a14da16e970773 100644 (file)
@@ -156,11 +156,11 @@ pub enum StackPopCleanup {
     /// `ret` stores the block we jump to on a normal return, while `unwind`
     /// stores the block used for cleanup during unwinding.
     Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind },
-    /// Just do nothing: Used by Main and for the `box_alloc` hook in miri.
+    /// The root frame of the stack: nowhere else to jump to.
     /// `cleanup` says whether locals are deallocated. Static computation
     /// wants them leaked to intern what they need (and just throw away
     /// the entire `ecx` when it is done).
-    None { cleanup: bool },
+    Root { cleanup: bool },
 }
 
 /// State of a local variable including a memoized layout
@@ -849,7 +849,7 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
         // because this is CTFE and the final value will be thoroughly validated anyway.
         let cleanup = match return_to_block {
             StackPopCleanup::Goto { .. } => true,
-            StackPopCleanup::None { cleanup, .. } => cleanup,
+            StackPopCleanup::Root { cleanup, .. } => cleanup,
         };
 
         if !cleanup {
@@ -874,8 +874,8 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
             // Follow the unwind edge.
             let unwind = match return_to_block {
                 StackPopCleanup::Goto { unwind, .. } => unwind,
-                StackPopCleanup::None { .. } => {
-                    panic!("Encountered StackPopCleanup::None when unwinding!")
+                StackPopCleanup::Root { .. } => {
+                    panic!("encountered StackPopCleanup::Root when unwinding!")
                 }
             };
             self.unwind_to_block(unwind)
@@ -883,7 +883,13 @@ pub(super) fn pop_stack_frame(&mut self, unwinding: bool) -> InterpResult<'tcx>
             // Follow the normal return edge.
             match return_to_block {
                 StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret),
-                StackPopCleanup::None { .. } => Ok(()),
+                StackPopCleanup::Root { .. } => {
+                    assert!(
+                        self.stack().is_empty(),
+                        "only the topmost frame can have StackPopCleanup::Root"
+                    );
+                    Ok(())
+                }
             }
         }
     }
index 6a03b699d47d442e945b6416764fbd47b5f18a23..23ec3875cbc1a51a38d4cbec791f9d0044389166 100644 (file)
@@ -212,12 +212,6 @@ fn binary_ptr_op(
         right: &ImmTy<'tcx, Self::PointerTag>,
     ) -> InterpResult<'tcx, (Scalar<Self::PointerTag>, bool, Ty<'tcx>)>;
 
-    /// Heap allocations via the `box` keyword.
-    fn box_alloc(
-        ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        dest: &PlaceTy<'tcx, Self::PointerTag>,
-    ) -> InterpResult<'tcx>;
-
     /// Called to read the specified `local` from the `frame`.
     /// Since reading a ZST is not actually accessing memory or locals, this is never invoked
     /// for ZST reads.
index dfec4509685f6b83614eec3278b2817c75c1b012..e9c94c0cc434ccf73a8270d7cba68aaf1f1e0d9b 100644 (file)
@@ -568,7 +568,7 @@ pub fn const_to_op(
             ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric),
             ty::ConstKind::Error(_) => throw_inval!(AlreadyReported(ErrorReported)),
             ty::ConstKind::Unevaluated(uv) => {
-                let instance = self.resolve(uv.def, uv.substs(*self.tcx))?;
+                let instance = self.resolve(uv.def, uv.substs)?;
                 Ok(self.eval_to_allocation(GlobalId { instance, promoted: uv.promoted })?.into())
             }
             ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
index 6e37aae0f5e5cf2f31898189e37ac419cf3614f3..3daa1d3c2b3e87ce3985f2f2ee234f5874feee5b 100644 (file)
@@ -271,10 +271,6 @@ pub fn eval_rvalue_into_place(
                 self.write_immediate(place.to_ref(self), &dest)?;
             }
 
-            NullaryOp(mir::NullOp::Box, _) => {
-                M::box_alloc(self, &dest)?;
-            }
-
             NullaryOp(null_op, ty) => {
                 let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
                 let layout = self.layout_of(ty)?;
@@ -289,7 +285,6 @@ pub fn eval_rvalue_into_place(
                 let val = match null_op {
                     mir::NullOp::SizeOf => layout.size.bytes(),
                     mir::NullOp::AlignOf => layout.align.abi.bytes(),
-                    mir::NullOp::Box => unreachable!(),
                 };
                 self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?;
             }
index a16388d5de21928f7d9bf4df269c7d9a0b9122a0..3dde34a64103e98fa0bf591647bd10c41d437bac 100644 (file)
@@ -9,7 +9,7 @@
     T: TypeFoldable<'tcx>,
 {
     debug!("ensure_monomorphic_enough: ty={:?}", ty);
-    if !ty.potentially_needs_subst() {
+    if !ty.needs_subst() {
         return Ok(());
     }
 
@@ -21,12 +21,8 @@ struct UsedParamsNeedSubstVisitor<'tcx> {
     impl<'tcx> TypeVisitor<'tcx> for UsedParamsNeedSubstVisitor<'tcx> {
         type BreakTy = FoundParam;
 
-        fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-            Some(self.tcx)
-        }
-
         fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-            if !ty.potentially_needs_subst() {
+            if !ty.needs_subst() {
                 return ControlFlow::CONTINUE;
             }
 
@@ -44,7 +40,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                         let is_used = unused_params.contains(index).map_or(true, |unused| !unused);
                         // Only recurse when generic parameters in fns, closures and generators
                         // are used and require substitution.
-                        match (is_used, subst.definitely_needs_subst(self.tcx)) {
+                        match (is_used, subst.needs_subst()) {
                             // Just in case there are closures or generators within this subst,
                             // recurse.
                             (true, true) => return subst.super_visit_with(self),
index 5a398c2f45af52e593b34831684dbed94871c609..9dc7930fc51fb48cc6bb774097cb3afd663e1928 100644 (file)
@@ -267,14 +267,14 @@ fn aggregate_field_path_elem(&mut self, layout: TyAndLayout<'tcx>, field: usize)
                 match layout.variants {
                     Variants::Single { index } => {
                         // Inside a variant
-                        PathElem::Field(def.variants[index].fields[field].ident.name)
+                        PathElem::Field(def.variants[index].fields[field].name)
                     }
                     Variants::Multiple { .. } => bug!("we handled variants above"),
                 }
             }
 
             // other ADTs
-            ty::Adt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].ident.name),
+            ty::Adt(def, _) => PathElem::Field(def.non_enum_variant().fields[field].name),
 
             // arrays/slices
             ty::Array(..) | ty::Slice(..) => PathElem::ArrayElem(field),
@@ -726,7 +726,7 @@ fn visit_variant(
         new_op: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx> {
         let name = match old_op.layout.ty.kind() {
-            ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].ident.name),
+            ty::Adt(adt, _) => PathElem::Variant(adt.variants[variant_id].name),
             // Generators also have variants
             ty::Generator(..) => PathElem::GeneratorState(variant_id),
             _ => bug!("Unexpected type with variant: {:?}", old_op.layout.ty),
index 1d5f4630152941629928db3e4dcd3c5f088ac083..b7665d149e4af7f71faec63ab7177ff88ae3dd8a 100644 (file)
@@ -221,8 +221,7 @@ pub fn check_body(&mut self) {
             // Prevent const trait methods from being annotated as `stable`.
             // FIXME: Do this as part of stability checking.
             if self.is_const_stable_const_fn() {
-                let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-                if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) {
+                if crate::const_eval::is_parent_const_impl_raw(tcx, def_id) {
                     self.ccx
                         .tcx
                         .sess
@@ -348,7 +347,7 @@ fn check_static(&mut self, def_id: DefId, span: Span) {
     fn check_local_or_return_ty(&mut self, ty: Ty<'tcx>, local: Local) {
         let kind = self.body.local_kind(local);
 
-        for ty in ty.walk(self.tcx) {
+        for ty in ty.walk() {
             let ty = match ty.unpack() {
                 GenericArgKind::Type(ty) => ty,
 
@@ -632,7 +631,6 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
             }
 
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
-            Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation),
             Rvalue::ShallowInitBox(_, _) => {}
 
             Rvalue::UnaryOp(_, ref operand) => {
@@ -811,7 +809,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                         param_env,
                         Binder::dummy(TraitPredicate {
                             trait_ref,
-                            constness: ty::BoundConstness::ConstIfConst,
+                            constness: ty::BoundConstness::NotConst,
                             polarity: ty::ImplPolarity::Positive,
                         }),
                     );
@@ -830,6 +828,10 @@ 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)
index 27f2da34262a1f2e851f95a979bd3ed7d54d583d..cf939aaa73f64a0f3529d6eccf371e6b03909346 100644 (file)
@@ -210,8 +210,7 @@ fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
         // because that component may be part of an enum variant (e.g.,
         // `Option::<NonStructuralMatchTy>::Some`), in which case some values of this type may be
         // structural-match (`Option::None`).
-        let id = cx.tcx.hir().local_def_id_to_hir_id(cx.def_id());
-        traits::search_for_structural_match_violation(id, cx.body.span, cx.tcx, ty).is_some()
+        traits::search_for_structural_match_violation(cx.body.span, cx.tcx, ty).is_some()
     }
 
     fn in_adt_inherently<'tcx>(
@@ -338,7 +337,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 1537de993d197f143327f854336bb40979f19fc8..ac282a5ecc82c281454dcc0c83a31a4662bd7f3d 100644 (file)
@@ -508,7 +508,6 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
             }
 
             Rvalue::NullaryOp(op, _) => match op {
-                NullOp::Box => return Err(Unpromotable),
                 NullOp::SizeOf => {}
                 NullOp::AlignOf => {}
             },
@@ -844,17 +843,13 @@ fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) ->
                             ty,
                             val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                                 def,
-                                substs_: Some(InternalSubsts::for_item(
-                                    tcx,
-                                    def.did,
-                                    |param, _| {
-                                        if let ty::GenericParamDefKind::Lifetime = param.kind {
-                                            tcx.lifetimes.re_erased.into()
-                                        } else {
-                                            tcx.mk_param_from_def(param)
-                                        }
-                                    },
-                                )),
+                                substs: InternalSubsts::for_item(tcx, def.did, |param, _| {
+                                    if let ty::GenericParamDefKind::Lifetime = param.kind {
+                                        tcx.lifetimes.re_erased.into()
+                                    } else {
+                                        tcx.mk_param_from_def(param)
+                                    }
+                                }),
                                 promoted: Some(promoted_id),
                             }),
                         })
@@ -970,7 +965,6 @@ pub fn promote_candidates<'tcx>(
         scope.parent_scope = None;
 
         let promoted = Body::new(
-            tcx,
             body.source, // `promoted` gets filled in below
             IndexVec::new(),
             IndexVec::from_elem_n(scope, 1),
index e3395df35908c847c1c83f6fa5501483a828ece0..2bb9d6c189314082a6ea56319eb981f11f41a362 100644 (file)
@@ -17,8 +17,8 @@ rustc_macros = { path = "../rustc_macros" }
 rustc_graphviz = { path = "../rustc_graphviz" }
 cfg-if = "0.1.2"
 stable_deref_trait = "1.0.0"
-rayon = { version = "0.3.1", package = "rustc-rayon" }
-rayon-core = { version = "0.3.1", package = "rustc-rayon-core" }
+rayon = { version = "0.3.2", package = "rustc-rayon" }
+rayon-core = { version = "0.3.2", package = "rustc-rayon-core" }
 rustc-hash = "1.1.0"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_index = { path = "../rustc_index", package = "rustc_index" }
index 53062b9c20da8b8e6e6118730a518ff98c3bbf3f..872b0eb7854ae4c2face1527a766ff89bec0594f 100644 (file)
@@ -409,6 +409,20 @@ pub fn finish128(mut self) -> (u64, u64) {
     }
 }
 
+macro_rules! dispatch_value {
+    ($target: expr, $value:expr) => {
+        let value = $value;
+        #[allow(unreachable_patterns)]
+        #[allow(overflowing_literals)]
+        match value {
+            0..=0xFF => $target.short_write(value as u8),
+            0x100..=0xFFFF => $target.short_write(value as u16),
+            0x10000..=0xFFFFFFFF => $target.short_write(value as u32),
+            _ => $target.short_write(value as u64),
+        }
+    };
+}
+
 impl Hasher for SipHasher128 {
     #[inline]
     fn write_u8(&mut self, i: u8) {
@@ -422,7 +436,7 @@ fn write_u16(&mut self, i: u16) {
 
     #[inline]
     fn write_u32(&mut self, i: u32) {
-        self.short_write(i);
+        dispatch_value!(self, i);
     }
 
     #[inline]
@@ -452,7 +466,7 @@ fn write_i32(&mut self, i: i32) {
 
     #[inline]
     fn write_i64(&mut self, i: i64) {
-        self.short_write(i as u64);
+        dispatch_value!(self, i as u64);
     }
 
     #[inline]
index 3da3517895712c61a78ea7e4a638ad6d8e401f0b..9c09a7f5f822e94c1abfa75918b1a2993b401a9b 100644 (file)
@@ -583,3 +583,22 @@ fn stable_hash_reduce<HCX, I, C, F>(
         }
     }
 }
+
+#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
+pub enum NodeIdHashingMode {
+    Ignore,
+    HashDefPath,
+}
+
+/// Controls what data we do or not not hash.
+/// Whenever a `HashStable` implementation caches its
+/// result, it needs to include `HashingControls` as part
+/// of the key, to ensure that is does not produce an incorrect
+/// result (for example, using a `Fingerprint` produced while
+/// hashing `Span`s when a `Fingeprint` without `Span`s is
+/// being requested)
+#[derive(Clone, Hash, Eq, PartialEq, Debug)]
+pub struct HashingControls {
+    pub hash_spans: bool,
+    pub node_id_hashing_mode: NodeIdHashingMode,
+}
index b5d2d24736cdc4b89d30e9dc4a84e83a84abebc2..716259142d18b22062149c4faa2c58de3c0966b6 100644 (file)
@@ -5,7 +5,7 @@
 /// A vector type optimized for cases where this size is usually 0 (cf. `SmallVec`).
 /// The `Option<Box<..>>` wrapping allows us to represent a zero sized vector with `None`,
 /// which uses only a single (null) pointer.
-#[derive(Clone, Encodable, Decodable, Debug)]
+#[derive(Clone, Encodable, Decodable, Debug, Hash, Eq, PartialEq)]
 pub struct ThinVec<T>(Option<Box<Vec<T>>>);
 
 impl<T> ThinVec<T> {
@@ -20,6 +20,13 @@ pub fn iter(&self) -> std::slice::Iter<'_, T> {
     pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
         self.into_iter()
     }
+
+    pub fn push(&mut self, item: T) {
+        match *self {
+            ThinVec(Some(ref mut vec)) => vec.push(item),
+            ThinVec(None) => *self = vec![item].into(),
+        }
+    }
 }
 
 impl<T> From<Vec<T>> for ThinVec<T> {
@@ -101,10 +108,7 @@ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
     }
 
     fn extend_one(&mut self, item: T) {
-        match *self {
-            ThinVec(Some(ref mut vec)) => vec.push(item),
-            ThinVec(None) => *self = vec![item].into(),
-        }
+        self.push(item)
     }
 
     fn extend_reserve(&mut self, additional: usize) {
index 5abfd939373c7668ff5657be21343c220f18cba3..0221b9912bbdcdc0af0f8a291a84ce4dba8a9bde 100644 (file)
@@ -10,8 +10,8 @@ fn into_vec(self) -> Vec<T> {
 fn test_from_iterator() {
     assert_eq!(std::iter::empty().collect::<ThinVec<String>>().into_vec(), Vec::<String>::new());
     assert_eq!(std::iter::once(42).collect::<ThinVec<_>>().into_vec(), vec![42]);
-    assert_eq!(vec![1, 2].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2]);
-    assert_eq!(vec![1, 2, 3].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2, 3]);
+    assert_eq!([1, 2].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2]);
+    assert_eq!([1, 2, 3].into_iter().collect::<ThinVec<_>>().into_vec(), vec![1, 2, 3]);
 }
 
 #[test]
index 9083de85982e7df482863d3e201a09acd5846cc7..458b60077dc75a76d5c3f63e31cf8bfbdb10012e 100644 (file)
@@ -14,7 +14,7 @@ fn test_from_iterator() {
     );
     assert_eq!(std::iter::once((42, true)).collect::<VecMap<_, _>>().into_vec(), vec![(42, true)]);
     assert_eq!(
-        vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(),
+        [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>().into_vec(),
         vec![(1, true), (2, false)]
     );
 }
@@ -41,7 +41,7 @@ fn test_insert() {
 
 #[test]
 fn test_get() {
-    let v = vec![(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>();
+    let v = [(1, true), (2, false)].into_iter().collect::<VecMap<_, _>>();
     assert_eq!(v.get(&1), Some(&true));
     assert_eq!(v.get(&2), Some(&false));
     assert_eq!(v.get(&3), None);
index 2383a000687fa67238ceb7beca6aaabc847821f7..872f946bf7d91cf9b8261c65154314302aa3eb70 100644 (file)
@@ -8,10 +8,8 @@ crate-type = ["dylib"]
 
 [dependencies]
 libc = "0.2"
-atty = "0.2"
 tracing = { version = "0.1.28" }
-tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
-tracing-tree = "0.2.0"
+rustc_log = { path = "../rustc_log" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
 rustc_target = { path = "../rustc_target" }
@@ -40,4 +38,4 @@ winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"]
 
 [features]
 llvm = ['rustc_interface/llvm']
-max_level_info = ['tracing/max_level_info']
+max_level_info = ['rustc_log/max_level_info']
index 12e0b7a4977e1cf88130901ac251958a77951cf0..694c679c1586efb40404f450ebd15ef9bfc7b0ca 100644 (file)
@@ -24,6 +24,7 @@
 use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
 use rustc_interface::{interface, Queries};
 use rustc_lint::LintStore;
+use rustc_log::stdout_isatty;
 use rustc_metadata::locator;
 use rustc_save_analysis as save;
 use rustc_save_analysis::DumpHandler;
@@ -514,14 +515,6 @@ pub fn and_then<F: FnOnce() -> Compilation>(self, next: F) -> Compilation {
 #[derive(Copy, Clone)]
 pub struct RustcDefaultCalls;
 
-fn stdout_isatty() -> bool {
-    atty::is(atty::Stream::Stdout)
-}
-
-fn stderr_isatty() -> bool {
-    atty::is(atty::Stream::Stderr)
-}
-
 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') {
@@ -1047,7 +1040,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
     let wall = matches.opt_strs("W");
     if wall.iter().any(|x| *x == "all") {
         print_wall_help();
-        return None;
+        rustc_errors::FatalError.raise();
     }
 
     // Don't handle -W help here, because we might first load plugins.
@@ -1254,54 +1247,18 @@ pub fn install_ice_hook() {
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version.
 pub fn init_rustc_env_logger() {
-    init_env_logger("RUSTC_LOG")
+    if let Err(error) = rustc_log::init_rustc_env_logger() {
+        early_error(ErrorOutputType::default(), &error.to_string());
+    }
 }
 
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose an env var
 /// other than `RUSTC_LOG`.
 pub fn init_env_logger(env: &str) {
-    use tracing_subscriber::{
-        filter::{self, EnvFilter, LevelFilter},
-        layer::SubscriberExt,
-    };
-
-    let filter = match std::env::var(env) {
-        Ok(env) => EnvFilter::new(env),
-        _ => EnvFilter::default().add_directive(filter::Directive::from(LevelFilter::WARN)),
-    };
-
-    let color_logs = match std::env::var(String::from(env) + "_COLOR") {
-        Ok(value) => match value.as_ref() {
-            "always" => true,
-            "never" => false,
-            "auto" => stderr_isatty(),
-            _ => early_error(
-                ErrorOutputType::default(),
-                &format!(
-                    "invalid log color value '{}': expected one of always, never, or auto",
-                    value
-                ),
-            ),
-        },
-        Err(std::env::VarError::NotPresent) => stderr_isatty(),
-        Err(std::env::VarError::NotUnicode(_value)) => early_error(
-            ErrorOutputType::default(),
-            "non-Unicode log color value: expected one of always, never, or auto",
-        ),
-    };
-
-    let layer = tracing_tree::HierarchicalLayer::default()
-        .with_writer(io::stderr)
-        .with_indent_lines(true)
-        .with_ansi(color_logs)
-        .with_targets(true)
-        .with_indent_amount(2);
-    #[cfg(parallel_compiler)]
-    let layer = layer.with_thread_ids(true).with_thread_names(true);
-
-    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
-    tracing::subscriber::set_global_default(subscriber).unwrap();
+    if let Err(error) = rustc_log::init_env_logger(env) {
+        early_error(ErrorOutputType::default(), &error.to_string());
+    }
 }
 
 #[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
index dde978cd8c6ceab4b1b7c2927cf8c303d2a0ccdc..c2af2b2a86d1842f55a95ee5cce0914fe073142f 100644 (file)
@@ -455,7 +455,7 @@ fn from_span_full(
         let backtrace_step = backtrace.next().map(|bt| {
             let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je);
             let def_site_span =
-                Self::from_span_full(bt.def_site, false, None, None, vec![].into_iter(), je);
+                Self::from_span_full(bt.def_site, false, None, None, [].into_iter(), je);
             Box::new(DiagnosticSpanMacroExpansion {
                 span: call_site,
                 macro_decl_name: bt.kind.descr(),
index 64353461e90e0cbe80e7dea4a98b39ebae3636f1..e4cc44c41ddec5c41506864b68fb6e1f9dbe137b 100644 (file)
@@ -69,9 +69,6 @@ pub enum AnnotationType {
     /// Annotation under a single line of code
     Singleline,
 
-    /// Annotation enclosing the first and last character of a multiline span
-    Multiline(MultilineAnnotation),
-
     // The Multiline type above is replaced with the following three in order
     // to reuse the current label drawing code.
     //
index db0dea4870876d9a78c3c51632fc239ed7f11fd8..e0bdeb30dc84bcfe70436b7bf9007fb4242db1e0 100644 (file)
@@ -238,7 +238,7 @@ macro_rules! configure {
 }
 
 impl<'a> StripUnconfigured<'a> {
-    pub fn configure<T: AstLike>(&mut self, mut node: T) -> Option<T> {
+    pub fn configure<T: AstLike>(&self, mut node: T) -> Option<T> {
         self.process_cfg_attrs(&mut node);
         if self.in_cfg(node.attrs()) {
             self.try_configure_tokens(&mut node);
@@ -248,7 +248,7 @@ pub fn configure<T: AstLike>(&mut self, mut node: T) -> Option<T> {
         }
     }
 
-    fn try_configure_tokens<T: AstLike>(&mut self, node: &mut T) {
+    fn try_configure_tokens<T: AstLike>(&self, node: &mut T) {
         if self.config_tokens {
             if let Some(Some(tokens)) = node.tokens_mut() {
                 let attr_annotated_tokens = tokens.create_token_stream();
@@ -257,10 +257,7 @@ fn try_configure_tokens<T: AstLike>(&mut self, node: &mut T) {
         }
     }
 
-    fn configure_krate_attrs(
-        &mut self,
-        mut attrs: Vec<ast::Attribute>,
-    ) -> Option<Vec<ast::Attribute>> {
+    fn configure_krate_attrs(&self, mut attrs: Vec<ast::Attribute>) -> Option<Vec<ast::Attribute>> {
         attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
         if self.in_cfg(&attrs) { Some(attrs) } else { None }
     }
@@ -269,7 +266,7 @@ fn configure_krate_attrs(
     /// This is only used during the invocation of `derive` proc-macros,
     /// which require that we cfg-expand their entire input.
     /// Normal cfg-expansion operates on parsed AST nodes via the `configure` method
-    fn configure_tokens(&mut self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream {
+    fn configure_tokens(&self, stream: &AttrAnnotatedTokenStream) -> AttrAnnotatedTokenStream {
         fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool {
             stream.0.iter().all(|(tree, _spacing)| match tree {
                 AttrAnnotatedTokenTree::Attributes(_) => false,
@@ -325,7 +322,7 @@ fn can_skip(stream: &AttrAnnotatedTokenStream) -> bool {
     /// Gives compiler warnings if any `cfg_attr` does not contain any
     /// attributes and is in the original source code. Gives compiler errors if
     /// the syntax of any `cfg_attr` is incorrect.
-    fn process_cfg_attrs<T: AstLike>(&mut self, node: &mut T) {
+    fn process_cfg_attrs<T: AstLike>(&self, node: &mut T) {
         node.visit_attrs(|attrs| {
             attrs.flat_map_in_place(|attr| self.process_cfg_attr(attr));
         });
@@ -338,7 +335,7 @@ fn process_cfg_attrs<T: AstLike>(&mut self, node: &mut T) {
     /// Gives a compiler warning when the `cfg_attr` contains no attributes and
     /// is in the original source file. Gives a compiler error if the syntax of
     /// the attribute is incorrect.
-    fn process_cfg_attr(&mut self, attr: Attribute) -> Vec<Attribute> {
+    fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> {
         if !attr.has_name(sym::cfg_attr) {
             return vec![attr];
         }
@@ -461,7 +458,7 @@ fn in_cfg(&self, attrs: &[Attribute]) -> bool {
         }
     }
 
-    pub fn configure_expr(&mut self, expr: &mut P<ast::Expr>) {
+    pub fn configure_expr(&self, expr: &mut P<ast::Expr>) {
         for attr in expr.attrs.iter() {
             self.maybe_emit_expr_attr_err(attr);
         }
index f216a66148703d0fee859d4dd7d08b7cb25403dc..07ce901fb417aa2b1c1fe47da35c4d9123c14622 100644 (file)
@@ -1,6 +1,5 @@
 use crate::base::*;
 use crate::config::StripUnconfigured;
-use crate::configure;
 use crate::hygiene::SyntaxContext;
 use crate::mbe::macro_rules::annotate_err_with_kind;
 use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
 use rustc_ast::token;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{self, AssocCtxt, Visitor};
-use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs, MacCall};
-use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
-use rustc_ast::{NodeId, PatKind, Path, StmtKind};
+use rustc_ast::{AssocItemKind, AstLike, AstLikeWrapper, AttrStyle, ExprKind, ForeignItemKind};
+use rustc_ast::{Inline, ItemKind, MacArgs, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem};
+use rustc_ast::{NodeId, PatKind, StmtKind, TyKind};
 use rustc_ast_pretty::pprust;
 use rustc_attr::is_builtin_attr;
 use rustc_data_structures::map_in_place::MapInPlace;
-use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::{Applicability, PResult};
 use rustc_feature::Features;
@@ -34,7 +32,7 @@
 use rustc_span::{FileName, LocalExpnId, Span};
 
 use smallvec::SmallVec;
-use std::ops::DerefMut;
+use std::ops::Deref;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::{iter, mem};
@@ -109,6 +107,10 @@ pub fn make_opt_expr(self) -> Option<P<ast::Expr>> {
                 }
             })*
 
+            fn make_ast<T: InvocationCollectorNode>(self) -> T::OutputTy {
+                T::fragment_to_output(self)
+            }
+
             pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
                 match self {
                     AstFragment::OptExpr(opt_expr) => {
@@ -178,10 +180,10 @@ impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
     Arms(SmallVec<[ast::Arm; 1]>) {
         "match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms;
     }
-    Fields(SmallVec<[ast::ExprField; 1]>) {
+    ExprFields(SmallVec<[ast::ExprField; 1]>) {
         "field expression"; many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields;
     }
-    FieldPats(SmallVec<[ast::PatField; 1]>) {
+    PatFields(SmallVec<[ast::PatField; 1]>) {
         "field pattern";
         many fn flat_map_pat_field;
         fn visit_pat_field();
@@ -196,7 +198,7 @@ impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
     Params(SmallVec<[ast::Param; 1]>) {
         "function parameter"; many fn flat_map_param; fn visit_param(); fn make_params;
     }
-    StructFields(SmallVec<[ast::FieldDef; 1]>) {
+    FieldDefs(SmallVec<[ast::FieldDef; 1]>) {
         "field";
         many fn flat_map_field_def;
         fn visit_field_def();
@@ -231,11 +233,11 @@ pub fn supports_macro_expansion(self) -> SupportsMacroExpansion {
             | AstFragmentKind::ForeignItems
             | AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true },
             AstFragmentKind::Arms
-            | AstFragmentKind::Fields
-            | AstFragmentKind::FieldPats
+            | AstFragmentKind::ExprFields
+            | AstFragmentKind::PatFields
             | AstFragmentKind::GenericParams
             | AstFragmentKind::Params
-            | AstFragmentKind::StructFields
+            | AstFragmentKind::FieldDefs
             | AstFragmentKind::Variants => SupportsMacroExpansion::No,
         }
     }
@@ -249,11 +251,11 @@ fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
             AstFragmentKind::Arms => {
                 AstFragment::Arms(items.map(Annotatable::expect_arm).collect())
             }
-            AstFragmentKind::Fields => {
-                AstFragment::Fields(items.map(Annotatable::expect_expr_field).collect())
+            AstFragmentKind::ExprFields => {
+                AstFragment::ExprFields(items.map(Annotatable::expect_expr_field).collect())
             }
-            AstFragmentKind::FieldPats => {
-                AstFragment::FieldPats(items.map(Annotatable::expect_pat_field).collect())
+            AstFragmentKind::PatFields => {
+                AstFragment::PatFields(items.map(Annotatable::expect_pat_field).collect())
             }
             AstFragmentKind::GenericParams => {
                 AstFragment::GenericParams(items.map(Annotatable::expect_generic_param).collect())
@@ -261,8 +263,8 @@ fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
             AstFragmentKind::Params => {
                 AstFragment::Params(items.map(Annotatable::expect_param).collect())
             }
-            AstFragmentKind::StructFields => {
-                AstFragment::StructFields(items.map(Annotatable::expect_field_def).collect())
+            AstFragmentKind::FieldDefs => {
+                AstFragment::FieldDefs(items.map(Annotatable::expect_field_def).collect())
             }
             AstFragmentKind::Variants => {
                 AstFragment::Variants(items.map(Annotatable::expect_variant).collect())
@@ -315,10 +317,10 @@ pub enum InvocationKind {
         pos: usize,
         item: Annotatable,
         // Required for resolving derive helper attributes.
-        derives: Vec<Path>,
+        derives: Vec<ast::Path>,
     },
     Derive {
-        path: Path,
+        path: ast::Path,
         item: Annotatable,
     },
 }
@@ -377,6 +379,7 @@ pub fn expand_crate(&mut self, krate: ast::Crate) -> ast::Crate {
             dir_path,
         });
         let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate();
+        assert_eq!(krate.id, ast::CRATE_NODE_ID);
         self.cx.trace_macros_diag();
         krate
     }
@@ -675,7 +678,7 @@ fn expand_invoc(
                             krate,
                         ),
                         Annotatable::Item(item_inner)
-                            if matches!(attr.style, ast::AttrStyle::Inner)
+                            if matches!(attr.style, AttrStyle::Inner)
                                 && matches!(
                                     item_inner.kind,
                                     ItemKind::Mod(
@@ -743,7 +746,7 @@ fn expand_invoc(
                     if let SyntaxExtensionKind::Derive(..) = ext {
                         self.gate_proc_macro_input(&item);
                     }
-                    let meta = ast::MetaItem { kind: ast::MetaItemKind::Word, span, path };
+                    let meta = ast::MetaItem { kind: MetaItemKind::Word, span, path };
                     let items = match expander.expand(self.cx, span, &meta, item) {
                         ExpandResult::Ready(items) => items,
                         ExpandResult::Retry(item) => {
@@ -805,7 +808,7 @@ struct GateProcMacroInput<'a> {
         impl<'ast, 'a> Visitor<'ast> for GateProcMacroInput<'a> {
             fn visit_item(&mut self, item: &'ast ast::Item) {
                 match &item.kind {
-                    ast::ItemKind::Mod(_, mod_kind)
+                    ItemKind::Mod(_, mod_kind)
                         if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _)) =>
                     {
                         feature_err(
@@ -833,7 +836,7 @@ fn parse_ast_fragment(
         &mut self,
         toks: TokenStream,
         kind: AstFragmentKind,
-        path: &Path,
+        path: &ast::Path,
         span: Span,
     ) -> AstFragment {
         let mut parser = self.cx.new_parser_from_tts(toks);
@@ -914,18 +917,18 @@ pub fn parse_ast_fragment<'a>(
         )?),
         AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?),
         AstFragmentKind::Arms
-        | AstFragmentKind::Fields
-        | AstFragmentKind::FieldPats
+        | AstFragmentKind::ExprFields
+        | AstFragmentKind::PatFields
         | AstFragmentKind::GenericParams
         | AstFragmentKind::Params
-        | AstFragmentKind::StructFields
+        | AstFragmentKind::FieldDefs
         | AstFragmentKind::Variants => panic!("unexpected AST fragment kind"),
     })
 }
 
 pub fn ensure_complete_parse<'a>(
     this: &mut Parser<'a>,
-    macro_path: &Path,
+    macro_path: &ast::Path,
     kind_name: &str,
     span: Span,
 ) {
@@ -960,6 +963,568 @@ pub fn ensure_complete_parse<'a>(
     }
 }
 
+/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
+/// for an AST node that supports attributes
+/// (see the `Annotatable` enum)
+/// This method assigns a `NodeId`, and sets that `NodeId`
+/// as our current 'lint node id'. If a macro call is found
+/// inside this AST node, we will use this AST node's `NodeId`
+/// to emit lints associated with that macro (allowing
+/// `#[allow]` / `#[deny]` to be applied close to
+/// the macro invocation).
+///
+/// Do *not* call this for a macro AST node
+/// (e.g. `ExprKind::MacCall`) - we cannot emit lints
+/// at these AST nodes, since they are removed and
+/// replaced with the result of macro expansion.
+///
+/// All other `NodeId`s are assigned by `visit_id`.
+/// * `self` is the 'self' parameter for the current method,
+/// * `id` is a mutable reference to the `NodeId` field
+///    of the current AST node.
+/// * `closure` is a closure that executes the
+///   `noop_visit_*` / `noop_flat_map_*` method
+///   for the current AST node.
+macro_rules! assign_id {
+    ($self:ident, $id:expr, $closure:expr) => {{
+        let old_id = $self.cx.current_expansion.lint_node_id;
+        if $self.monotonic {
+            debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);
+            let new_id = $self.cx.resolver.next_node_id();
+            *$id = new_id;
+            $self.cx.current_expansion.lint_node_id = new_id;
+        }
+        let ret = ($closure)();
+        $self.cx.current_expansion.lint_node_id = old_id;
+        ret
+    }};
+}
+
+enum AddSemicolon {
+    Yes,
+    No,
+}
+
+/// A trait implemented for all `AstFragment` nodes and providing all pieces
+/// of functionality used by `InvocationCollector`.
+trait InvocationCollectorNode: AstLike {
+    type OutputTy = SmallVec<[Self; 1]>;
+    type AttrsTy: Deref<Target = [ast::Attribute]> = Vec<ast::Attribute>;
+    const KIND: AstFragmentKind;
+    fn to_annotatable(self) -> Annotatable;
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;
+    fn id(&mut self) -> &mut NodeId;
+    fn noop_flat_map<V: MutVisitor>(self, _visitor: &mut V) -> Self::OutputTy {
+        unreachable!()
+    }
+    fn noop_visit<V: MutVisitor>(&mut self, _visitor: &mut V) {
+        unreachable!()
+    }
+    fn is_mac_call(&self) -> bool {
+        false
+    }
+    fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+        unreachable!()
+    }
+    fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}
+    fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {
+    }
+    fn wrap_flat_map_node_noop_flat_map(
+        node: Self,
+        collector: &mut InvocationCollector<'_, '_>,
+        noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
+    ) -> Result<Self::OutputTy, Self> {
+        Ok(noop_flat_map(node, collector))
+    }
+}
+
+impl InvocationCollectorNode for P<ast::Item> {
+    const KIND: AstFragmentKind = AstFragmentKind::Items;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::Item(self)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_items()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_item(self, visitor)
+    }
+    fn is_mac_call(&self) -> bool {
+        matches!(self.kind, ItemKind::MacCall(..))
+    }
+    fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+        let node = self.into_inner();
+        match node.kind {
+            ItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+            _ => unreachable!(),
+        }
+    }
+    fn wrap_flat_map_node_noop_flat_map(
+        mut node: Self,
+        collector: &mut InvocationCollector<'_, '_>,
+        noop_flat_map: impl FnOnce(Self, &mut InvocationCollector<'_, '_>) -> Self::OutputTy,
+    ) -> Result<Self::OutputTy, Self> {
+        if !matches!(node.kind, ItemKind::Mod(..)) {
+            return Ok(noop_flat_map(node, collector));
+        }
+
+        // Work around borrow checker not seeing through `P`'s deref.
+        let (ident, span, mut attrs) = (node.ident, node.span, mem::take(&mut node.attrs));
+        let ItemKind::Mod(_, mod_kind) = &mut node.kind else {
+            unreachable!()
+        };
+
+        let ecx = &mut collector.cx;
+        let (file_path, dir_path, dir_ownership) = match mod_kind {
+            ModKind::Loaded(_, inline, _) => {
+                // Inline `mod foo { ... }`, but we still need to push directories.
+                let (dir_path, dir_ownership) = mod_dir_path(
+                    &ecx.sess,
+                    ident,
+                    &attrs,
+                    &ecx.current_expansion.module,
+                    ecx.current_expansion.dir_ownership,
+                    *inline,
+                );
+                node.attrs = attrs;
+                (None, dir_path, dir_ownership)
+            }
+            ModKind::Unloaded => {
+                // We have an outline `mod foo;` so we need to parse the file.
+                let old_attrs_len = attrs.len();
+                let ParsedExternalMod { mut items, inner_span, file_path, dir_path, dir_ownership } =
+                    parse_external_mod(
+                        &ecx.sess,
+                        ident,
+                        span,
+                        &ecx.current_expansion.module,
+                        ecx.current_expansion.dir_ownership,
+                        &mut attrs,
+                    );
+
+                if let Some(extern_mod_loaded) = ecx.extern_mod_loaded {
+                    (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span);
+                }
+
+                *mod_kind = ModKind::Loaded(items, Inline::No, inner_span);
+                node.attrs = attrs;
+                if node.attrs.len() > old_attrs_len {
+                    // If we loaded an out-of-line module and added some inner attributes,
+                    // then we need to re-configure it and re-collect attributes for
+                    // resolution and expansion.
+                    return Err(node);
+                }
+                (Some(file_path), dir_path, dir_ownership)
+            }
+        };
+
+        // Set the module info before we flat map.
+        let mut module = ecx.current_expansion.module.with_dir_path(dir_path);
+        module.mod_path.push(ident);
+        if let Some(file_path) = file_path {
+            module.file_path_stack.push(file_path);
+        }
+
+        let orig_module = mem::replace(&mut ecx.current_expansion.module, Rc::new(module));
+        let orig_dir_ownership =
+            mem::replace(&mut ecx.current_expansion.dir_ownership, dir_ownership);
+
+        let res = Ok(noop_flat_map(node, collector));
+
+        collector.cx.current_expansion.dir_ownership = orig_dir_ownership;
+        collector.cx.current_expansion.module = orig_module;
+        res
+    }
+}
+
+struct TraitItemTag;
+impl InvocationCollectorNode for AstLikeWrapper<P<ast::AssocItem>, TraitItemTag> {
+    type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
+    const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::TraitItem(self.wrapped)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_trait_items()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.wrapped.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_assoc_item(self.wrapped, visitor)
+    }
+    fn is_mac_call(&self) -> bool {
+        matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
+    }
+    fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+        let item = self.wrapped.into_inner();
+        match item.kind {
+            AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
+            _ => unreachable!(),
+        }
+    }
+}
+
+struct ImplItemTag;
+impl InvocationCollectorNode for AstLikeWrapper<P<ast::AssocItem>, ImplItemTag> {
+    type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
+    const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::ImplItem(self.wrapped)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_impl_items()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.wrapped.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_assoc_item(self.wrapped, visitor)
+    }
+    fn is_mac_call(&self) -> bool {
+        matches!(self.wrapped.kind, AssocItemKind::MacCall(..))
+    }
+    fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+        let item = self.wrapped.into_inner();
+        match item.kind {
+            AssocItemKind::MacCall(mac) => (mac, item.attrs, AddSemicolon::No),
+            _ => unreachable!(),
+        }
+    }
+}
+
+impl InvocationCollectorNode for P<ast::ForeignItem> {
+    const KIND: AstFragmentKind = AstFragmentKind::ForeignItems;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::ForeignItem(self)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_foreign_items()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_foreign_item(self, visitor)
+    }
+    fn is_mac_call(&self) -> bool {
+        matches!(self.kind, ForeignItemKind::MacCall(..))
+    }
+    fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+        let node = self.into_inner();
+        match node.kind {
+            ForeignItemKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+            _ => unreachable!(),
+        }
+    }
+}
+
+impl InvocationCollectorNode for ast::Variant {
+    const KIND: AstFragmentKind = AstFragmentKind::Variants;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::Variant(self)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_variants()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_variant(self, visitor)
+    }
+}
+
+impl InvocationCollectorNode for ast::FieldDef {
+    const KIND: AstFragmentKind = AstFragmentKind::FieldDefs;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::FieldDef(self)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_field_defs()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_field_def(self, visitor)
+    }
+}
+
+impl InvocationCollectorNode for ast::PatField {
+    const KIND: AstFragmentKind = AstFragmentKind::PatFields;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::PatField(self)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_pat_fields()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_pat_field(self, visitor)
+    }
+}
+
+impl InvocationCollectorNode for ast::ExprField {
+    const KIND: AstFragmentKind = AstFragmentKind::ExprFields;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::ExprField(self)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_expr_fields()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_expr_field(self, visitor)
+    }
+}
+
+impl InvocationCollectorNode for ast::Param {
+    const KIND: AstFragmentKind = AstFragmentKind::Params;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::Param(self)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_params()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_param(self, visitor)
+    }
+}
+
+impl InvocationCollectorNode for ast::GenericParam {
+    const KIND: AstFragmentKind = AstFragmentKind::GenericParams;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::GenericParam(self)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_generic_params()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_generic_param(self, visitor)
+    }
+}
+
+impl InvocationCollectorNode for ast::Arm {
+    const KIND: AstFragmentKind = AstFragmentKind::Arms;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::Arm(self)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_arms()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_arm(self, visitor)
+    }
+}
+
+impl InvocationCollectorNode for ast::Stmt {
+    type AttrsTy = ast::AttrVec;
+    const KIND: AstFragmentKind = AstFragmentKind::Stmts;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::Stmt(P(self))
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_stmts()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_flat_map<V: MutVisitor>(self, visitor: &mut V) -> Self::OutputTy {
+        noop_flat_map_stmt(self, visitor)
+    }
+    fn is_mac_call(&self) -> bool {
+        match &self.kind {
+            StmtKind::MacCall(..) => true,
+            StmtKind::Item(item) => matches!(item.kind, ItemKind::MacCall(..)),
+            StmtKind::Semi(expr) => matches!(expr.kind, ExprKind::MacCall(..)),
+            StmtKind::Expr(..) => unreachable!(),
+            StmtKind::Local(..) | StmtKind::Empty => false,
+        }
+    }
+    fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+        // We pull macro invocations (both attributes and fn-like macro calls) out of their
+        // `StmtKind`s and treat them as statement macro invocations, not as items or expressions.
+        let (add_semicolon, mac, attrs) = match self.kind {
+            StmtKind::MacCall(mac) => {
+                let ast::MacCallStmt { mac, style, attrs, .. } = mac.into_inner();
+                (style == MacStmtStyle::Semicolon, mac, attrs)
+            }
+            StmtKind::Item(item) => match item.into_inner() {
+                ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
+                    (mac.args.need_semicolon(), mac, attrs.into())
+                }
+                _ => unreachable!(),
+            },
+            StmtKind::Semi(expr) => match expr.into_inner() {
+                ast::Expr { kind: ExprKind::MacCall(mac), attrs, .. } => {
+                    (mac.args.need_semicolon(), mac, attrs)
+                }
+                _ => unreachable!(),
+            },
+            _ => unreachable!(),
+        };
+        (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No })
+    }
+    fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) {
+        // If this is a macro invocation with a semicolon, then apply that
+        // semicolon to the final statement produced by expansion.
+        if matches!(add_semicolon, AddSemicolon::Yes) {
+            if let Some(stmt) = stmts.pop() {
+                stmts.push(stmt.add_trailing_semicolon());
+            }
+        }
+    }
+}
+
+impl InvocationCollectorNode for ast::Crate {
+    type OutputTy = ast::Crate;
+    const KIND: AstFragmentKind = AstFragmentKind::Crate;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::Crate(self)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_crate()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+        noop_visit_crate(self, visitor)
+    }
+}
+
+impl InvocationCollectorNode for P<ast::Ty> {
+    type OutputTy = P<ast::Ty>;
+    const KIND: AstFragmentKind = AstFragmentKind::Ty;
+    fn to_annotatable(self) -> Annotatable {
+        unreachable!()
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_ty()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+        noop_visit_ty(self, visitor)
+    }
+    fn is_mac_call(&self) -> bool {
+        matches!(self.kind, ast::TyKind::MacCall(..))
+    }
+    fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+        let node = self.into_inner();
+        match node.kind {
+            TyKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No),
+            _ => unreachable!(),
+        }
+    }
+}
+
+impl InvocationCollectorNode for P<ast::Pat> {
+    type OutputTy = P<ast::Pat>;
+    const KIND: AstFragmentKind = AstFragmentKind::Pat;
+    fn to_annotatable(self) -> Annotatable {
+        unreachable!()
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_pat()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+        noop_visit_pat(self, visitor)
+    }
+    fn is_mac_call(&self) -> bool {
+        matches!(self.kind, PatKind::MacCall(..))
+    }
+    fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+        let node = self.into_inner();
+        match node.kind {
+            PatKind::MacCall(mac) => (mac, Vec::new(), AddSemicolon::No),
+            _ => unreachable!(),
+        }
+    }
+}
+
+impl InvocationCollectorNode for P<ast::Expr> {
+    type OutputTy = P<ast::Expr>;
+    type AttrsTy = ast::AttrVec;
+    const KIND: AstFragmentKind = AstFragmentKind::Expr;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::Expr(self)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_expr()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.id
+    }
+    fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
+        noop_visit_expr(self, visitor)
+    }
+    fn is_mac_call(&self) -> bool {
+        matches!(self.kind, ExprKind::MacCall(..))
+    }
+    fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+        let node = self.into_inner();
+        match node.kind {
+            ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+            _ => unreachable!(),
+        }
+    }
+}
+
+struct OptExprTag;
+impl InvocationCollectorNode for AstLikeWrapper<P<ast::Expr>, OptExprTag> {
+    type OutputTy = Option<P<ast::Expr>>;
+    type AttrsTy = ast::AttrVec;
+    const KIND: AstFragmentKind = AstFragmentKind::OptExpr;
+    fn to_annotatable(self) -> Annotatable {
+        Annotatable::Expr(self.wrapped)
+    }
+    fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
+        fragment.make_opt_expr()
+    }
+    fn id(&mut self) -> &mut NodeId {
+        &mut self.wrapped.id
+    }
+    fn noop_flat_map<V: MutVisitor>(mut self, visitor: &mut V) -> Self::OutputTy {
+        noop_visit_expr(&mut self.wrapped, visitor);
+        Some(self.wrapped)
+    }
+    fn is_mac_call(&self) -> bool {
+        matches!(self.wrapped.kind, ast::ExprKind::MacCall(..))
+    }
+    fn take_mac_call(self) -> (ast::MacCall, Self::AttrsTy, AddSemicolon) {
+        let node = self.wrapped.into_inner();
+        match node.kind {
+            ExprKind::MacCall(mac) => (mac, node.attrs, AddSemicolon::No),
+            _ => unreachable!(),
+        }
+    }
+    fn pre_flat_map_node_collect_attr(cfg: &StripUnconfigured<'_>, attr: &ast::Attribute) {
+        cfg.maybe_emit_expr_attr_err(&attr);
+    }
+}
+
 struct InvocationCollector<'a, 'b> {
     cx: &'a mut ExtCtxt<'b>,
     cfg: StripUnconfigured<'a>,
@@ -995,7 +1560,7 @@ fn collect_bang(&mut self, mac: ast::MacCall, kind: AstFragmentKind) -> AstFragm
 
     fn collect_attr(
         &mut self,
-        (attr, pos, derives): (ast::Attribute, usize, Vec<Path>),
+        (attr, pos, derives): (ast::Attribute, usize, Vec<ast::Path>),
         item: Annotatable,
         kind: AstFragmentKind,
     ) -> AstFragment {
@@ -1006,9 +1571,9 @@ fn collect_attr(
     /// its position and derives following it. We have to collect the derives in order to resolve
     /// legacy derive helpers (helpers written before derives that introduce them).
     fn take_first_attr(
-        &mut self,
+        &self,
         item: &mut impl AstLike,
-    ) -> Option<(ast::Attribute, usize, Vec<Path>)> {
+    ) -> Option<(ast::Attribute, usize, Vec<ast::Path>)> {
         let mut attr = None;
 
         item.visit_attrs(|attrs| {
@@ -1038,45 +1603,13 @@ fn take_first_attr(
         attr
     }
 
-    fn take_stmt_bang(
-        &mut self,
-        stmt: ast::Stmt,
-    ) -> Result<(bool, MacCall, Vec<ast::Attribute>), ast::Stmt> {
-        match stmt.kind {
-            StmtKind::MacCall(mac) => {
-                let MacCallStmt { mac, style, attrs, .. } = mac.into_inner();
-                Ok((style == MacStmtStyle::Semicolon, mac, attrs.into()))
-            }
-            StmtKind::Item(item) if matches!(item.kind, ItemKind::MacCall(..)) => {
-                match item.into_inner() {
-                    ast::Item { kind: ItemKind::MacCall(mac), attrs, .. } => {
-                        Ok((mac.args.need_semicolon(), mac, attrs))
-                    }
-                    _ => unreachable!(),
-                }
-            }
-            StmtKind::Semi(expr) if matches!(expr.kind, ast::ExprKind::MacCall(..)) => {
-                match expr.into_inner() {
-                    ast::Expr { kind: ast::ExprKind::MacCall(mac), attrs, .. } => {
-                        Ok((mac.args.need_semicolon(), mac, attrs.into()))
-                    }
-                    _ => unreachable!(),
-                }
-            }
-            StmtKind::Local(..) | StmtKind::Empty | StmtKind::Item(..) | StmtKind::Semi(..) => {
-                Err(stmt)
-            }
-            StmtKind::Expr(..) => unreachable!(),
-        }
-    }
-
     fn configure<T: AstLike>(&mut self, node: T) -> Option<T> {
         self.cfg.configure(node)
     }
 
     // Detect use of feature-gated or invalid attributes on macro invocations
     // since they will not be detected after macro expansion.
-    fn check_attributes(&self, attrs: &[ast::Attribute], call: &MacCall) {
+    fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
         let features = self.cx.ecfg.features.unwrap();
         let mut attrs = attrs.iter().peekable();
         let mut span: Option<Span> = None;
@@ -1119,509 +1652,165 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &MacCall) {
             }
         }
     }
-}
 
-/// Wraps a call to `noop_visit_*` / `noop_flat_map_*`
-/// for an AST node that supports attributes
-/// (see the `Annotatable` enum)
-/// This method assigns a `NodeId`, and sets that `NodeId`
-/// as our current 'lint node id'. If a macro call is found
-/// inside this AST node, we will use this AST node's `NodeId`
-/// to emit lints associated with that macro (allowing
-/// `#[allow]` / `#[deny]` to be applied close to
-/// the macro invocation).
-///
-/// Do *not* call this for a macro AST node
-/// (e.g. `ExprKind::MacCall`) - we cannot emit lints
-/// at these AST nodes, since they are removed and
-/// replaced with the result of macro expansion.
-///
-/// All other `NodeId`s are assigned by `visit_id`.
-/// * `self` is the 'self' parameter for the current method,
-/// * `id` is a mutable reference to the `NodeId` field
-///    of the current AST node.
-/// * `closure` is a closure that executes the
-///   `noop_visit_*` / `noop_flat_map_*` method
-///   for the current AST node.
-macro_rules! assign_id {
-    ($self:ident, $id:expr, $closure:expr) => {{
-        let old_id = $self.cx.current_expansion.lint_node_id;
-        if $self.monotonic {
-            debug_assert_eq!(*$id, ast::DUMMY_NODE_ID);
-            let new_id = $self.cx.resolver.next_node_id();
-            *$id = new_id;
-            $self.cx.current_expansion.lint_node_id = new_id;
+    fn flat_map_node<Node: InvocationCollectorNode<OutputTy: Default>>(
+        &mut self,
+        node: Node,
+    ) -> Node::OutputTy {
+        let mut node = configure!(self, node);
+
+        if let Some(attr) = self.take_first_attr(&mut node) {
+            Node::pre_flat_map_node_collect_attr(&self.cfg, &attr.0);
+            self.collect_attr(attr, node.to_annotatable(), Node::KIND).make_ast::<Node>()
+        } else if node.is_mac_call() {
+            let (mac, attrs, add_semicolon) = node.take_mac_call();
+            self.check_attributes(&attrs, &mac);
+            let mut res = self.collect_bang(mac, Node::KIND).make_ast::<Node>();
+            Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
+            res
+        } else {
+            match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| {
+                assign_id!(this, node.id(), || node.noop_flat_map(this))
+            }) {
+                Ok(output) => output,
+                Err(node) => self.flat_map_node(node),
+            }
         }
-        let ret = ($closure)();
-        $self.cx.current_expansion.lint_node_id = old_id;
-        ret
-    }};
+    }
+
+    fn visit_node<Node: InvocationCollectorNode<OutputTy = Node> + DummyAstNode>(
+        &mut self,
+        node: &mut Node,
+    ) {
+        if let Some(attr) = self.take_first_attr(node) {
+            visit_clobber(node, |node| {
+                self.collect_attr(attr, node.to_annotatable(), Node::KIND).make_ast::<Node>()
+            })
+        } else if node.is_mac_call() {
+            visit_clobber(node, |node| {
+                // Do not clobber unless it's actually a macro (uncommon case).
+                let (mac, attrs, _) = node.take_mac_call();
+                self.check_attributes(&attrs, &mac);
+                self.collect_bang(mac, Node::KIND).make_ast::<Node>()
+            })
+        } else {
+            assign_id!(self, node.id(), || node.noop_visit(self))
+        }
+    }
 }
 
 impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
-    fn visit_crate(&mut self, krate: &mut ast::Crate) {
-        visit_clobber(krate, |krate| {
-            let span = krate.span;
-            let mut krate = match self.configure(krate) {
-                Some(krate) => krate,
-                None => {
-                    return ast::Crate {
-                        attrs: Vec::new(),
-                        items: Vec::new(),
-                        span,
-                        is_placeholder: None,
-                    };
-                }
-            };
-
-            if let Some(attr) = self.take_first_attr(&mut krate) {
-                return self
-                    .collect_attr(attr, Annotatable::Crate(krate), AstFragmentKind::Crate)
-                    .make_crate();
-            }
-
-            noop_visit_crate(&mut krate, self);
-            krate
-        })
+    fn flat_map_item(&mut self, node: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
+        self.flat_map_node(node)
     }
 
-    fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
-        self.cfg.configure_expr(expr);
-        visit_clobber(expr.deref_mut(), |mut expr| {
-            if let Some(attr) = self.take_first_attr(&mut expr) {
-                // Collect the invoc regardless of whether or not attributes are permitted here
-                // expansion will eat the attribute so it won't error later.
-                self.cfg.maybe_emit_expr_attr_err(&attr.0);
-
-                // AstFragmentKind::Expr requires the macro to emit an expression.
-                return self
-                    .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::Expr)
-                    .make_expr()
-                    .into_inner();
-            }
-
-            if let ast::ExprKind::MacCall(mac) = expr.kind {
-                self.check_attributes(&expr.attrs, &mac);
-                self.collect_bang(mac, AstFragmentKind::Expr).make_expr().into_inner()
-            } else {
-                assign_id!(self, &mut expr.id, || {
-                    ensure_sufficient_stack(|| noop_visit_expr(&mut expr, self));
-                });
-                expr
-            }
-        });
+    fn flat_map_trait_item(&mut self, node: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
+        self.flat_map_node(AstLikeWrapper::new(node, TraitItemTag))
     }
 
-    fn flat_map_arm(&mut self, arm: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
-        let mut arm = configure!(self, arm);
-
-        if let Some(attr) = self.take_first_attr(&mut arm) {
-            return self
-                .collect_attr(attr, Annotatable::Arm(arm), AstFragmentKind::Arms)
-                .make_arms();
-        }
-
-        assign_id!(self, &mut arm.id, || noop_flat_map_arm(arm, self))
+    fn flat_map_impl_item(&mut self, node: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
+        self.flat_map_node(AstLikeWrapper::new(node, ImplItemTag))
     }
 
-    fn flat_map_expr_field(&mut self, field: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
-        let mut field = configure!(self, field);
-
-        if let Some(attr) = self.take_first_attr(&mut field) {
-            return self
-                .collect_attr(attr, Annotatable::ExprField(field), AstFragmentKind::Fields)
-                .make_expr_fields();
-        }
-
-        assign_id!(self, &mut field.id, || noop_flat_map_expr_field(field, self))
+    fn flat_map_foreign_item(
+        &mut self,
+        node: P<ast::ForeignItem>,
+    ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
+        self.flat_map_node(node)
     }
 
-    fn flat_map_pat_field(&mut self, fp: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
-        let mut fp = configure!(self, fp);
-
-        if let Some(attr) = self.take_first_attr(&mut fp) {
-            return self
-                .collect_attr(attr, Annotatable::PatField(fp), AstFragmentKind::FieldPats)
-                .make_pat_fields();
-        }
-
-        assign_id!(self, &mut fp.id, || noop_flat_map_pat_field(fp, self))
+    fn flat_map_variant(&mut self, node: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
+        self.flat_map_node(node)
     }
 
-    fn flat_map_param(&mut self, p: ast::Param) -> SmallVec<[ast::Param; 1]> {
-        let mut p = configure!(self, p);
-
-        if let Some(attr) = self.take_first_attr(&mut p) {
-            return self
-                .collect_attr(attr, Annotatable::Param(p), AstFragmentKind::Params)
-                .make_params();
-        }
-
-        assign_id!(self, &mut p.id, || noop_flat_map_param(p, self))
+    fn flat_map_field_def(&mut self, node: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
+        self.flat_map_node(node)
     }
 
-    fn flat_map_field_def(&mut self, sf: ast::FieldDef) -> SmallVec<[ast::FieldDef; 1]> {
-        let mut sf = configure!(self, sf);
-
-        if let Some(attr) = self.take_first_attr(&mut sf) {
-            return self
-                .collect_attr(attr, Annotatable::FieldDef(sf), AstFragmentKind::StructFields)
-                .make_field_defs();
-        }
-
-        assign_id!(self, &mut sf.id, || noop_flat_map_field_def(sf, self))
+    fn flat_map_pat_field(&mut self, node: ast::PatField) -> SmallVec<[ast::PatField; 1]> {
+        self.flat_map_node(node)
     }
 
-    fn flat_map_variant(&mut self, variant: ast::Variant) -> SmallVec<[ast::Variant; 1]> {
-        let mut variant = configure!(self, variant);
-
-        if let Some(attr) = self.take_first_attr(&mut variant) {
-            return self
-                .collect_attr(attr, Annotatable::Variant(variant), AstFragmentKind::Variants)
-                .make_variants();
-        }
-
-        assign_id!(self, &mut variant.id, || noop_flat_map_variant(variant, self))
+    fn flat_map_expr_field(&mut self, node: ast::ExprField) -> SmallVec<[ast::ExprField; 1]> {
+        self.flat_map_node(node)
     }
 
-    fn filter_map_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
-        let expr = configure!(self, expr);
-        expr.filter_map(|mut expr| {
-            if let Some(attr) = self.take_first_attr(&mut expr) {
-                self.cfg.maybe_emit_expr_attr_err(&attr.0);
-
-                return self
-                    .collect_attr(attr, Annotatable::Expr(P(expr)), AstFragmentKind::OptExpr)
-                    .make_opt_expr()
-                    .map(|expr| expr.into_inner());
-            }
-
-            if let ast::ExprKind::MacCall(mac) = expr.kind {
-                self.check_attributes(&expr.attrs, &mac);
-                self.collect_bang(mac, AstFragmentKind::OptExpr)
-                    .make_opt_expr()
-                    .map(|expr| expr.into_inner())
-            } else {
-                assign_id!(self, &mut expr.id, || {
-                    Some({
-                        noop_visit_expr(&mut expr, self);
-                        expr
-                    })
-                })
-            }
-        })
+    fn flat_map_param(&mut self, node: ast::Param) -> SmallVec<[ast::Param; 1]> {
+        self.flat_map_node(node)
     }
 
-    fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
-        match pat.kind {
-            PatKind::MacCall(_) => {}
-            _ => return noop_visit_pat(pat, self),
-        }
-
-        visit_clobber(pat, |mut pat| match mem::replace(&mut pat.kind, PatKind::Wild) {
-            PatKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Pat).make_pat(),
-            _ => unreachable!(),
-        });
+    fn flat_map_generic_param(
+        &mut self,
+        node: ast::GenericParam,
+    ) -> SmallVec<[ast::GenericParam; 1]> {
+        self.flat_map_node(node)
     }
 
-    fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
-        let mut stmt = configure!(self, stmt);
+    fn flat_map_arm(&mut self, node: ast::Arm) -> SmallVec<[ast::Arm; 1]> {
+        self.flat_map_node(node)
+    }
 
-        // We pull macro invocations (both attributes and fn-like macro calls) out of their
-        // `StmtKind`s and treat them as statement macro invocations, not as items or expressions.
+    fn flat_map_stmt(&mut self, node: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
         // FIXME: invocations in semicolon-less expressions positions are expanded as expressions,
         // changing that requires some compatibility measures.
-        let mut stmt = if !stmt.is_expr() {
-            if let Some(attr) = self.take_first_attr(&mut stmt) {
-                return self
-                    .collect_attr(attr, Annotatable::Stmt(P(stmt)), AstFragmentKind::Stmts)
-                    .make_stmts();
-            }
-
-            match self.take_stmt_bang(stmt) {
-                Ok((add_semicolon, mac, attrs)) => {
-                    self.check_attributes(&attrs, &mac);
-                    let mut stmts = self.collect_bang(mac, AstFragmentKind::Stmts).make_stmts();
-
-                    // If this is a macro invocation with a semicolon, then apply that
-                    // semicolon to the final statement produced by expansion.
-                    if add_semicolon {
-                        if let Some(stmt) = stmts.pop() {
-                            stmts.push(stmt.add_trailing_semicolon());
-                        }
-                    }
-
-                    return stmts;
+        if node.is_expr() {
+            // The only way that we can end up with a `MacCall` expression statement,
+            // (as opposed to a `StmtKind::MacCall`) is if we have a macro as the
+            // traiing expression in a block (e.g. `fn foo() { my_macro!() }`).
+            // Record this information, so that we can report a more specific
+            // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
+            // See #78991 for an investigation of treating macros in this position
+            // as statements, rather than expressions, during parsing.
+            let mut node = configure!(self, node);
+            return match &node.kind {
+                StmtKind::Expr(expr)
+                    if matches!(**expr, ast::Expr { kind: ExprKind::MacCall(..), .. }) =>
+                {
+                    self.cx.current_expansion.is_trailing_mac = true;
+                    // Don't use `assign_id` for this statement - it may get removed
+                    // entirely due to a `#[cfg]` on the contained expression
+                    let res = noop_flat_map_stmt(node, self);
+                    self.cx.current_expansion.is_trailing_mac = false;
+                    res
                 }
-                Err(stmt) => stmt,
-            }
-        } else {
-            stmt
-        };
-
-        // The only way that we can end up with a `MacCall` expression statement,
-        // (as opposed to a `StmtKind::MacCall`) is if we have a macro as the
-        // traiing expression in a block (e.g. `fn foo() { my_macro!() }`).
-        // Record this information, so that we can report a more specific
-        // `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` lint if needed.
-        // See #78991 for an investigation of treating macros in this position
-        // as statements, rather than expressions, during parsing.
-        let res = match &stmt.kind {
-            StmtKind::Expr(expr)
-                if matches!(**expr, ast::Expr { kind: ast::ExprKind::MacCall(..), .. }) =>
-            {
-                self.cx.current_expansion.is_trailing_mac = true;
-                // Don't use `assign_id` for this statement - it may get removed
-                // entirely due to a `#[cfg]` on the contained expression
-                noop_flat_map_stmt(stmt, self)
-            }
-            _ => assign_id!(self, &mut stmt.id, || noop_flat_map_stmt(stmt, self)),
-        };
-        self.cx.current_expansion.is_trailing_mac = false;
-        res
-    }
-
-    fn visit_block(&mut self, block: &mut P<Block>) {
-        let orig_dir_ownership = mem::replace(
-            &mut self.cx.current_expansion.dir_ownership,
-            DirOwnership::UnownedViaBlock,
-        );
-        noop_visit_block(block, self);
-        self.cx.current_expansion.dir_ownership = orig_dir_ownership;
-    }
-
-    fn flat_map_item(&mut self, item: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
-        let mut item = configure!(self, item);
-
-        if let Some(attr) = self.take_first_attr(&mut item) {
-            return self
-                .collect_attr(attr, Annotatable::Item(item), AstFragmentKind::Items)
-                .make_items();
+                _ => assign_id!(self, &mut node.id, || noop_flat_map_stmt(node, self)),
+            };
         }
 
-        let mut attrs = mem::take(&mut item.attrs); // We do this to please borrowck.
-        let ident = item.ident;
-        let span = item.span;
-
-        match item.kind {
-            ast::ItemKind::MacCall(ref mac) => {
-                self.check_attributes(&attrs, &mac);
-                item.attrs = attrs;
-                item.and_then(|item| match item.kind {
-                    ItemKind::MacCall(mac) => {
-                        self.collect_bang(mac, AstFragmentKind::Items).make_items()
-                    }
-                    _ => unreachable!(),
-                })
-            }
-            ast::ItemKind::Mod(_, ref mut mod_kind) if ident != Ident::empty() => {
-                let (file_path, dir_path, dir_ownership) = match mod_kind {
-                    ModKind::Loaded(_, inline, _) => {
-                        // Inline `mod foo { ... }`, but we still need to push directories.
-                        let (dir_path, dir_ownership) = mod_dir_path(
-                            &self.cx.sess,
-                            ident,
-                            &attrs,
-                            &self.cx.current_expansion.module,
-                            self.cx.current_expansion.dir_ownership,
-                            *inline,
-                        );
-                        item.attrs = attrs;
-                        (None, dir_path, dir_ownership)
-                    }
-                    ModKind::Unloaded => {
-                        // We have an outline `mod foo;` so we need to parse the file.
-                        let old_attrs_len = attrs.len();
-                        let ParsedExternalMod {
-                            mut items,
-                            inner_span,
-                            file_path,
-                            dir_path,
-                            dir_ownership,
-                        } = parse_external_mod(
-                            &self.cx.sess,
-                            ident,
-                            span,
-                            &self.cx.current_expansion.module,
-                            self.cx.current_expansion.dir_ownership,
-                            &mut attrs,
-                        );
-
-                        if let Some(extern_mod_loaded) = self.cx.extern_mod_loaded {
-                            (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span);
-                        }
-
-                        *mod_kind = ModKind::Loaded(items, Inline::No, inner_span);
-                        item.attrs = attrs;
-                        if item.attrs.len() > old_attrs_len {
-                            // If we loaded an out-of-line module and added some inner attributes,
-                            // then we need to re-configure it and re-collect attributes for
-                            // resolution and expansion.
-                            item = configure!(self, item);
-
-                            if let Some(attr) = self.take_first_attr(&mut item) {
-                                return self
-                                    .collect_attr(
-                                        attr,
-                                        Annotatable::Item(item),
-                                        AstFragmentKind::Items,
-                                    )
-                                    .make_items();
-                            }
-                        }
-                        (Some(file_path), dir_path, dir_ownership)
-                    }
-                };
-
-                // Set the module info before we flat map.
-                let mut module = self.cx.current_expansion.module.with_dir_path(dir_path);
-                module.mod_path.push(ident);
-                if let Some(file_path) = file_path {
-                    module.file_path_stack.push(file_path);
-                }
-
-                let orig_module =
-                    mem::replace(&mut self.cx.current_expansion.module, Rc::new(module));
-                let orig_dir_ownership =
-                    mem::replace(&mut self.cx.current_expansion.dir_ownership, dir_ownership);
-
-                let result = assign_id!(self, &mut item.id, || noop_flat_map_item(item, self));
-
-                // Restore the module info.
-                self.cx.current_expansion.dir_ownership = orig_dir_ownership;
-                self.cx.current_expansion.module = orig_module;
-
-                result
-            }
-            _ => {
-                item.attrs = attrs;
-                // The crate root is special - don't assign an ID to it.
-                if !(matches!(item.kind, ast::ItemKind::Mod(..)) && ident == Ident::empty()) {
-                    assign_id!(self, &mut item.id, || noop_flat_map_item(item, self))
-                } else {
-                    noop_flat_map_item(item, self)
-                }
-            }
-        }
+        self.flat_map_node(node)
     }
 
-    fn flat_map_trait_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
-        let mut item = configure!(self, item);
-
-        if let Some(attr) = self.take_first_attr(&mut item) {
-            return self
-                .collect_attr(attr, Annotatable::TraitItem(item), AstFragmentKind::TraitItems)
-                .make_trait_items();
-        }
-
-        match item.kind {
-            ast::AssocItemKind::MacCall(ref mac) => {
-                self.check_attributes(&item.attrs, &mac);
-                item.and_then(|item| match item.kind {
-                    ast::AssocItemKind::MacCall(mac) => {
-                        self.collect_bang(mac, AstFragmentKind::TraitItems).make_trait_items()
-                    }
-                    _ => unreachable!(),
-                })
-            }
-            _ => {
-                assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
-            }
-        }
+    fn visit_crate(&mut self, node: &mut ast::Crate) {
+        self.visit_node(node)
     }
 
-    fn flat_map_impl_item(&mut self, item: P<ast::AssocItem>) -> SmallVec<[P<ast::AssocItem>; 1]> {
-        let mut item = configure!(self, item);
-
-        if let Some(attr) = self.take_first_attr(&mut item) {
-            return self
-                .collect_attr(attr, Annotatable::ImplItem(item), AstFragmentKind::ImplItems)
-                .make_impl_items();
-        }
-
-        match item.kind {
-            ast::AssocItemKind::MacCall(ref mac) => {
-                self.check_attributes(&item.attrs, &mac);
-                item.and_then(|item| match item.kind {
-                    ast::AssocItemKind::MacCall(mac) => {
-                        self.collect_bang(mac, AstFragmentKind::ImplItems).make_impl_items()
-                    }
-                    _ => unreachable!(),
-                })
-            }
-            _ => {
-                assign_id!(self, &mut item.id, || noop_flat_map_assoc_item(item, self))
-            }
-        }
+    fn visit_ty(&mut self, node: &mut P<ast::Ty>) {
+        self.visit_node(node)
     }
 
-    fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
-        match ty.kind {
-            ast::TyKind::MacCall(_) => {}
-            _ => return noop_visit_ty(ty, self),
-        };
-
-        visit_clobber(ty, |mut ty| match mem::replace(&mut ty.kind, ast::TyKind::Err) {
-            ast::TyKind::MacCall(mac) => self.collect_bang(mac, AstFragmentKind::Ty).make_ty(),
-            _ => unreachable!(),
-        });
+    fn visit_pat(&mut self, node: &mut P<ast::Pat>) {
+        self.visit_node(node)
     }
 
-    fn flat_map_foreign_item(
-        &mut self,
-        foreign_item: P<ast::ForeignItem>,
-    ) -> SmallVec<[P<ast::ForeignItem>; 1]> {
-        let mut foreign_item = configure!(self, foreign_item);
-
-        if let Some(attr) = self.take_first_attr(&mut foreign_item) {
-            return self
-                .collect_attr(
-                    attr,
-                    Annotatable::ForeignItem(foreign_item),
-                    AstFragmentKind::ForeignItems,
-                )
-                .make_foreign_items();
-        }
-
-        match foreign_item.kind {
-            ast::ForeignItemKind::MacCall(ref mac) => {
-                self.check_attributes(&foreign_item.attrs, &mac);
-                foreign_item.and_then(|item| match item.kind {
-                    ast::ForeignItemKind::MacCall(mac) => {
-                        self.collect_bang(mac, AstFragmentKind::ForeignItems).make_foreign_items()
-                    }
-                    _ => unreachable!(),
-                })
-            }
-            _ => {
-                assign_id!(self, &mut foreign_item.id, || noop_flat_map_foreign_item(
-                    foreign_item,
-                    self
-                ))
-            }
-        }
+    fn visit_expr(&mut self, node: &mut P<ast::Expr>) {
+        self.cfg.configure_expr(node);
+        self.visit_node(node)
     }
 
-    fn flat_map_generic_param(
-        &mut self,
-        param: ast::GenericParam,
-    ) -> SmallVec<[ast::GenericParam; 1]> {
-        let mut param = configure!(self, param);
-
-        if let Some(attr) = self.take_first_attr(&mut param) {
-            return self
-                .collect_attr(
-                    attr,
-                    Annotatable::GenericParam(param),
-                    AstFragmentKind::GenericParams,
-                )
-                .make_generic_params();
-        }
+    fn filter_map_expr(&mut self, node: P<ast::Expr>) -> Option<P<ast::Expr>> {
+        self.flat_map_node(AstLikeWrapper::new(node, OptExprTag))
+    }
 
-        assign_id!(self, &mut param.id, || noop_flat_map_generic_param(param, self))
+    fn visit_block(&mut self, node: &mut P<ast::Block>) {
+        let orig_dir_ownership = mem::replace(
+            &mut self.cx.current_expansion.dir_ownership,
+            DirOwnership::UnownedViaBlock,
+        );
+        noop_visit_block(node, self);
+        self.cx.current_expansion.dir_ownership = orig_dir_ownership;
     }
 
-    fn visit_id(&mut self, id: &mut ast::NodeId) {
+    fn visit_id(&mut self, id: &mut NodeId) {
         // We may have already assigned a `NodeId`
         // by calling `assign_id`
         if self.monotonic && *id == ast::DUMMY_NODE_ID {
index 47a64b457d0cadf216df5240c7a07d1b1e6e8b42..5599c1df6d9de3c0011d353075a39d8b4f252412 100644 (file)
@@ -1,3 +1,5 @@
+#![feature(associated_type_bounds)]
+#![feature(associated_type_defaults)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
 #![cfg_attr(bootstrap, feature(destructuring_assignment))]
index 25b3a5820e60aaaed52d6b42e870f672a23154a3..af593e92634b034be962b944d9038b036bf2568c 100644 (file)
@@ -50,7 +50,8 @@ fn mac_placeholder() -> ast::MacCall {
             attrs: Default::default(),
             items: Default::default(),
             span,
-            is_placeholder: Some(id),
+            id,
+            is_placeholder: true,
         }),
         AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()),
         AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())),
@@ -122,7 +123,7 @@ fn mac_placeholder() -> ast::MacCall {
             span,
             is_placeholder: true,
         }]),
-        AstFragmentKind::Fields => AstFragment::Fields(smallvec![ast::ExprField {
+        AstFragmentKind::ExprFields => AstFragment::ExprFields(smallvec![ast::ExprField {
             attrs: Default::default(),
             expr: expr_placeholder(),
             id,
@@ -131,7 +132,7 @@ fn mac_placeholder() -> ast::MacCall {
             span,
             is_placeholder: true,
         }]),
-        AstFragmentKind::FieldPats => AstFragment::FieldPats(smallvec![ast::PatField {
+        AstFragmentKind::PatFields => AstFragment::PatFields(smallvec![ast::PatField {
             attrs: Default::default(),
             id,
             ident,
@@ -158,7 +159,7 @@ fn mac_placeholder() -> ast::MacCall {
             ty: ty(),
             is_placeholder: true,
         }]),
-        AstFragmentKind::StructFields => AstFragment::StructFields(smallvec![ast::FieldDef {
+        AstFragmentKind::FieldDefs => AstFragment::FieldDefs(smallvec![ast::FieldDef {
             attrs: Default::default(),
             id,
             ident: None,
@@ -362,8 +363,8 @@ fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
     }
 
     fn visit_crate(&mut self, krate: &mut ast::Crate) {
-        if let Some(id) = krate.is_placeholder {
-            *krate = self.remove(id).make_crate();
+        if krate.is_placeholder {
+            *krate = self.remove(krate.id).make_crate();
         } else {
             noop_visit_crate(krate, self)
         }
index 56564656556ef8ab68d6151f8186f5edd6c242f6..efbe0b65715f41bde785d14c1bdff0a0fa7d880c 100644 (file)
@@ -158,7 +158,7 @@ macro_rules! op {
                 for ch in data.as_str().chars() {
                     escaped.extend(ch.escape_debug());
                 }
-                let stream = vec![
+                let stream = [
                     Ident(sym::doc, false),
                     Eq,
                     TokenKind::lit(token::Str, Symbol::intern(&escaped), None),
@@ -221,7 +221,7 @@ fn to_internal(self) -> TokenStream {
                 let integer = TokenKind::lit(token::Integer, symbol, suffix);
                 let a = tokenstream::TokenTree::token(minus, span);
                 let b = tokenstream::TokenTree::token(integer, span);
-                return vec![a, b].into_iter().collect();
+                return [a, b].into_iter().collect();
             }
             TokenTree::Literal(self::Literal {
                 lit: token::Lit { kind: token::Float, symbol, suffix },
@@ -232,7 +232,7 @@ fn to_internal(self) -> TokenStream {
                 let float = TokenKind::lit(token::Float, symbol, suffix);
                 let a = tokenstream::TokenTree::token(minus, span);
                 let b = tokenstream::TokenTree::token(float, span);
-                return vec![a, b].into_iter().collect();
+                return [a, b].into_iter().collect();
             }
             TokenTree::Literal(self::Literal { lit, span }) => {
                 return tokenstream::TokenTree::token(Literal(lit), span).into();
index a297bac86c410406c116d5679130ff033a3df6b1..154bae4cb058b370d3d809dfd79331eecb466013 100644 (file)
@@ -56,7 +56,7 @@ fn to_opt_strs(self) -> Vec<Option<&'static str>> {
         match self {
             UnlabelledNodes(len) => vec![None; len],
             AllNodesLabelled(lbls) => lbls.into_iter().map(Some).collect(),
-            SomeNodesLabelled(lbls) => lbls.into_iter().collect(),
+            SomeNodesLabelled(lbls) => lbls,
         }
     }
 
index 69572807e7c9d6cf87853dfa842bbe52849dec64..76d94fe7dbcd2cbb6bf00e37afb27be49c8c5eb0 100644 (file)
@@ -205,7 +205,6 @@ pub fn is_global(&self) -> bool {
 #[derive(Debug, HashStable_Generic)]
 pub struct PathSegment<'hir> {
     /// The identifier portion of this path segment.
-    #[stable_hasher(project(name))]
     pub ident: Ident,
     // `id` and `res` are optional. We currently only use these in save-analysis,
     // any path segments without these will not have save-analysis info and
@@ -294,10 +293,6 @@ pub fn id(&self) -> HirId {
         }
     }
 
-    pub fn is_const(&self) -> bool {
-        matches!(self, GenericArg::Const(_))
-    }
-
     pub fn is_synthetic(&self) -> bool {
         matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::empty())
     }
@@ -319,6 +314,13 @@ pub fn to_ord(&self) -> ast::ParamKindOrd {
             GenericArg::Infer(_) => ast::ParamKindOrd::Infer,
         }
     }
+
+    pub fn is_ty_or_const(&self) -> bool {
+        match self {
+            GenericArg::Lifetime(_) => false,
+            GenericArg::Type(_) | GenericArg::Const(_) | GenericArg::Infer(_) => true,
+        }
+    }
 }
 
 #[derive(Debug, HashStable_Generic)]
@@ -850,7 +852,6 @@ pub struct PatField<'hir> {
     #[stable_hasher(ignore)]
     pub hir_id: HirId,
     /// The identifier for the field.
-    #[stable_hasher(project(name))]
     pub ident: Ident,
     /// The pattern the field is destructured to.
     pub pat: &'hir Pat<'hir>,
@@ -1407,6 +1408,20 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// A literal.
 pub type Lit = Spanned<LitKind>;
 
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+pub enum ArrayLen {
+    Infer(HirId, Span),
+    Body(AnonConst),
+}
+
+impl ArrayLen {
+    pub fn hir_id(&self) -> HirId {
+        match self {
+            &ArrayLen::Infer(hir_id, _) | &ArrayLen::Body(AnonConst { hir_id, body: _ }) => hir_id,
+        }
+    }
+}
+
 /// A constant (expression) that's not an item or associated item,
 /// but needs its own `DefId` for type-checking, const-eval, etc.
 /// These are usually found nested inside types (e.g., array lengths)
@@ -1756,7 +1771,7 @@ pub enum ExprKind<'hir> {
     ///
     /// E.g., `[1; 5]`. The first expression is the element
     /// to be repeated; the second is the number of times to repeat it.
-    Repeat(&'hir Expr<'hir>, AnonConst),
+    Repeat(&'hir Expr<'hir>, ArrayLen),
 
     /// A suspension point for generators (i.e., `yield <expr>`).
     Yield(&'hir Expr<'hir>, YieldSource),
@@ -2113,7 +2128,6 @@ pub enum ImplItemKind<'hir> {
 #[derive(Debug, HashStable_Generic)]
 pub struct TypeBinding<'hir> {
     pub hir_id: HirId,
-    #[stable_hasher(project(name))]
     pub ident: Ident,
     pub gen_args: &'hir GenericArgs<'hir>,
     pub kind: TypeBindingKind<'hir>,
@@ -2266,7 +2280,7 @@ pub enum TyKind<'hir> {
     /// A variable length slice (i.e., `[T]`).
     Slice(&'hir Ty<'hir>),
     /// A fixed length array (i.e., `[T; n]`).
-    Array(&'hir Ty<'hir>, AnonConst),
+    Array(&'hir Ty<'hir>, ArrayLen),
     /// A raw pointer (i.e., `*const T` or `*mut T`).
     Ptr(MutTy<'hir>),
     /// A reference (i.e., `&'a T` or `&'a mut T`).
@@ -2484,7 +2498,7 @@ pub fn span(&self) -> Span {
     }
 }
 
-#[derive(Encodable, Debug)]
+#[derive(Encodable, Debug, HashStable_Generic)]
 pub struct Mod<'hir> {
     /// A span from the first token past `{` to the last token until `}`.
     /// For `mod foo;`, the inner span ranges from the first token
@@ -2501,7 +2515,6 @@ pub struct EnumDef<'hir> {
 #[derive(Debug, HashStable_Generic)]
 pub struct Variant<'hir> {
     /// Name of the variant.
-    #[stable_hasher(project(name))]
     pub ident: Ident,
     /// Id of the variant (not the constructor, see `VariantData::ctor_hir_id()`).
     pub id: HirId,
@@ -2591,7 +2604,6 @@ pub fn is_pub_restricted(&self) -> bool {
 #[derive(Debug, HashStable_Generic)]
 pub struct FieldDef<'hir> {
     pub span: Span,
-    #[stable_hasher(project(name))]
     pub ident: Ident,
     pub vis: Visibility<'hir>,
     pub hir_id: HirId,
@@ -2850,7 +2862,6 @@ pub fn descr(&self) -> &'static str {
 #[derive(Encodable, Debug, HashStable_Generic)]
 pub struct TraitItemRef {
     pub id: TraitItemId,
-    #[stable_hasher(project(name))]
     pub ident: Ident,
     pub kind: AssocItemKind,
     pub span: Span,
@@ -2866,11 +2877,12 @@ pub struct TraitItemRef {
 #[derive(Debug, HashStable_Generic)]
 pub struct ImplItemRef {
     pub id: ImplItemId,
-    #[stable_hasher(project(name))]
     pub ident: Ident,
     pub kind: AssocItemKind,
     pub span: Span,
     pub defaultness: Defaultness,
+    /// When we are in a trait impl, link to the trait-item's id.
+    pub trait_item_def_id: Option<DefId>,
 }
 
 #[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
@@ -2905,7 +2917,6 @@ pub fn hir_id(&self) -> HirId {
 #[derive(Debug, HashStable_Generic)]
 pub struct ForeignItemRef {
     pub id: ForeignItemId,
-    #[stable_hasher(project(name))]
     pub ident: Ident,
     pub span: Span,
 }
index 1482a96cae3165b289c2a4a31ea8fde86ed1f8c6..5b486819c35e83e55296f187a264c265c2a0c16a 100644 (file)
@@ -19,11 +19,13 @@ pub struct HirId {
 }
 
 impl HirId {
+    #[inline]
     pub fn expect_owner(self) -> LocalDefId {
         assert_eq!(self.local_id.index(), 0);
         self.owner
     }
 
+    #[inline]
     pub fn as_owner(self) -> Option<LocalDefId> {
         if self.local_id.index() == 0 { Some(self.owner) } else { None }
     }
index 0fab7cbfeea3472a3d2758f987ba4c0e1304d84f..7c77930193c0b2818ac1e097abd56d756443f68a 100644 (file)
@@ -383,6 +383,9 @@ fn visit_arm(&mut self, a: &'v Arm<'v>) {
     fn visit_pat(&mut self, p: &'v Pat<'v>) {
         walk_pat(self, p)
     }
+    fn visit_array_length(&mut self, len: &'v ArrayLen) {
+        walk_array_len(self, len)
+    }
     fn visit_anon_const(&mut self, c: &'v AnonConst) {
         walk_anon_const(self, c)
     }
@@ -753,7 +756,7 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
         }
         TyKind::Array(ref ty, ref length) => {
             visitor.visit_ty(ty);
-            visitor.visit_anon_const(length)
+            visitor.visit_array_length(length)
         }
         TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
             for bound in bounds {
@@ -1085,7 +1088,8 @@ pub fn walk_foreign_item_ref<'v, V: Visitor<'v>>(
 
 pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) {
     // N.B., deliberately force a compilation error if/when new fields are added.
-    let ImplItemRef { id, ident, ref kind, span: _, ref defaultness } = *impl_item_ref;
+    let ImplItemRef { id, ident, ref kind, span: _, ref defaultness, trait_item_def_id: _ } =
+        *impl_item_ref;
     visitor.visit_nested_impl_item(id);
     visitor.visit_ident(ident);
     visitor.visit_associated_item_kind(kind);
@@ -1124,6 +1128,13 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
     }
 }
 
+pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
+    match len {
+        &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
+        ArrayLen::Body(c) => visitor.visit_anon_const(c),
+    }
+}
+
 pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
     visitor.visit_id(constant.hir_id);
     visitor.visit_nested_body(constant.body);
@@ -1147,7 +1158,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
         ExprKind::Repeat(ref element, ref count) => {
             visitor.visit_expr(element);
-            visitor.visit_anon_const(count)
+            visitor.visit_array_length(count)
         }
         ExprKind::Struct(ref qpath, fields, ref optional_base) => {
             visitor.visit_qpath(qpath, expression.hir_id, expression.span);
index a03c561861e2b58a6df22560399dce137d59487d..def0c1d06871b252dfa98327686fd05c78e56e7f 100644 (file)
@@ -151,20 +151,12 @@ fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) {
 /// Extracts the first `lang = "$name"` out of a list of attributes.
 /// The attributes `#[panic_handler]` and `#[alloc_error_handler]`
 /// are also extracted out when found.
-///
-/// About the `check_name` argument: passing in a `Session` would be simpler,
-/// because then we could call `Session::check_name` directly. But we want to
-/// avoid the need for `rustc_hir` to depend on `rustc_session`, so we
-/// use a closure instead.
-pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Symbol, Span)>
-where
-    F: Fn(&'a ast::Attribute, Symbol) -> bool,
-{
+pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
     attrs.iter().find_map(|attr| {
         Some(match attr {
-            _ if check_name(attr, sym::lang) => (attr.value_str()?, attr.span),
-            _ if check_name(attr, sym::panic_handler) => (sym::panic_impl, attr.span),
-            _ if check_name(attr, sym::alloc_error_handler) => (sym::oom, attr.span),
+            _ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span),
+            _ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span),
+            _ if attr.has_name(sym::alloc_error_handler) => (sym::oom, attr.span),
             _ => return None,
         })
     })
index c8d729a999e831e15cb21a625c9a8d32d3c1bb70..a43c1f9d9ae3352bb4dd590064b30d20f17644cf 100644 (file)
@@ -2,7 +2,7 @@
 
 use crate::hir::{
     AttributeMap, BodyId, Crate, Expr, ForeignItem, ForeignItemId, ImplItem, ImplItemId, Item,
-    ItemId, Mod, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind,
+    ItemId, OwnerNodes, TraitCandidate, TraitItem, TraitItemId, Ty, VisibilityKind,
 };
 use crate::hir_id::{HirId, ItemLocalId};
 use rustc_span::def_id::DefPathHash;
@@ -16,7 +16,6 @@ pub trait HashStableContext:
     fn hash_hir_id(&mut self, _: HirId, hasher: &mut StableHasher);
     fn hash_body_id(&mut self, _: BodyId, hasher: &mut StableHasher);
     fn hash_reference_to_item(&mut self, _: HirId, hasher: &mut StableHasher);
-    fn hash_hir_mod(&mut self, _: &Mod<'_>, hasher: &mut StableHasher);
     fn hash_hir_expr(&mut self, _: &Expr<'_>, hasher: &mut StableHasher);
     fn hash_hir_ty(&mut self, _: &Ty<'_>, hasher: &mut StableHasher);
     fn hash_hir_visibility_kind(&mut self, _: &VisibilityKind<'_>, hasher: &mut StableHasher);
@@ -132,12 +131,6 @@ fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
     }
 }
 
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Mod<'_> {
-    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_hir_mod(self, hasher)
-    }
-}
-
 impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Expr<'_> {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         hcx.hash_hir_expr(self, hasher)
index 58c3065240c9495770ebb6d6cf9d7cfc48f78930..78748209d1a5bd55a0cd559a597451a5fa77c9e9 100644 (file)
@@ -18,13 +18,9 @@ macro_rules! weak_lang_items {
     map
 });
 
-/// The `check_name` argument avoids the need for `rustc_hir` to depend on
-/// `rustc_session`.
-pub fn link_name<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<Symbol>
-where
-    F: Fn(&'a ast::Attribute, Symbol) -> bool
+pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol>
 {
-    lang_items::extract(check_name, attrs).and_then(|(name, _)| {
+    lang_items::extract(attrs).and_then(|(name, _)| {
         $(if name == sym::$name {
             Some(sym::$sym)
         } else)* {
index ad47c69652035fa652c9f9d5da556c8e8970fbbf..1fd226291d12afca04b846cbc102dbfa7d4acf34 100644 (file)
@@ -358,7 +358,7 @@ pub fn print_type(&mut self, ty: &hir::Ty<'_>) {
                 self.word("[");
                 self.print_type(&ty);
                 self.word("; ");
-                self.print_anon_const(length);
+                self.print_array_length(length);
                 self.word("]");
             }
             hir::TyKind::Typeof(ref e) => {
@@ -1065,6 +1065,13 @@ pub fn print_if(
         self.print_else(elseopt)
     }
 
+    pub fn print_array_length(&mut self, len: &hir::ArrayLen) {
+        match len {
+            hir::ArrayLen::Infer(_, _) => self.word("_"),
+            hir::ArrayLen::Body(ct) => self.print_anon_const(ct),
+        }
+    }
+
     pub fn print_anon_const(&mut self, constant: &hir::AnonConst) {
         self.ann.nested(self, Nested::Body(constant.body))
     }
@@ -1140,12 +1147,12 @@ fn print_expr_anon_const(&mut self, anon_const: &hir::AnonConst) {
         self.end()
     }
 
-    fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::AnonConst) {
+    fn print_expr_repeat(&mut self, element: &hir::Expr<'_>, count: &hir::ArrayLen) {
         self.ibox(INDENT_UNIT);
         self.word("[");
         self.print_expr(element);
         self.word_space(";");
-        self.print_anon_const(count);
+        self.print_array_length(count);
         self.word("]");
         self.end()
     }
@@ -1874,7 +1881,11 @@ pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
             PatKind::Struct(ref qpath, ref fields, etc) => {
                 self.print_qpath(qpath, true);
                 self.nbsp();
-                self.word_space("{");
+                self.word("{");
+                let empty = fields.is_empty() && !etc;
+                if !empty {
+                    self.space();
+                }
                 self.commasep_cmnt(
                     Consistent,
                     &fields,
@@ -1895,7 +1906,9 @@ pub fn print_pat(&mut self, pat: &hir::Pat<'_>) {
                     }
                     self.word("..");
                 }
-                self.space();
+                if !empty {
+                    self.space();
+                }
                 self.word("}");
             }
             PatKind::Or(ref pats) => {
index 7ac00b4609aaf92efe2b2aaee926d97bc46a8271..7676ff3c41cc7adcc7c783f9a20e5e07e13747ea 100644 (file)
@@ -9,6 +9,13 @@
 //! - `#[rustc_clean(cfg="rev2")]` same as above, except that the
 //!   fingerprints must be the SAME (along with all other fingerprints).
 //!
+//! - `#[rustc_clean(cfg="rev2", loaded_from_disk='typeck")]` asserts that
+//!   the query result for `DepNode::typeck(X)` was actually
+//!   loaded from disk (not just marked green). This can be useful
+//!   to ensure that a test is actually exercising the deserialization
+//!   logic for a particular query result. This can be combined with
+//!   `except`
+//!
 //! Errors are reported if we are in the suitable configuration but
 //! the required condition is not met.
 
@@ -28,6 +35,7 @@
 use std::iter::FromIterator;
 use std::vec::Vec;
 
+const LOADED_FROM_DISK: Symbol = sym::loaded_from_disk;
 const EXCEPT: Symbol = sym::except;
 const CFG: Symbol = sym::cfg;
 
 struct Assertion {
     clean: Labels,
     dirty: Labels,
+    loaded_from_disk: Labels,
 }
 
 pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
@@ -174,6 +183,7 @@ fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<A
     fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion {
         let (name, mut auto) = self.auto_labels(item_id, attr);
         let except = self.except(attr);
+        let loaded_from_disk = self.loaded_from_disk(attr);
         for e in except.iter() {
             if !auto.remove(e) {
                 let msg = format!(
@@ -183,7 +193,19 @@ fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion
                 self.tcx.sess.span_fatal(attr.span, &msg);
             }
         }
-        Assertion { clean: auto, dirty: except }
+        Assertion { clean: auto, dirty: except, loaded_from_disk }
+    }
+
+    /// `loaded_from_disk=` attribute value
+    fn loaded_from_disk(&self, attr: &Attribute) -> Labels {
+        for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
+            if item.has_name(LOADED_FROM_DISK) {
+                let value = expect_associated_value(self.tcx, &item);
+                return self.resolve_labels(&item, value);
+            }
+        }
+        // If `loaded_from_disk=` is not specified, don't assert anything
+        Labels::default()
     }
 
     /// `except=` attribute value
@@ -201,8 +223,7 @@ fn except(&self, attr: &Attribute) -> Labels {
     /// Return all DepNode labels that should be asserted for this item.
     /// index=0 is the "name" used for error messages
     fn auto_labels(&mut self, item_id: LocalDefId, attr: &Attribute) -> (&'static str, Labels) {
-        let hir_id = self.tcx.hir().local_def_id_to_hir_id(item_id);
-        let node = self.tcx.hir().get(hir_id);
+        let node = self.tcx.hir().get_by_def_id(item_id);
         let (name, labels) = match node {
             HirNode::Item(item) => {
                 match item.kind {
@@ -332,6 +353,18 @@ fn assert_clean(&self, item_span: Span, dep_node: DepNode) {
         }
     }
 
+    fn assert_loaded_from_disk(&self, item_span: Span, dep_node: DepNode) {
+        debug!("assert_loaded_from_disk({:?})", dep_node);
+
+        if !self.tcx.dep_graph.debug_was_loaded_from_disk(dep_node) {
+            let dep_node_str = self.dep_node_str(&dep_node);
+            self.tcx.sess.span_err(
+                item_span,
+                &format!("`{}` should have been loaded from disk but it was not", dep_node_str),
+            );
+        }
+    }
+
     fn check_item(&mut self, item_id: LocalDefId, item_span: Span) {
         let def_path_hash = self.tcx.def_path_hash(item_id.to_def_id());
         for attr in self.tcx.get_attrs(item_id.to_def_id()).iter() {
@@ -348,6 +381,10 @@ fn check_item(&mut self, item_id: LocalDefId, item_span: Span) {
                 let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
                 self.assert_dirty(item_span, dep_node);
             }
+            for label in assertion.loaded_from_disk {
+                let dep_node = DepNode::from_label_string(self.tcx, &label, def_path_hash).unwrap();
+                self.assert_loaded_from_disk(item_span, dep_node);
+            }
         }
     }
 }
@@ -382,7 +419,7 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
             let value = expect_associated_value(tcx, &item);
             debug!("check_config: searching for cfg {:?}", value);
             cfg = Some(config.contains(&(value, None)));
-        } else if !item.has_name(EXCEPT) {
+        } else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) {
             tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty()));
         }
     }
index 652ef6bcdced2cce04f7596481ade655f7222e25..184796948b67d21956aa2e63d2a8b755f2ee7538 100644 (file)
@@ -13,7 +13,7 @@ fn test_all_except_most_recent() {
         .keys()
         .cloned()
         .collect::<FxHashSet<PathBuf>>(),
-        vec![PathBuf::from("1"), PathBuf::from("2"), PathBuf::from("3"), PathBuf::from("4"),]
+        [PathBuf::from("1"), PathBuf::from("2"), PathBuf::from("3"), PathBuf::from("4"),]
             .into_iter()
             .collect::<FxHashSet<PathBuf>>()
     );
@@ -40,7 +40,7 @@ fn test_find_source_directory_in_iter() {
     // Find newest
     assert_eq!(
         find_source_directory_in_iter(
-            vec![
+            [
                 PathBuf::from("crate-dir/s-3234-0000-svh"),
                 PathBuf::from("crate-dir/s-2234-0000-svh"),
                 PathBuf::from("crate-dir/s-1234-0000-svh")
@@ -54,7 +54,7 @@ fn test_find_source_directory_in_iter() {
     // Filter out "-working"
     assert_eq!(
         find_source_directory_in_iter(
-            vec![
+            [
                 PathBuf::from("crate-dir/s-3234-0000-working"),
                 PathBuf::from("crate-dir/s-2234-0000-svh"),
                 PathBuf::from("crate-dir/s-1234-0000-svh")
@@ -66,12 +66,12 @@ fn test_find_source_directory_in_iter() {
     );
 
     // Handle empty
-    assert_eq!(find_source_directory_in_iter(vec![].into_iter(), &already_visited), None);
+    assert_eq!(find_source_directory_in_iter([].into_iter(), &already_visited), None);
 
     // Handle only working
     assert_eq!(
         find_source_directory_in_iter(
-            vec![
+            [
                 PathBuf::from("crate-dir/s-3234-0000-working"),
                 PathBuf::from("crate-dir/s-2234-0000-working"),
                 PathBuf::from("crate-dir/s-1234-0000-working")
index 6023973665360e46ec59c41e478feee9deaee030..0e267179e309978837f9a9c8844cb9ade385257d 100644 (file)
@@ -470,7 +470,7 @@ fn canonicalize<V>(
     {
         let needs_canonical_flags = if canonicalize_region_mode.any() {
             TypeFlags::NEEDS_INFER |
-            TypeFlags::HAS_POTENTIAL_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_POTENTIAL_FREE_REGIONS`
+            TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
             TypeFlags::HAS_TY_PLACEHOLDER |
             TypeFlags::HAS_CT_PLACEHOLDER
         } else {
index da71edbd2d941b3a5f759b56ce512f62cd2f2b2b..a77fd8fae8d20d059cbfc110d90bda00580111d9 100644 (file)
@@ -129,8 +129,6 @@ pub fn super_combine_consts<R>(
     where
         R: ConstEquateRelation<'tcx>,
     {
-        let a = self.tcx.expose_default_const_substs(a);
-        let b = self.tcx.expose_default_const_substs(b);
         debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
         if a == b {
             return Ok(a);
@@ -746,9 +744,10 @@ fn consts(
                     }
                 }
             }
-            ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => {
-                assert_eq!(uv.promoted, None);
-                let substs = uv.substs(self.tcx());
+            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
+                if self.tcx().lazy_normalization() =>
+            {
+                assert_eq!(promoted, None);
                 let substs = self.relate_with_variance(
                     ty::Variance::Invariant,
                     ty::VarianceDiagInfo::default(),
@@ -757,7 +756,7 @@ fn consts(
                 )?;
                 Ok(self.tcx().mk_const(ty::Const {
                     ty: c.ty,
-                    val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)),
+                    val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
                 }))
             }
             _ => relate::super_relate_consts(self, c, c),
@@ -991,9 +990,10 @@ fn consts(
                     }
                 }
             }
-            ty::ConstKind::Unevaluated(uv) if self.tcx().lazy_normalization() => {
-                assert_eq!(uv.promoted, None);
-                let substs = uv.substs(self.tcx());
+            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
+                if self.tcx().lazy_normalization() =>
+            {
+                assert_eq!(promoted, None);
                 let substs = self.relate_with_variance(
                     ty::Variance::Invariant,
                     ty::VarianceDiagInfo::default(),
@@ -1002,7 +1002,7 @@ fn consts(
                 )?;
                 Ok(self.tcx().mk_const(ty::Const {
                     ty: c.ty,
-                    val: ty::ConstKind::Unevaluated(ty::Unevaluated::new(uv.def, substs)),
+                    val: ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted }),
                 }))
             }
             _ => relate::super_relate_consts(self, c, c),
index 9a76c05e4f6202bd23a49f7e87ee55501883c59e..6e6012fdc1a60a44dfdaaaa25115fdd086f11d49 100644 (file)
@@ -151,11 +151,10 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
 ) -> (String, Span) {
     let sm = tcx.sess.source_map();
 
-    let scope = region.free_region_binding_scope(tcx);
-    let node = tcx.hir().local_def_id_to_hir_id(scope.expect_local());
+    let scope = region.free_region_binding_scope(tcx).expect_local();
     match *region {
         ty::ReEarlyBound(ref br) => {
-            let mut sp = sm.guess_head_span(tcx.hir().span(node));
+            let mut sp = sm.guess_head_span(tcx.def_span(scope));
             if let Some(param) =
                 tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
             {
@@ -166,7 +165,7 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
         ty::ReFree(ty::FreeRegion {
             bound_region: ty::BoundRegionKind::BrNamed(_, name), ..
         }) => {
-            let mut sp = sm.guess_head_span(tcx.hir().span(node));
+            let mut sp = sm.guess_head_span(tcx.def_span(scope));
             if let Some(param) =
                 tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(name))
             {
@@ -181,13 +180,13 @@ fn msg_span_from_early_bound_and_free_regions<'tcx>(
                 } else {
                     (
                         format!("the anonymous lifetime #{} defined here", idx + 1),
-                        tcx.hir().span(node),
+                        tcx.def_span(scope),
                     )
                 }
             }
             _ => (
                 format!("the lifetime `{}` as defined here", region),
-                sm.guess_head_span(tcx.hir().span(node)),
+                sm.guess_head_span(tcx.def_span(scope)),
             ),
         },
         _ => bug!(),
@@ -771,7 +770,7 @@ fn note_error_origin(
                     self.suggest_boxing_for_return_impl_trait(
                         err,
                         ret_sp,
-                        vec![then, else_sp].into_iter(),
+                        [then, else_sp].into_iter(),
                     );
                 }
             }
@@ -807,11 +806,8 @@ fn suggest_boxing_for_return_impl_trait(
         );
         let sugg = arm_spans
             .flat_map(|sp| {
-                vec![
-                    (sp.shrink_to_lo(), "Box::new(".to_string()),
-                    (sp.shrink_to_hi(), ")".to_string()),
-                ]
-                .into_iter()
+                [(sp.shrink_to_lo(), "Box::new(".to_string()), (sp.shrink_to_hi(), ")".to_string())]
+                    .into_iter()
             })
             .collect::<Vec<_>>();
         err.multipart_suggestion(
@@ -1553,10 +1549,6 @@ fn add_labels_for_types(
         }
 
         impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypesVisitor<'tcx> {
-            fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-                Some(self.tcx)
-            }
-
             fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 if let Some((kind, def_id)) = TyCategory::from_ty(self.tcx, t) {
                     let span = self.tcx.def_span(def_id);
@@ -1762,8 +1754,7 @@ enum Mismatch<'a> {
         if let Some(ValuePairs::PolyTraitRefs(exp_found)) = values {
             if let ty::Closure(def_id, _) = exp_found.expected.skip_binder().self_ty().kind() {
                 if let Some(def_id) = def_id.as_local() {
-                    let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-                    let span = self.tcx.hir().span(hir_id);
+                    let span = self.tcx.def_span(def_id);
                     diag.span_note(span, "this closure does not fulfill the lifetime requirements");
                 }
             }
@@ -1924,7 +1915,7 @@ fn suggest_accessing_field_where_appropriate(
                 .fields
                 .iter()
                 .filter(|field| field.vis.is_accessible_from(field.did, self.tcx))
-                .map(|field| (field.ident.name, field.ty(self.tcx, expected_substs)))
+                .map(|field| (field.name, field.ty(self.tcx, expected_substs)))
                 .find(|(_, ty)| same_type_modulo_infer(ty, exp_found.found))
             {
                 if let ObligationCauseCode::Pattern { span: Some(span), .. } = *cause.code() {
@@ -2041,11 +2032,11 @@ pub fn report_and_explain_type_error(
                 if let ValuePairs::Types(ty::error::ExpectedFound { expected, found }) =
                     trace.values
                 {
-                    // 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)
                     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) =
@@ -2060,6 +2051,41 @@ pub fn report_and_explain_type_error(
                                 }
                             }
                         }
+                        // If a character was expected and the found expression is a string literal
+                        // containing a single character, perhaps the user meant to write `'c'` to
+                        // specify a character literal (issue #92479)
+                        (ty::Char, ty::Ref(_, r, _)) if r.is_str() => {
+                            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('"'))
+                                {
+                                    if code.chars().nth(1).is_none() {
+                                        err.span_suggestion(
+                                            span,
+                                            "if you meant to write a `char` literal, use single quotes",
+                                            format!("'{}'", code),
+                                            Applicability::MachineApplicable,
+                                        );
+                                    }
+                                }
+                            }
+                        }
+                        // If a string was expected and the found expression is a character literal,
+                        // perhaps the user meant to write `"s"` to specify a string literal.
+                        (ty::Ref(_, r, _), ty::Char) if r.is_str() => {
+                            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,
+                                        "if you meant to write a `str` literal, use double quotes",
+                                        format!("\"{}\"", code),
+                                        Applicability::MachineApplicable,
+                                    );
+                                }
+                            }
+                        }
                         _ => {}
                     }
                 }
@@ -2180,9 +2206,9 @@ pub fn construct_generic_bound_failure(
                     if let Some(Node::Item(Item {
                         kind: ItemKind::Trait(..) | ItemKind::Impl { .. },
                         ..
-                    })) = hir.find(parent_id)
+                    })) = hir.find_by_def_id(parent_id)
                     {
-                        Some(self.tcx.generics_of(hir.local_def_id(parent_id).to_def_id()))
+                        Some(self.tcx.generics_of(parent_id))
                     } else {
                         None
                     },
@@ -2213,7 +2239,7 @@ pub fn construct_generic_bound_failure(
                         if let Node::GenericParam(param) = hir.get(id) {
                             has_bounds = !param.bounds.is_empty();
                         }
-                        let sp = hir.span(id);
+                        let sp = self.tcx.def_span(def_id);
                         // `sp` only covers `T`, change it so that it covers
                         // `T:` when appropriate
                         let is_impl_trait = bound_kind.to_string().starts_with("impl ");
@@ -2259,12 +2285,7 @@ pub fn construct_generic_bound_failure(
             .as_ref()
             .and_then(|(_, g, _)| g.params.first())
             .and_then(|param| param.def_id.as_local())
-            .map(|def_id| {
-                (
-                    hir.span(hir.local_def_id_to_hir_id(def_id)).shrink_to_lo(),
-                    format!("{}, ", new_lt),
-                )
-            });
+            .map(|def_id| (self.tcx.def_span(def_id).shrink_to_lo(), format!("{}, ", new_lt)));
 
         let labeled_user_string = match bound_kind {
             GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
index 9cf6cde259150a433041cbdb7631d194f04d736a..4e2946bb2f910632c73cd793bb8e0869b2f1cd71 100644 (file)
@@ -12,7 +12,7 @@
 use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
 use rustc_middle::ty::{self, Const, DefIdTree, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder};
 use rustc_span::symbol::kw;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
 use std::borrow::Cow;
 
 struct FindHirNodeVisitor<'a, 'tcx> {
@@ -52,7 +52,7 @@ fn node_type_opt(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
 
     fn node_ty_contains_target(&self, hir_id: HirId) -> Option<Ty<'tcx>> {
         self.node_type_opt(hir_id).map(|ty| self.infcx.resolve_vars_if_possible(ty)).filter(|ty| {
-            ty.walk(self.infcx.tcx).any(|inner| {
+            ty.walk().any(|inner| {
                 inner == self.target
                     || match (inner.unpack(), self.target.unpack()) {
                         (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => {
@@ -445,9 +445,7 @@ pub fn extract_inference_diagnostics_data(
                             parent: None,
                         }
                     }
-                    ty::ConstKind::Unevaluated(ty::Unevaluated {
-                        substs_: Some(substs), ..
-                    }) => {
+                    ty::ConstKind::Unevaluated(ty::Unevaluated { substs, .. }) => {
                         assert!(substs.has_infer_types_or_consts());
 
                         // FIXME: We only use the first inference variable we encounter in
@@ -540,8 +538,8 @@ pub fn emit_inference_failure_err(
             // error[E0284]: type annotations needed
             //  --> file.rs:2:5
             //   |
-            // 2 |     vec![Ok(2)].into_iter().collect()?;
-            //   |                             ^^^^^^^ cannot infer type
+            // 2 |     [Ok(2)].into_iter().collect()?;
+            //   |                         ^^^^^^^ cannot infer type
             //   |
             //   = note: cannot resolve `<_ as std::ops::Try>::Ok == _`
             if span.contains(*call_span) { *call_span } else { span }
@@ -1003,9 +1001,9 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
             | ty::Opaque(..)
             | 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, Symbol::intern("N")))),
+            ty::Array(ty, c) => {
+                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
             // name in the output.
index b6dff2e53e9cd0e5eac97c50d8bbb4035685acf5..87d79b1344421c8100557475b08c7ebfc41a8501 100644 (file)
@@ -187,6 +187,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
             | ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
             {
                 let parent_id = tcx.hir().get_parent_item(*hir_id);
+                let parent_id = tcx.hir().local_def_id_to_hir_id(parent_id);
                 if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) {
                     let mut span: MultiSpan = fn_decl.output.span().into();
                     let mut add_label = true;
@@ -425,7 +426,7 @@ fn get_impl_ident_and_self_ty_from_trait(
         let tcx = self.tcx();
         match tcx.hir().get_if_local(def_id) {
             Some(Node::ImplItem(impl_item)) => {
-                match tcx.hir().find(tcx.hir().get_parent_item(impl_item.hir_id())) {
+                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id())) {
                     Some(Node::Item(Item {
                         kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
                         ..
@@ -434,13 +435,13 @@ fn get_impl_ident_and_self_ty_from_trait(
                 }
             }
             Some(Node::TraitItem(trait_item)) => {
-                let parent_id = tcx.hir().get_parent_item(trait_item.hir_id());
-                match tcx.hir().find(parent_id) {
+                let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
+                match tcx.hir().find_by_def_id(trait_did) {
                     Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
                         // The method being called is defined in the `trait`, but the `'static`
                         // obligation comes from the `impl`. Find that `impl` so that we can point
                         // at it in the suggestion.
-                        let trait_did = tcx.hir().local_def_id(parent_id).to_def_id();
+                        let trait_did = trait_did.to_def_id();
                         match tcx
                             .hir()
                             .trait_impls(trait_did)
@@ -557,12 +558,6 @@ fn suggest_constrain_dyn_trait_in_impl(
 pub(super) struct TraitObjectVisitor(pub(super) FxHashSet<DefId>);
 
 impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        // The default anon const substs cannot include
-        // trait objects, so we don't have to bother looking.
-        None
-    }
-
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match t.kind() {
             ty::Dynamic(preds, RegionKind::ReStatic) => {
index f5fb82dbf31d2c9bb95b85d4f8e73280097731a7..cd6b51195e491ff8a97add3c848698ff561d0ce1 100644 (file)
@@ -80,26 +80,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<'tcx> {
+        struct HighlightBuilder {
             highlight: RegionHighlightMode,
-            tcx: TyCtxt<'tcx>,
             counter: usize,
         }
 
-        impl<'tcx> HighlightBuilder<'tcx> {
-            fn build(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> RegionHighlightMode {
+        impl HighlightBuilder {
+            fn build(ty: Ty<'_>) -> RegionHighlightMode {
                 let mut builder =
-                    HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1, tcx };
+                    HighlightBuilder { highlight: RegionHighlightMode::default(), counter: 1 };
                 builder.visit_ty(ty);
                 builder.highlight
             }
         }
 
-        impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder<'tcx> {
-            fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-                Some(self.tcx)
-            }
-
+        impl<'tcx> ty::fold::TypeVisitor<'tcx> for HighlightBuilder {
             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);
@@ -109,12 +104,12 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
         }
 
-        let expected_highlight = HighlightBuilder::build(self.tcx(), expected);
+        let expected_highlight = HighlightBuilder::build(expected);
         let expected = self
             .infcx
             .extract_inference_diagnostics_data(expected.into(), Some(expected_highlight))
             .name;
-        let found_highlight = HighlightBuilder::build(self.tcx(), found);
+        let found_highlight = HighlightBuilder::build(found);
         let found =
             self.infcx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
 
index c40e409891bc25cb76a7612fbab231493c67de98..4af1bdf97a773f7e9796b857d02ce31ff6f24b32 100644 (file)
@@ -146,7 +146,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if !t.needs_infer() && !t.has_erasable_regions(self.tcx()) {
+        if !t.needs_infer() && !t.has_erasable_regions() {
             return t;
         }
 
index 04e04e297cdd260407ff75d0b73fae7b6a076adc..266eec08cebf57ec7fed15994cbf0998db03b961 100644 (file)
@@ -10,7 +10,6 @@
 
 use crate::traits::{self, ObligationCause, PredicateObligations, TraitEngine};
 
-use hir::def_id::CRATE_DEF_ID;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::Rollback;
@@ -291,7 +290,12 @@ pub struct InferCtxt<'a, 'tcx> {
 
     /// The `DefId` of the item in whose context we are performing inference or typeck.
     /// It is used to check whether an opaque type use is a defining use.
-    pub defining_use_anchor: LocalDefId,
+    ///
+    /// If it is `None`, we can't resolve opaque types here and need to bubble up
+    /// the obligation. This frequently happens for
+    /// short lived InferCtxt within queries. The opaque type obligations are forwarded
+    /// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
+    pub defining_use_anchor: Option<LocalDefId>,
 
     /// During type-checking/inference of a body, `in_progress_typeck_results`
     /// contains a reference to the typeck results being built up, which are
@@ -547,7 +551,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
     fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
-    defining_use_anchor: LocalDefId,
+    defining_use_anchor: Option<LocalDefId>,
 }
 
 pub trait TyCtxtInferExt<'tcx> {
@@ -556,11 +560,7 @@ pub trait TyCtxtInferExt<'tcx> {
 
 impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
-        InferCtxtBuilder {
-            tcx: self,
-            defining_use_anchor: CRATE_DEF_ID,
-            fresh_typeck_results: None,
-        }
+        InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
     }
 }
 
@@ -580,7 +580,7 @@ pub fn with_fresh_in_progress_typeck_results(mut self, table_owner: LocalDefId)
     /// (via `with_fresh_in_progress_typeck_results`) and for the inference context used
     /// in mir borrowck.
     pub fn with_opaque_type_inference(mut self, defining_use_anchor: LocalDefId) -> Self {
-        self.defining_use_anchor = defining_use_anchor;
+        self.defining_use_anchor = Some(defining_use_anchor);
         self
     }
 
@@ -1585,8 +1585,7 @@ pub fn const_eval_resolve(
         unevaluated: ty::Unevaluated<'tcx>,
         span: Option<Span>,
     ) -> EvalToConstValueResult<'tcx> {
-        let mut substs = unevaluated.substs(self.tcx);
-        substs = self.resolve_vars_if_possible(substs);
+        let substs = self.resolve_vars_if_possible(unevaluated.substs);
 
         // Postpone the evaluation of constants whose substs depend on inference
         // variables
@@ -1599,7 +1598,7 @@ pub fn const_eval_resolve(
 
         let unevaluated = ty::Unevaluated {
             def: unevaluated.def,
-            substs_: Some(substs_erased),
+            substs: substs_erased,
             promoted: unevaluated.promoted,
         };
 
index ebc0e80cdf2679562c9c83adc31036d89cc011bf..0a210ed053ce4ec7f61c9bbc0aa4ea3e0e13c6e5 100644 (file)
@@ -201,7 +201,6 @@ fn create_scope(
         };
 
         value.skip_binder().visit_with(&mut ScopeInstantiator {
-            tcx: self.infcx.tcx,
             next_region: &mut next_region,
             target_index: ty::INNERMOST,
             bound_region_scope: &mut scope,
@@ -759,7 +758,6 @@ fn const_equate_obligation(&mut self, a: &'tcx ty::Const<'tcx>, b: &'tcx ty::Con
 /// `for<..`>.  For each of those, it creates an entry in
 /// `bound_region_scope`.
 struct ScopeInstantiator<'me, 'tcx> {
-    tcx: TyCtxt<'tcx>,
     next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
     // The debruijn index of the scope we are instantiating.
     target_index: ty::DebruijnIndex,
@@ -767,10 +765,6 @@ struct ScopeInstantiator<'me, 'tcx> {
 }
 
 impl<'me, 'tcx> TypeVisitor<'tcx> for ScopeInstantiator<'me, 'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.tcx)
-    }
-
     fn visit_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: &ty::Binder<'tcx, T>,
index c2ef0b41e27bf182761eef46e02d64d33f6b86d9..8894093c66c985c0990a9b86387126eff76191c0 100644 (file)
@@ -316,7 +316,6 @@ pub fn constrain_opaque_type(
         );
 
         concrete_ty.visit_with(&mut ConstrainOpaqueTypeRegionVisitor {
-            tcx: self.tcx,
             op: |r| {
                 self.member_constraint(
                     opaque_type_key.def_id,
@@ -328,6 +327,31 @@ pub fn constrain_opaque_type(
             },
         });
     }
+
+    fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<hir::OpaqueTyOrigin> {
+        let tcx = self.tcx;
+        let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+        let parent_def_id = self.defining_use_anchor?;
+        let item_kind = &tcx.hir().expect_item(def_id).kind;
+        let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, ..  }) = item_kind else {
+            span_bug!(
+                tcx.def_span(def_id),
+                "weird opaque type: {:#?}",
+                item_kind
+            )
+        };
+        let in_definition_scope = match *origin {
+            // Async `impl Trait`
+            hir::OpaqueTyOrigin::AsyncFn(parent) => parent == parent_def_id,
+            // Anonymous `impl Trait`
+            hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
+            // Named `type Foo = impl Bar;`
+            hir::OpaqueTyOrigin::TyAlias => {
+                may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
+            }
+        };
+        in_definition_scope.then_some(*origin)
+    }
 }
 
 // Visitor that requires that (almost) all regions in the type visited outlive
@@ -343,19 +367,14 @@ pub fn constrain_opaque_type(
 //
 // We ignore any type parameters because impl trait values are assumed to
 // capture all the in-scope type parameters.
-struct ConstrainOpaqueTypeRegionVisitor<'tcx, OP> {
-    tcx: TyCtxt<'tcx>,
+struct ConstrainOpaqueTypeRegionVisitor<OP> {
     op: OP,
 }
 
-impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<'tcx, OP>
+impl<'tcx, OP> TypeVisitor<'tcx> for ConstrainOpaqueTypeRegionVisitor<OP>
 where
     OP: FnMut(ty::Region<'tcx>),
 {
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.tcx)
-    }
-
     fn visit_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: &ty::Binder<'tcx, T>,
@@ -377,7 +396,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         // We're only interested in types involving regions
-        if !ty.flags().intersects(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
+        if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) {
             return ControlFlow::CONTINUE;
         }
 
@@ -459,31 +478,10 @@ fn instantiate_opaque_types_in_map<T: TypeFoldable<'tcx>>(&mut self, value: T) -
                     // }
                     // ```
                     if let Some(def_id) = def_id.as_local() {
-                        let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-                        let parent_def_id = self.infcx.defining_use_anchor;
-                        let item_kind = &tcx.hir().expect_item(def_id).kind;
-                        let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, ..  }) = item_kind else {
-                            span_bug!(
-                                self.value_span,
-                                "weird opaque type: {:#?}, {:#?}",
-                                ty.kind(),
-                                item_kind
-                            )
-                        };
-                        let in_definition_scope = match *origin {
-                            // Async `impl Trait`
-                            hir::OpaqueTyOrigin::AsyncFn(parent) => parent == parent_def_id,
-                            // Anonymous `impl Trait`
-                            hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
-                            // Named `type Foo = impl Bar;`
-                            hir::OpaqueTyOrigin::TyAlias => {
-                                may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
-                            }
-                        };
-                        if in_definition_scope {
+                        if let Some(origin) = self.infcx.opaque_type_origin(def_id) {
                             let opaque_type_key =
                                 OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
-                            return self.fold_opaque_ty(ty, opaque_type_key, *origin);
+                            return self.fold_opaque_ty(ty, opaque_type_key, origin);
                         }
 
                         debug!(
@@ -551,6 +549,22 @@ fn fold_opaque_ty(
             let predicate = predicate.subst(tcx, substs);
             debug!(?predicate);
 
+            let predicate = predicate.fold_with(&mut BottomUpFolder {
+                tcx,
+                ty_op: |ty| match *ty.kind() {
+                    // Replace all other mentions of the same opaque type with the hidden type,
+                    // as the bounds must hold on the hidden type after all.
+                    ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => {
+                        ty_var
+                    }
+                    // Instantiate nested instances of `impl Trait`.
+                    ty::Opaque(..) => self.instantiate_opaque_types_in_map(ty),
+                    _ => ty,
+                },
+                lt_op: |lt| lt,
+                ct_op: |ct| ct,
+            });
+
             // We can't normalize associated types from `rustc_infer`, but we can eagerly register inference variables for them.
             let predicate = predicate.fold_with(&mut BottomUpFolder {
                 tcx,
@@ -575,10 +589,6 @@ fn fold_opaque_ty(
                     return tcx.ty_error();
                 }
             }
-            // Change the predicate to refer to the type variable,
-            // which will be the concrete type instead of the opaque type.
-            // This also instantiates nested instances of `impl Trait`.
-            let predicate = self.instantiate_opaque_types_in_map(predicate);
 
             let cause =
                 traits::ObligationCause::new(self.value_span, self.body_id, traits::OpaqueType);
@@ -619,7 +629,7 @@ fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hi
     let scope = tcx.hir().get_defining_scope(opaque_hir_id);
     // We walk up the node tree until we hit the root or the scope of the opaque type.
     while hir_id != scope && hir_id != hir::CRATE_HIR_ID {
-        hir_id = tcx.hir().get_parent_item(hir_id);
+        hir_id = tcx.hir().local_def_id_to_hir_id(tcx.hir().get_parent_item(hir_id));
     }
     // Syntactically, we are allowed to define the concrete type if:
     let res = hir_id == scope;
index 22e18deac25e4e4a973ca11e41b9217c13f0b372..fbf149a4788e3fe76feba0bd00c878c58b8dcdcb 100644 (file)
@@ -196,7 +196,7 @@ fn compute_components_recursive<'tcx>(
     out: &mut SmallVec<[Component<'tcx>; 4]>,
     visited: &mut SsoHashSet<GenericArg<'tcx>>,
 ) {
-    for child in parent.walk_shallow(tcx, visited) {
+    for child in parent.walk_shallow(visited) {
         match child.unpack() {
             GenericArgKind::Type(ty) => {
                 compute_components(tcx, ty, out, visited);
index dba73251b4f0d44e9e8d68e3333c6f44181e38f5..f69212c599b6258dbb4964098c7a15749aea9e32 100644 (file)
@@ -189,7 +189,7 @@ fn recursive_bound(
         visited: &mut SsoHashSet<GenericArg<'tcx>>,
     ) -> VerifyBound<'tcx> {
         let mut bounds = parent
-            .walk_shallow(self.tcx, visited)
+            .walk_shallow(visited)
             .filter_map(|child| match child.unpack() {
                 GenericArgKind::Type(ty) => Some(self.type_bound(ty, visited)),
                 GenericArgKind::Lifetime(lt) => {
index f036e1214aaf7d97cee8453922d964a3cd78b7db..744599113849b2282cc6df446f889bd85093d19d 100644 (file)
@@ -126,11 +126,6 @@ pub fn new(infcx: &'a InferCtxt<'a, 'tcx>) -> Self {
 
 impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> {
     type BreakTy = (Ty<'tcx>, Option<Span>);
-
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.infcx.tcx)
-    }
-
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         let t = self.infcx.shallow_resolve(t);
         if t.has_infer_types() {
index 8f5d6c85097cb0d053716c3b681cb6d82569d59a..65443fd88d7339728c2115d6c599dca6ffa512ac 100644 (file)
@@ -152,7 +152,7 @@ fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
                         obligation.cause.clone(),
                     )
                 });
-                debug!("super_predicates: data={:?}", data);
+                debug!(?data, ?obligations, "super_predicates");
 
                 // Only keep those bounds that we haven't already seen.
                 // This is necessary to prevent infinite recursion in some
index f5823e521b9e67d6c9453287994ae5b1689e1dca..e31119c12921df6a02824c56420198905764d87c 100644 (file)
@@ -10,8 +10,8 @@ doctest = false
 libc = "0.2"
 libloading = "0.7.1"
 tracing = "0.1"
-rustc-rayon-core = "0.3.1"
-rayon = { version = "0.3.1", package = "rustc-rayon" }
+rustc-rayon-core = "0.3.2"
+rayon = { version = "0.3.2", package = "rustc-rayon" }
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr = { path = "../rustc_attr" }
index 2904b3f5b7071bd5f54ed664a200d1bb0b1ac353..3804e10030733309293866cc5383da930661a2d8 100644 (file)
@@ -11,7 +11,7 @@
 use rustc_errors::{ErrorReported, Handler};
 use rustc_lint::LintStore;
 use rustc_middle::ty;
-use rustc_parse::new_parser_from_source_str;
+use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_query_impl::QueryCtxt;
 use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
 use rustc_session::early_error;
@@ -91,7 +91,6 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
                     s
                 )));
                 let filename = FileName::cfg_spec_source_code(&s);
-                let mut parser = new_parser_from_source_str(&sess, filename, s.to_string());
 
                 macro_rules! error {
                     ($reason: expr) => {
@@ -102,26 +101,27 @@ macro_rules! error {
                     };
                 }
 
-                match &mut parser.parse_meta_item() {
-                    Ok(meta_item) if parser.token == token::Eof => {
-                        if meta_item.path.segments.len() != 1 {
-                            error!("argument key must be an identifier");
-                        }
-                        match &meta_item.kind {
-                            MetaItemKind::List(..) => {
-                                error!(r#"expected `key` or `key="value"`"#);
-                            }
-                            MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
-                                error!("argument value must be a string");
+                match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
+                    Ok(mut parser) => match &mut parser.parse_meta_item() {
+                        Ok(meta_item) if parser.token == token::Eof => {
+                            if meta_item.path.segments.len() != 1 {
+                                error!("argument key must be an identifier");
                             }
-                            MetaItemKind::NameValue(..) | MetaItemKind::Word => {
-                                let ident = meta_item.ident().expect("multi-segment cfg key");
-                                return (ident.name, meta_item.value_str());
+                            match &meta_item.kind {
+                                MetaItemKind::List(..) => {}
+                                MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
+                                    error!("argument value must be a string");
+                                }
+                                MetaItemKind::NameValue(..) | MetaItemKind::Word => {
+                                    let ident = meta_item.ident().expect("multi-segment cfg key");
+                                    return (ident.name, meta_item.value_str());
+                                }
                             }
                         }
-                    }
-                    Ok(..) => {}
-                    Err(err) => err.cancel(),
+                        Ok(..) => {}
+                        Err(err) => err.cancel(),
+                    },
+                    Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()),
                 }
 
                 error!(r#"expected `key` or `key="value"`"#);
index d11cc52b50860fd7e222fc4c99350afd110e250b..33bf670f570f897631d6320468bf1a4eebb61d79 100644 (file)
@@ -3,7 +3,7 @@
 use crate::util;
 
 use rustc_ast::mut_visit::MutVisitor;
-use rustc_ast::{self as ast, visit};
+use rustc_ast::{self as ast, visit, DUMMY_NODE_ID};
 use rustc_borrowck as mir_borrowck;
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_ssa::traits::CodegenBackend;
@@ -323,7 +323,7 @@ pub fn configure_and_expand(
 
         let crate_attrs = krate.attrs.clone();
         let extern_mod_loaded = |ident: Ident, attrs, items, span| {
-            let krate = ast::Crate { attrs, items, span, is_placeholder: None };
+            let krate = ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false };
             pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, ident.name.as_str());
             (krate.attrs, krate.items)
         };
index 4a181ce544de0204ee490912eb165bb3802a540b..816e770f01252ed97e1b5f4aa0ec81839d1ee8af 100644 (file)
@@ -594,6 +594,7 @@ macro_rules! tracked {
     tracked!(relocation_model, Some(RelocModel::Pic));
     tracked!(soft_float, true);
     tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
+    tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
     tracked!(target_cpu, Some(String::from("abc")));
     tracked!(target_feature, String::from("all the features, all of them"));
 }
index c0384875a47c9b917450f4bafb6d36b07ceabffd..0da37cc1be5a6471b7e9783dfd4f5431431ddfa9 100644 (file)
@@ -152,8 +152,8 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
 declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
 
 impl BoxPointers {
-    fn check_heap_type<'tcx>(&self, cx: &LateContext<'tcx>, span: Span, ty: Ty<'tcx>) {
-        for leaf in ty.walk(cx.tcx) {
+    fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
+        for leaf in ty.walk() {
             if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
                 if leaf_ty.is_box() {
                     cx.struct_span_lint(BOX_POINTERS, span, |lint| {
@@ -610,8 +610,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
                 // reported for missing docs.
                 let real_trait = trait_ref.path.res.def_id();
                 let Some(def_id) = real_trait.as_local() else { return };
-                let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
-                let Some(Node::Item(item)) = cx.tcx.hir().find(hir_id) else { return };
+                let Some(Node::Item(item)) = cx.tcx.hir().find_by_def_id(def_id) else { return };
                 if let hir::VisibilityKind::Inherited = item.vis.node {
                     for impl_item_ref in items {
                         self.private_traits.insert(impl_item_ref.id.hir_id());
@@ -656,7 +655,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
 
         // If the method is an impl for an item with docs_hidden, don't doc.
         if method_context(cx, impl_item.hir_id()) == MethodLateContext::PlainImpl {
-            let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
+            let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
             let impl_ty = cx.tcx.type_of(parent);
             let outerdef = match impl_ty.kind() {
                 ty::Adt(def, _) => Some(def.did),
@@ -1212,7 +1211,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
                             check_no_mangle_on_generic_fn(
                                 no_mangle_attr,
                                 Some(generics),
-                                cx.tcx.hir().get_generics(it.id.def_id.to_def_id()).unwrap(),
+                                cx.tcx.hir().get_generics(it.id.def_id).unwrap(),
                                 it.span,
                             );
                         }
@@ -1663,7 +1662,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
                     ConstEquate(..) |
                     TypeWellFormedFromEnv(..) => continue,
                 };
-                if predicate.is_global(cx.tcx) {
+                if predicate.is_global() {
                     cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
                         lint.build(&format!(
                             "{} bound {} does not depend on any type \
index 65772d02376d43ae082a6e4b11933604c5649fb3..c5e15a88fdf1c302a48d75dfc5795f9311613314 100644 (file)
@@ -38,7 +38,7 @@
 /// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where
 /// the type is generic, we can't be certain if it will be an enum so we have to assume that it is.
 fn is_non_enum(t: Ty<'_>) -> bool {
-    !t.is_enum() && !t.potentially_needs_subst()
+    !t.is_enum() && !t.needs_subst()
 }
 
 fn enforce_mem_discriminant(
index c7823032b0c23530d1edbe239e3f549abaed8d5e..c6145ae0d510b366b07f702aa11daae4438b7390 100644 (file)
@@ -92,7 +92,8 @@
 
 /// Useful for other parts of the compiler / Clippy.
 pub use builtin::SoftLints;
-pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore};
+pub use context::{CheckLintNameResult, FindLintError, LintStore};
+pub use context::{EarlyContext, LateContext, LintContext};
 pub use early::check_ast_crate;
 pub use late::check_crate;
 pub use passes::{EarlyLintPass, LateLintPass};
index 600504f7c1280973c018386ecc2afacba0fb2fbc..4bcd4c6d6038d72e961f62413b3d12872d06f88c 100644 (file)
@@ -62,7 +62,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             _ => return,
         };
         let substs = cx.typeck_results().node_substs(expr.hir_id);
-        if substs.definitely_needs_subst(cx.tcx) {
+        if substs.needs_subst() {
             // We can't resolve on types that require monomorphization, so we don't handle them if
             // we need to perfom substitution.
             return;
index 32ed6dad7f8c349b5f411924759610e540b26a6c..1acff13d1aa33f7fc317d3f9a15c1049d3ef8de3 100644 (file)
@@ -1175,9 +1175,6 @@ struct ProhibitOpaqueTypes<'a, 'tcx> {
 
         impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
             type BreakTy = Ty<'tcx>;
-            fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-                Some(self.cx.tcx)
-            }
 
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 match ty.kind() {
index 27a06943cbc25b2f6b300866cc99ef3add07c3b2..c2f6118227a4aec07d316381e1607edd127dde95 100644 (file)
     ///
     /// ### Example
     ///
-    /// ```
+    /// ```rust
     /// if let _ = 123 {
     ///     println!("always runs!");
     /// }
     /// }
     /// ```
     ///
-    /// {{produces}}
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: formatting may not be suitable for sub-register argument
+    ///  --> src/main.rs:7:19
+    ///   |
+    /// 7 |         asm!("mov {0}, {0}", in(reg) 0i16);
+    ///   |                   ^^^  ^^^           ---- for this argument
+    ///   |
+    ///   = note: `#[warn(asm_sub_register)]` on by default
+    ///   = help: use the `x` modifier to have the register formatted as `ax`
+    ///   = help: or use the `r` modifier to keep the default formatting of `rax`
+    /// ```
     ///
     /// ### Explanation
     ///
     /// }
     /// ```
     ///
-    /// {{produces}}
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
+    ///  --> src/main.rs:8:14
+    ///   |
+    /// 8 |             ".att_syntax",
+    ///   |              ^^^^^^^^^^^
+    ///   |
+    ///   = note: `#[warn(bad_asm_style)]` on by default
+    /// ```
     ///
     /// ### Explanation
     ///
     ///
     /// ### Example
     ///
-    /// ```compile_fail
+    /// ```rust,compile_fail
     /// #![feature(staged_api)]
     ///
     /// #[derive(Clone)]
     /// fn foo() {}
     /// ```
     ///
-    /// {{produces}}
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: duplicated attribute
+    ///  --> src/lib.rs:2:1
+    ///   |
+    /// 2 | #[test]
+    ///   | ^^^^^^^
+    ///   |
+    ///   = note: `#[warn(duplicate_macro_attributes)]` on by default
+    /// ```
     ///
     /// ### Explanation
     ///
index 025a0ee376e3e5e6f390ca00b2c23929446a0dbd..c21e4acbefec04541ccfbda0e1d28f8ab2a8af5c 100644 (file)
@@ -341,14 +341,12 @@ extern "C" void LLVMRustRemoveFunctionAttributes(LLVMValueRef Fn,
                                                  unsigned Index,
                                                  LLVMRustAttribute RustAttr) {
   Function *F = unwrap<Function>(Fn);
-  Attribute Attr = Attribute::get(F->getContext(), fromRust(RustAttr));
-  AttrBuilder B(Attr);
-  auto PAL = F->getAttributes();
+  AttributeList PAL = F->getAttributes();
   AttributeList PALNew;
 #if LLVM_VERSION_LT(14, 0)
-  PALNew = PAL.removeAttributes(F->getContext(), Index, B);
+  PALNew = PAL.removeAttribute(F->getContext(), Index, fromRust(RustAttr));
 #else
-  PALNew = PAL.removeAttributesAtIndex(F->getContext(), Index, B);
+  PALNew = PAL.removeAttributeAtIndex(F->getContext(), Index, fromRust(RustAttr));
 #endif
   F->setAttributes(PALNew);
 }
@@ -979,11 +977,11 @@ LLVMRustDIBuilderGetOrCreateArray(LLVMRustDIBuilderRef Builder,
 
 extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd(
     LLVMRustDIBuilderRef Builder, LLVMValueRef V, LLVMMetadataRef VarInfo,
-    int64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
+    uint64_t *AddrOps, unsigned AddrOpsCount, LLVMMetadataRef DL,
     LLVMBasicBlockRef InsertAtEnd) {
   return wrap(Builder->insertDeclare(
       unwrap(V), unwrap<DILocalVariable>(VarInfo),
-      Builder->createExpression(llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)),
+      Builder->createExpression(llvm::ArrayRef<uint64_t>(AddrOps, AddrOpsCount)),
       DebugLoc(cast<MDNode>(unwrap(DL))),
       unwrap(InsertAtEnd)));
 }
@@ -1057,11 +1055,11 @@ LLVMRustDIBuilderCreateDebugLocation(unsigned Line, unsigned Column,
   return wrap(Loc);
 }
 
-extern "C" int64_t LLVMRustDIBuilderCreateOpDeref() {
+extern "C" uint64_t LLVMRustDIBuilderCreateOpDeref() {
   return dwarf::DW_OP_deref;
 }
 
-extern "C" int64_t LLVMRustDIBuilderCreateOpPlusUconst() {
+extern "C" uint64_t LLVMRustDIBuilderCreateOpPlusUconst() {
   return dwarf::DW_OP_plus_uconst;
 }
 
diff --git a/compiler/rustc_log/Cargo.toml b/compiler/rustc_log/Cargo.toml
new file mode 100644 (file)
index 0000000..1b2cde6
--- /dev/null
@@ -0,0 +1,16 @@
+[package]
+name = "rustc_log"
+version = "0.0.0"
+edition = "2021"
+
+[dependencies]
+atty = "0.2"
+tracing = "0.1.28"
+tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
+tracing-tree = "0.2.0"
+
+[dev-dependencies]
+rustc_span = { path = "../rustc_span" }
+
+[features]
+max_level_info = ['tracing/max_level_info']
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
new file mode 100644 (file)
index 0000000..f5e7435
--- /dev/null
@@ -0,0 +1,115 @@
+//! This crate allows tools to enable rust logging without having to magically
+//! match rustc's tracing crate version.
+//!
+//! For example if someone is working on rustc_ast and wants to write some
+//! minimal code against it to run in a debugger, with access to the `debug!`
+//! logs emitted by rustc_ast, that can be done by writing:
+//!
+//! ```toml
+//! [dependencies]
+//! rustc_ast = { path = "../rust/compiler/rustc_ast" }
+//! rustc_log = { path = "../rust/compiler/rustc_log" }
+//! rustc_span = { path = "../rust/compiler/rustc_span" }
+//! ```
+//!
+//! ```
+//! fn main() {
+//!     rustc_log::init_rustc_env_logger().unwrap();
+//!
+//!     let edition = rustc_span::edition::Edition::Edition2021;
+//!     rustc_span::create_session_globals_then(edition, || {
+//!         /* ... */
+//!     });
+//! }
+//! ```
+//!
+//! Now `RUSTC_LOG=debug cargo run` will run your minimal main.rs and show
+//! rustc's debug logging. In a workflow like this, one might also add
+//! `std::env::set_var("RUSTC_LOG", "debug")` to the top of main so that `cargo
+//! run` by itself is sufficient to get logs.
+//!
+//! The reason rustc_log is a tiny separate crate, as opposed to exposing the
+//! same things in rustc_driver only, is to enable the above workflow. If you
+//! had to depend on rustc_driver in order to turn on rustc's debug logs, that's
+//! an enormously bigger dependency tree; every change you make to rustc_ast (or
+//! whichever piece of the compiler you are interested in) would involve
+//! rebuilding all the rest of rustc up to rustc_driver in order to run your
+//! main.rs. Whereas by depending only on rustc_log and the few crates you are
+//! debugging, you can make changes inside those crates and quickly run main.rs
+//! to read the debug logs.
+
+use std::env::{self, VarError};
+use std::fmt::{self, Display};
+use std::io;
+use tracing_subscriber::filter::{Directive, EnvFilter, LevelFilter};
+use tracing_subscriber::layer::SubscriberExt;
+
+pub fn init_rustc_env_logger() -> Result<(), Error> {
+    init_env_logger("RUSTC_LOG")
+}
+
+/// In contrast to `init_rustc_env_logger` this allows you to choose an env var
+/// other than `RUSTC_LOG`.
+pub fn init_env_logger(env: &str) -> Result<(), Error> {
+    let filter = match env::var(env) {
+        Ok(env) => EnvFilter::new(env),
+        _ => EnvFilter::default().add_directive(Directive::from(LevelFilter::WARN)),
+    };
+
+    let color_logs = match env::var(String::from(env) + "_COLOR") {
+        Ok(value) => match value.as_ref() {
+            "always" => true,
+            "never" => false,
+            "auto" => stderr_isatty(),
+            _ => return Err(Error::InvalidColorValue(value)),
+        },
+        Err(VarError::NotPresent) => stderr_isatty(),
+        Err(VarError::NotUnicode(_value)) => return Err(Error::NonUnicodeColorValue),
+    };
+
+    let layer = tracing_tree::HierarchicalLayer::default()
+        .with_writer(io::stderr)
+        .with_indent_lines(true)
+        .with_ansi(color_logs)
+        .with_targets(true)
+        .with_indent_amount(2);
+    #[cfg(parallel_compiler)]
+    let layer = layer.with_thread_ids(true).with_thread_names(true);
+
+    let subscriber = tracing_subscriber::Registry::default().with(filter).with(layer);
+    tracing::subscriber::set_global_default(subscriber).unwrap();
+
+    Ok(())
+}
+
+pub fn stdout_isatty() -> bool {
+    atty::is(atty::Stream::Stdout)
+}
+
+pub fn stderr_isatty() -> bool {
+    atty::is(atty::Stream::Stderr)
+}
+
+#[derive(Debug)]
+pub enum Error {
+    InvalidColorValue(String),
+    NonUnicodeColorValue,
+}
+
+impl std::error::Error for Error {}
+
+impl Display for Error {
+    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::InvalidColorValue(value) => write!(
+                formatter,
+                "invalid log color value '{}': expected one of always, never, or auto",
+                value,
+            ),
+            Error::NonUnicodeColorValue => write!(
+                formatter,
+                "non-Unicode log color value: expected one of always, never, or auto",
+            ),
+        }
+    }
+}
index 66e6b571beb2b84bbc1acf3961a372191259de75..3351564299ca521421e17a32143c69b91fa2776f 100644 (file)
@@ -1,6 +1,7 @@
 use proc_macro2::TokenStream;
-use quote::quote;
+use quote::{quote, quote_spanned};
 use syn::parse_quote;
+use syn::spanned::Spanned;
 
 pub fn type_decodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
     let decoder_ty = quote! { __D };
@@ -104,6 +105,8 @@ fn decode(
 }
 
 fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro2::TokenStream {
+    let field_span = field.ident.as_ref().map_or(field.ty.span(), |ident| ident.span());
+
     let decode_inner_method = if let syn::Type::Reference(_) = field.ty {
         quote! { ::rustc_middle::ty::codec::RefDecodable::decode }
     } else {
@@ -111,20 +114,21 @@ fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro
     };
     let (decode_method, opt_field_name) = if is_struct {
         let field_name = field.ident.as_ref().map_or_else(|| index.to_string(), |i| i.to_string());
-        (
-            proc_macro2::Ident::new("read_struct_field", proc_macro2::Span::call_site()),
-            quote! { #field_name, },
-        )
+        (proc_macro2::Ident::new("read_struct_field", field_span), quote! { #field_name, })
     } else {
-        (
-            proc_macro2::Ident::new("read_enum_variant_arg", proc_macro2::Span::call_site()),
-            quote! {},
-        )
+        (proc_macro2::Ident::new("read_enum_variant_arg", field_span), quote! {})
+    };
+
+    let __decoder = quote! { __decoder };
+    // Use the span of the field for the method call, so
+    // that backtraces will point to the field.
+    let decode_call = quote_spanned! {field_span=>
+        ::rustc_serialize::Decoder::#decode_method(
+                #__decoder, #opt_field_name #decode_inner_method)
     };
 
     quote! {
-        match ::rustc_serialize::Decoder::#decode_method(
-            __decoder, #opt_field_name #decode_inner_method) {
+        match #decode_call  {
             ::std::result::Result::Ok(__res) => __res,
             ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err),
         }
index 1069c24405842a949d3be09a17f901a6d5aa8109..85c0d28d5ea1180e4e5e00b27e64e1a09e589972 100644 (file)
 use rustc_hir::diagnostic_items::DiagnosticItems;
 use rustc_hir::lang_items;
 use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::mir::{self, Body, Promoted};
 use rustc_middle::thir;
 use rustc_middle::ty::codec::TyDecoder;
+use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, Ty, TyCtxt, Visibility};
 use rustc_serialize::{opaque, Decodable, Decoder};
 use rustc_session::cstore::{
@@ -92,8 +93,7 @@ fn deref(&self) -> &[u8] {
     /// Trait impl data.
     /// FIXME: Used only from queries and can use query cache,
     /// so pre-decoding can probably be avoided.
-    trait_impls:
-        FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<ty::fast_reject::SimplifiedType>)]>>,
+    trait_impls: FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option<SimplifiedType>)]>>,
     /// Proc macro descriptions for this crate, if it's a proc macro crate.
     raw_proc_macros: Option<&'static [ProcMacro]>,
     /// Source maps for code from the crate.
@@ -218,40 +218,40 @@ fn sess(self) -> Option<&'tcx Session> {
     }
 }
 
-impl<'a, 'tcx> Metadata<'a, 'tcx> for &'a CrateMetadataRef<'a> {
+impl<'a, 'tcx> Metadata<'a, 'tcx> for CrateMetadataRef<'a> {
     #[inline]
     fn blob(self) -> &'a MetadataBlob {
-        &self.blob
+        &self.cdata.blob
     }
     #[inline]
     fn cdata(self) -> Option<CrateMetadataRef<'a>> {
-        Some(*self)
+        Some(self)
     }
 }
 
-impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, &'tcx Session) {
+impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, &'tcx Session) {
     #[inline]
     fn blob(self) -> &'a MetadataBlob {
-        &self.0.blob
+        &self.0.cdata.blob
     }
     #[inline]
     fn cdata(self) -> Option<CrateMetadataRef<'a>> {
-        Some(*self.0)
+        Some(self.0)
     }
     #[inline]
     fn sess(self) -> Option<&'tcx Session> {
-        Some(&self.1)
+        Some(self.1)
     }
 }
 
-impl<'a, 'tcx> Metadata<'a, 'tcx> for (&'a CrateMetadataRef<'a>, TyCtxt<'tcx>) {
+impl<'a, 'tcx> Metadata<'a, 'tcx> for (CrateMetadataRef<'a>, TyCtxt<'tcx>) {
     #[inline]
     fn blob(self) -> &'a MetadataBlob {
-        &self.0.blob
+        &self.0.cdata.blob
     }
     #[inline]
     fn cdata(self) -> Option<CrateMetadataRef<'a>> {
-        Some(*self.0)
+        Some(self.0)
     }
     #[inline]
     fn tcx(self) -> Option<TyCtxt<'tcx>> {
@@ -304,18 +304,17 @@ fn read_lazy_with_meta<T: ?Sized + LazyMeta>(
         &mut self,
         meta: T::Meta,
     ) -> Result<Lazy<T>, <Self as Decoder>::Error> {
-        let min_size = T::min_size(meta);
         let distance = self.read_usize()?;
         let position = match self.lazy_state {
             LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"),
             LazyState::NodeStart(start) => {
                 let start = start.get();
-                assert!(distance + min_size <= start);
-                start - distance - min_size
+                assert!(distance <= start);
+                start - distance
             }
-            LazyState::Previous(last_min_end) => last_min_end.get() + distance,
+            LazyState::Previous(last_pos) => last_pos.get() + distance,
         };
-        self.lazy_state = LazyState::Previous(NonZeroUsize::new(position + min_size).unwrap());
+        self.lazy_state = LazyState::Previous(NonZeroUsize::new(position).unwrap());
         Ok(Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta))
     }
 
@@ -415,9 +414,9 @@ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<SyntaxContext, String
             Ok(cdata
                 .root
                 .syntax_contexts
-                .get(&cdata, id)
+                .get(cdata, id)
                 .unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname))
-                .decode((&cdata, sess)))
+                .decode((cdata, sess)))
         })
     }
 }
@@ -443,15 +442,15 @@ fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<ExpnId, String> {
             let expn_data = crate_data
                 .root
                 .expn_data
-                .get(&crate_data, index)
+                .get(crate_data, index)
                 .unwrap()
-                .decode((&crate_data, sess));
+                .decode((crate_data, sess));
             let expn_hash = crate_data
                 .root
                 .expn_hashes
-                .get(&crate_data, index)
+                .get(crate_data, index)
                 .unwrap()
-                .decode((&crate_data, sess));
+                .decode((crate_data, sess));
             (expn_data, expn_hash)
         });
         Ok(expn_id)
@@ -707,7 +706,7 @@ impl CrateRoot<'_> {
 }
 
 impl<'a, 'tcx> CrateMetadataRef<'a> {
-    fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
+    fn raw_proc_macro(self, id: DefIndex) -> &'a ProcMacro {
         // DefIndex's in root.proc_macro_data have a one-to-one correspondence
         // with items in 'raw_proc_macros'.
         let pos = self
@@ -722,32 +721,31 @@ fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
         &self.raw_proc_macros.unwrap()[pos]
     }
 
-    fn try_item_ident(&self, item_index: DefIndex, sess: &Session) -> Result<Ident, String> {
-        let name = self
-            .def_key(item_index)
-            .disambiguated_data
-            .data
-            .get_opt_name()
-            .ok_or_else(|| format!("Missing opt name for {:?}", item_index))?;
-        let span = self
-            .root
-            .tables
-            .ident_span
-            .get(self, item_index)
-            .ok_or_else(|| format!("Missing ident span for {:?} ({:?})", name, item_index))?
-            .decode((self, sess));
-        Ok(Ident::new(name, span))
+    fn opt_item_ident(self, item_index: DefIndex, sess: &Session) -> Option<Ident> {
+        let name = self.def_key(item_index).disambiguated_data.data.get_opt_name()?;
+        let span = match self.root.tables.ident_span.get(self, item_index) {
+            Some(lazy_span) => lazy_span.decode((self, sess)),
+            None => {
+                // FIXME: this weird case of a name with no span is specific to `extern crate`
+                // items, which are supposed to be treated like `use` items and only be encoded
+                // to metadata as `Export`s, return `None` because that's what all the callers
+                // expect in this case.
+                assert_eq!(self.def_kind(item_index), DefKind::ExternCrate);
+                return None;
+            }
+        };
+        Some(Ident::new(name, span))
     }
 
-    fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident {
-        self.try_item_ident(item_index, sess).unwrap()
+    fn item_ident(self, item_index: DefIndex, sess: &Session) -> Ident {
+        self.opt_item_ident(item_index, sess).expect("no encoded ident for item")
     }
 
-    fn maybe_kind(&self, item_id: DefIndex) -> Option<EntryKind> {
+    fn maybe_kind(self, item_id: DefIndex) -> Option<EntryKind> {
         self.root.tables.kind.get(self, item_id).map(|k| k.decode(self))
     }
 
-    fn kind(&self, item_id: DefIndex) -> EntryKind {
+    fn kind(self, item_id: DefIndex) -> EntryKind {
         self.maybe_kind(item_id).unwrap_or_else(|| {
             bug!(
                 "CrateMetadata::kind({:?}): id not found, in crate {:?} with number {}",
@@ -758,7 +756,7 @@ fn kind(&self, item_id: DefIndex) -> EntryKind {
         })
     }
 
-    fn def_kind(&self, item_id: DefIndex) -> DefKind {
+    fn def_kind(self, item_id: DefIndex) -> DefKind {
         self.root.tables.def_kind.get(self, item_id).map(|k| k.decode(self)).unwrap_or_else(|| {
             bug!(
                 "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}",
@@ -769,7 +767,7 @@ fn def_kind(&self, item_id: DefIndex) -> DefKind {
         })
     }
 
-    fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
+    fn get_span(self, index: DefIndex, sess: &Session) -> Span {
         self.root
             .tables
             .span
@@ -778,7 +776,7 @@ fn get_span(&self, index: DefIndex, sess: &Session) -> Span {
             .decode((self, sess))
     }
 
-    fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension {
+    fn load_proc_macro(self, id: DefIndex, sess: &Session) -> SyntaxExtension {
         let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) {
             ProcMacro::CustomDerive { trait_name, attributes, client } => {
                 let helper_attrs =
@@ -809,7 +807,7 @@ fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension {
         )
     }
 
-    fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
+    fn get_trait_def(self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
         match self.kind(item_id) {
             EntryKind::Trait(data) => {
                 let data = data.decode((self, sess));
@@ -839,7 +837,7 @@ fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
     }
 
     fn get_variant(
-        &self,
+        self,
         kind: &EntryKind,
         index: DefIndex,
         parent_did: DefId,
@@ -864,7 +862,7 @@ fn get_variant(
         let ctor_did = data.ctor.map(|index| self.local_def_id(index));
 
         ty::VariantDef::new(
-            self.item_ident(index, sess),
+            self.item_ident(index, sess).name,
             variant_did,
             ctor_did,
             data.discr,
@@ -876,7 +874,7 @@ fn get_variant(
                 .decode(self)
                 .map(|index| ty::FieldDef {
                     did: self.local_def_id(index),
-                    ident: self.item_ident(index, sess),
+                    name: self.item_ident(index, sess).name,
                     vis: self.get_visibility(index),
                 })
                 .collect(),
@@ -888,7 +886,7 @@ fn get_variant(
         )
     }
 
-    fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
+    fn get_adt_def(self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef {
         let kind = self.kind(item_id);
         let did = self.local_def_id(item_id);
 
@@ -916,7 +914,7 @@ fn get_adt_def(&self, item_id: DefIndex, tcx: TyCtxt<'tcx>) -> &'tcx ty::AdtDef
     }
 
     fn get_explicit_predicates(
-        &self,
+        self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> ty::GenericPredicates<'tcx> {
@@ -924,7 +922,7 @@ fn get_explicit_predicates(
     }
 
     fn get_inferred_outlives(
-        &self,
+        self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
@@ -937,7 +935,7 @@ fn get_inferred_outlives(
     }
 
     fn get_super_predicates(
-        &self,
+        self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> ty::GenericPredicates<'tcx> {
@@ -945,7 +943,7 @@ fn get_super_predicates(
     }
 
     fn get_explicit_item_bounds(
-        &self,
+        self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
@@ -957,11 +955,11 @@ fn get_explicit_item_bounds(
             .unwrap_or_default()
     }
 
-    fn get_generics(&self, item_id: DefIndex, sess: &Session) -> ty::Generics {
+    fn get_generics(self, item_id: DefIndex, sess: &Session) -> ty::Generics {
         self.root.tables.generics.get(self, item_id).unwrap().decode((self, sess))
     }
 
-    fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+    fn get_type(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         self.root
             .tables
             .ty
@@ -970,59 +968,63 @@ fn get_type(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
             .decode((self, tcx))
     }
 
-    fn get_stability(&self, id: DefIndex) -> Option<attr::Stability> {
+    fn get_stability(self, id: DefIndex) -> Option<attr::Stability> {
         self.root.tables.stability.get(self, id).map(|stab| stab.decode(self))
     }
 
-    fn get_const_stability(&self, id: DefIndex) -> Option<attr::ConstStability> {
+    fn get_const_stability(self, id: DefIndex) -> Option<attr::ConstStability> {
         self.root.tables.const_stability.get(self, id).map(|stab| stab.decode(self))
     }
 
-    fn get_deprecation(&self, id: DefIndex) -> Option<attr::Deprecation> {
+    fn get_deprecation(self, id: DefIndex) -> Option<attr::Deprecation> {
         self.root.tables.deprecation.get(self, id).map(|depr| depr.decode(self))
     }
 
-    fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
+    fn get_visibility(self, id: DefIndex) -> ty::Visibility {
         self.root.tables.visibility.get(self, id).unwrap().decode(self)
     }
 
-    fn get_impl_data(&self, id: DefIndex) -> ImplData {
+    fn get_impl_data(self, id: DefIndex) -> ImplData {
         match self.kind(id) {
             EntryKind::Impl(data) => data.decode(self),
             _ => bug!(),
         }
     }
 
-    fn get_parent_impl(&self, id: DefIndex) -> Option<DefId> {
+    fn get_parent_impl(self, id: DefIndex) -> Option<DefId> {
         self.get_impl_data(id).parent_impl
     }
 
-    fn get_impl_polarity(&self, id: DefIndex) -> ty::ImplPolarity {
+    fn get_impl_polarity(self, id: DefIndex) -> ty::ImplPolarity {
         self.get_impl_data(id).polarity
     }
 
-    fn get_impl_defaultness(&self, id: DefIndex) -> hir::Defaultness {
+    fn get_impl_defaultness(self, id: DefIndex) -> hir::Defaultness {
         self.get_impl_data(id).defaultness
     }
 
-    fn get_impl_constness(&self, id: DefIndex) -> hir::Constness {
+    fn get_impl_constness(self, id: DefIndex) -> hir::Constness {
         self.get_impl_data(id).constness
     }
 
-    fn get_coerce_unsized_info(&self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
+    fn get_trait_item_def_id(self, id: DefIndex) -> Option<DefId> {
+        self.root.tables.trait_item_def_id.get(self, id).map(|d| d.decode(self))
+    }
+
+    fn get_coerce_unsized_info(self, id: DefIndex) -> Option<ty::adjustment::CoerceUnsizedInfo> {
         self.get_impl_data(id).coerce_unsized_info
     }
 
-    fn get_impl_trait(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option<ty::TraitRef<'tcx>> {
+    fn get_impl_trait(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> Option<ty::TraitRef<'tcx>> {
         self.root.tables.impl_trait_ref.get(self, id).map(|tr| tr.decode((self, tcx)))
     }
 
-    fn get_expn_that_defined(&self, id: DefIndex, sess: &Session) -> ExpnId {
+    fn get_expn_that_defined(self, id: DefIndex, sess: &Session) -> ExpnId {
         self.root.tables.expn_that_defined.get(self, id).unwrap().decode((self, sess))
     }
 
     fn get_const_param_default(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         id: DefIndex,
     ) -> rustc_middle::ty::Const<'tcx> {
@@ -1030,14 +1032,14 @@ fn get_const_param_default(
     }
 
     /// Iterates over all the stability attributes in the given crate.
-    fn get_lib_features(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)] {
+    fn get_lib_features(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)] {
         // FIXME: For a proc macro crate, not sure whether we should return the "host"
         // features or an empty Vec. Both don't cause ICEs.
         tcx.arena.alloc_from_iter(self.root.lib_features.decode(self))
     }
 
     /// Iterates over the language items in the given crate.
-    fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
+    fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
         if self.root.is_proc_macro_crate() {
             // Proc macro crates do not export any lang-items to the target.
             &[]
@@ -1052,7 +1054,7 @@ fn get_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
     }
 
     /// Iterates over the diagnostic items in the given crate.
-    fn get_diagnostic_items(&self) -> DiagnosticItems {
+    fn get_diagnostic_items(self) -> DiagnosticItems {
         if self.root.is_proc_macro_crate() {
             // Proc macro crates do not export any diagnostic-items to the target.
             Default::default()
@@ -1072,60 +1074,54 @@ fn get_diagnostic_items(&self) -> DiagnosticItems {
         }
     }
 
-    /// Iterates over each child of the given item.
-    fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), sess: &Session) {
+    /// Iterates over all named children of the given module,
+    /// including both proper items and reexports.
+    /// Module here is understood in name resolution sense - it can be a `mod` item,
+    /// or a crate root, or an enum, or a trait.
+    fn for_each_module_child(
+        self,
+        id: DefIndex,
+        mut callback: impl FnMut(ModChild),
+        sess: &Session,
+    ) {
         if let Some(data) = &self.root.proc_macro_data {
-            /* If we are loading as a proc macro, we want to return the view of this crate
-             * as a proc macro crate.
-             */
+            // If we are loading as a proc macro, we want to return
+            // the view of this crate as a proc macro crate.
             if id == CRATE_DEF_INDEX {
-                let macros = data.macros.decode(self);
-                for def_index in macros {
+                for def_index in data.macros.decode(self) {
                     let raw_macro = self.raw_proc_macro(def_index);
                     let res = Res::Def(
                         DefKind::Macro(macro_kind(raw_macro)),
                         self.local_def_id(def_index),
                     );
                     let ident = self.item_ident(def_index, sess);
-                    callback(Export { ident, res, vis: ty::Visibility::Public, span: ident.span });
+                    callback(ModChild {
+                        ident,
+                        res,
+                        vis: ty::Visibility::Public,
+                        span: ident.span,
+                    });
                 }
             }
             return;
         }
 
-        // Find the item.
-        let kind = match self.maybe_kind(id) {
-            None => return,
-            Some(kind) => kind,
-        };
-
         // Iterate over all children.
-        let macros_only = self.dep_kind.lock().macros_only();
-        if !macros_only {
-            let children = self.root.tables.children.get(self, id).unwrap_or_else(Lazy::empty);
-
+        if let Some(children) = self.root.tables.children.get(self, id) {
             for child_index in children.decode((self, sess)) {
-                // FIXME: Merge with the logic below.
-                if let None | Some(EntryKind::ForeignMod | EntryKind::Impl(_)) =
-                    self.maybe_kind(child_index)
-                {
-                    continue;
-                }
-
-                let def_key = self.def_key(child_index);
-                if def_key.disambiguated_data.data.get_opt_name().is_some() {
-                    let span = self.get_span(child_index, sess);
+                if let Some(ident) = self.opt_item_ident(child_index, sess) {
                     let kind = self.def_kind(child_index);
-                    let ident = self.item_ident(child_index, sess);
-                    let vis = self.get_visibility(child_index);
+                    if matches!(kind, DefKind::Macro(..)) {
+                        // FIXME: Macros are currently encoded twice, once as items and once as
+                        // reexports. We ignore the items here and only use the reexports.
+                        continue;
+                    }
                     let def_id = self.local_def_id(child_index);
                     let res = Res::Def(kind, def_id);
+                    let vis = self.get_visibility(child_index);
+                    let span = self.get_span(child_index, sess);
 
-                    // FIXME: Macros are currently encoded twice, once as items and once as
-                    // reexports. We ignore the items here and only use the reexports.
-                    if !matches!(kind, DefKind::Macro(..)) {
-                        callback(Export { res, ident, vis, span });
-                    }
+                    callback(ModChild { ident, res, vis, span });
 
                     // For non-re-export structs and variants add their constructors to children.
                     // Re-export lists automatically contain constructors when necessary.
@@ -1137,7 +1133,7 @@ fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), ses
                                 let ctor_res =
                                     Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
                                 let vis = self.get_visibility(ctor_def_id.index);
-                                callback(Export { res: ctor_res, vis, ident, span });
+                                callback(ModChild { ident, res: ctor_res, vis, span });
                             }
                         }
                         DefKind::Variant => {
@@ -1162,7 +1158,7 @@ fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), ses
                                     vis = ty::Visibility::Restricted(crate_def_id);
                                 }
                             }
-                            callback(Export { res: ctor_res, ident, vis, span });
+                            callback(ModChild { ident, res: ctor_res, vis, span });
                         }
                         _ => {}
                     }
@@ -1170,27 +1166,26 @@ fn each_child_of_item(&self, id: DefIndex, mut callback: impl FnMut(Export), ses
             }
         }
 
-        if let EntryKind::Mod(exports) = kind {
-            for exp in exports.decode((self, sess)) {
-                match exp.res {
-                    Res::Def(DefKind::Macro(..), _) => {}
-                    _ if macros_only => continue,
-                    _ => {}
+        match self.kind(id) {
+            EntryKind::Mod(exports) => {
+                for exp in exports.decode((self, sess)) {
+                    callback(exp);
                 }
-                callback(exp);
             }
+            EntryKind::Enum(..) | EntryKind::Trait(..) => {}
+            _ => bug!("`for_each_module_child` is called on a non-module: {:?}", self.def_kind(id)),
         }
     }
 
-    fn is_ctfe_mir_available(&self, id: DefIndex) -> bool {
+    fn is_ctfe_mir_available(self, id: DefIndex) -> bool {
         self.root.tables.mir_for_ctfe.get(self, id).is_some()
     }
 
-    fn is_item_mir_available(&self, id: DefIndex) -> bool {
+    fn is_item_mir_available(self, id: DefIndex) -> bool {
         self.root.tables.mir.get(self, id).is_some()
     }
 
-    fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
+    fn module_expansion(self, id: DefIndex, sess: &Session) -> ExpnId {
         match self.kind(id) {
             EntryKind::Mod(_) | EntryKind::Enum(_) | EntryKind::Trait(_) => {
                 self.get_expn_that_defined(id, sess)
@@ -1199,7 +1194,7 @@ fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
         }
     }
 
-    fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
+    fn get_optimized_mir(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
         self.root
             .tables
             .mir
@@ -1210,7 +1205,7 @@ fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
             .decode((self, tcx))
     }
 
-    fn get_mir_for_ctfe(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
+    fn get_mir_for_ctfe(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
         self.root
             .tables
             .mir_for_ctfe
@@ -1222,7 +1217,7 @@ fn get_mir_for_ctfe(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
     }
 
     fn get_thir_abstract_const(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         id: DefIndex,
     ) -> Result<Option<&'tcx [thir::abstract_const::Node<'tcx>]>, ErrorReported> {
@@ -1233,7 +1228,7 @@ fn get_thir_abstract_const(
             .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx)))))
     }
 
-    fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u32> {
+    fn get_unused_generic_params(self, id: DefIndex) -> FiniteBitSet<u32> {
         self.root
             .tables
             .unused_generic_params
@@ -1242,7 +1237,7 @@ fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet<u32> {
             .unwrap_or_default()
     }
 
-    fn get_promoted_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec<Promoted, Body<'tcx>> {
+    fn get_promoted_mir(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec<Promoted, Body<'tcx>> {
         self.root
             .tables
             .promoted_mir
@@ -1253,7 +1248,7 @@ fn get_promoted_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> IndexVec<Promoted
             .decode((self, tcx))
     }
 
-    fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs {
+    fn mir_const_qualif(self, id: DefIndex) -> mir::ConstQualifs {
         match self.kind(id) {
             EntryKind::AnonConst(qualif, _)
             | EntryKind::Const(qualif, _)
@@ -1268,14 +1263,24 @@ fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs {
         }
     }
 
-    fn get_fn_has_self_parameter(&self, id: DefIndex) -> bool {
+    fn get_fn_has_self_parameter(self, id: DefIndex) -> bool {
         match self.kind(id) {
             EntryKind::AssocFn(data) => data.decode(self).has_self,
             _ => false,
         }
     }
 
-    fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem {
+    fn get_associated_item_def_ids(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] {
+        if let Some(children) = self.root.tables.children.get(self, id) {
+            tcx.arena.alloc_from_iter(
+                children.decode((self, tcx.sess)).map(|child_index| self.local_def_id(child_index)),
+            )
+        } else {
+            &[]
+        }
+    }
+
+    fn get_associated_item(self, id: DefIndex, sess: &Session) -> ty::AssocItem {
         let def_key = self.def_key(id);
         let parent = self.local_def_id(def_key.parent.unwrap());
         let ident = self.item_ident(id, sess);
@@ -1296,16 +1301,17 @@ fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem {
             vis: self.get_visibility(id),
             defaultness: container.defaultness(),
             def_id: self.local_def_id(id),
+            trait_item_def_id: self.get_trait_item_def_id(id),
             container: container.with_def_id(parent),
             fn_has_self_parameter: has_self,
         }
     }
 
-    fn get_item_variances(&'a self, id: DefIndex) -> impl Iterator<Item = ty::Variance> + 'a {
+    fn get_item_variances(self, id: DefIndex) -> impl Iterator<Item = ty::Variance> + 'a {
         self.root.tables.variances.get(self, id).unwrap_or_else(Lazy::empty).decode(self)
     }
 
-    fn get_ctor_def_id_and_kind(&self, node_id: DefIndex) -> Option<(DefId, CtorKind)> {
+    fn get_ctor_def_id_and_kind(self, node_id: DefIndex) -> Option<(DefId, CtorKind)> {
         match self.kind(node_id) {
             EntryKind::Struct(data, _) | EntryKind::Variant(data) => {
                 let vdata = data.decode(self);
@@ -1316,29 +1322,31 @@ fn get_ctor_def_id_and_kind(&self, node_id: DefIndex) -> Option<(DefId, CtorKind
     }
 
     fn get_item_attrs(
-        &'a self,
-        node_id: DefIndex,
+        self,
+        id: DefIndex,
         sess: &'a Session,
     ) -> impl Iterator<Item = ast::Attribute> + 'a {
-        // The attributes for a tuple struct/variant are attached to the definition, not the ctor;
-        // we assume that someone passing in a tuple struct ctor is actually wanting to
-        // look at the definition
-        let def_key = self.def_key(node_id);
-        let item_id = if def_key.disambiguated_data.data == DefPathData::Ctor {
-            def_key.parent.unwrap()
-        } else {
-            node_id
-        };
-
         self.root
             .tables
             .attributes
-            .get(self, item_id)
-            .unwrap_or_else(Lazy::empty)
+            .get(self, id)
+            .unwrap_or_else(|| {
+                // Structure and variant constructors don't have any attributes encoded for them,
+                // but we assume that someone passing a constructor ID actually wants to look at
+                // the attributes on the corresponding struct or variant.
+                let def_key = self.def_key(id);
+                assert_eq!(def_key.disambiguated_data.data, DefPathData::Ctor);
+                let parent_id = def_key.parent.expect("no parent for a constructor");
+                self.root
+                    .tables
+                    .attributes
+                    .get(self, parent_id)
+                    .expect("no encoded attributes for a structure or variant")
+            })
             .decode((self, sess))
     }
 
-    fn get_struct_field_names(&self, id: DefIndex, sess: &Session) -> Vec<Spanned<Symbol>> {
+    fn get_struct_field_names(self, id: DefIndex, sess: &Session) -> Vec<Spanned<Symbol>> {
         self.root
             .tables
             .children
@@ -1349,7 +1357,7 @@ fn get_struct_field_names(&self, id: DefIndex, sess: &Session) -> Vec<Spanned<Sy
             .collect()
     }
 
-    fn get_struct_field_visibilities(&self, id: DefIndex) -> Vec<Visibility> {
+    fn get_struct_field_visibilities(self, id: DefIndex) -> Vec<Visibility> {
         self.root
             .tables
             .children
@@ -1361,7 +1369,7 @@ fn get_struct_field_visibilities(&self, id: DefIndex) -> Vec<Visibility> {
     }
 
     fn get_inherent_implementations_for_type(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         id: DefIndex,
     ) -> &'tcx [DefId] {
@@ -1376,47 +1384,47 @@ fn get_inherent_implementations_for_type(
         )
     }
 
-    fn get_traits(&'a self) -> impl Iterator<Item = DefId> + 'a {
-        self.root.traits.decode(self).map(|index| self.local_def_id(index))
+    fn get_traits(self) -> impl Iterator<Item = DefId> + 'a {
+        self.root.traits.decode(self).map(move |index| self.local_def_id(index))
     }
 
-    fn get_implementations_for_trait(
-        &self,
+    fn get_trait_impls(self) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + 'a {
+        self.cdata.trait_impls.values().flat_map(move |impls| {
+            impls
+                .decode(self)
+                .map(move |(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
+        })
+    }
+
+    fn get_implementations_of_trait(
+        self,
         tcx: TyCtxt<'tcx>,
-        filter: Option<DefId>,
-    ) -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
+        trait_def_id: DefId,
+    ) -> &'tcx [(DefId, Option<SimplifiedType>)] {
         if self.root.is_proc_macro_crate() {
             // proc-macro crates export no trait impls.
             return &[];
         }
 
-        if let Some(def_id) = filter {
-            // Do a reverse lookup beforehand to avoid touching the crate_num
-            // hash map in the loop below.
-            let filter = match self.reverse_translate_def_id(def_id) {
-                Some(def_id) => (def_id.krate.as_u32(), def_id.index),
-                None => return &[],
-            };
+        // Do a reverse lookup beforehand to avoid touching the crate_num
+        // hash map in the loop below.
+        let key = match self.reverse_translate_def_id(trait_def_id) {
+            Some(def_id) => (def_id.krate.as_u32(), def_id.index),
+            None => return &[],
+        };
 
-            if let Some(impls) = self.trait_impls.get(&filter) {
-                tcx.arena.alloc_from_iter(
-                    impls.decode(self).map(|(idx, simplified_self_ty)| {
-                        (self.local_def_id(idx), simplified_self_ty)
-                    }),
-                )
-            } else {
-                &[]
-            }
-        } else {
-            tcx.arena.alloc_from_iter(self.trait_impls.values().flat_map(|impls| {
+        if let Some(impls) = self.trait_impls.get(&key) {
+            tcx.arena.alloc_from_iter(
                 impls
                     .decode(self)
-                    .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
-            }))
+                    .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)),
+            )
+        } else {
+            &[]
         }
     }
 
-    fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
+    fn get_trait_of_item(self, id: DefIndex) -> Option<DefId> {
         let def_key = self.def_key(id);
         match def_key.disambiguated_data.data {
             DefPathData::TypeNs(..) | DefPathData::ValueNs(..) => (),
@@ -1429,7 +1437,7 @@ fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
         })
     }
 
-    fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLib> {
+    fn get_native_libraries(self, sess: &Session) -> Vec<NativeLib> {
         if self.root.is_proc_macro_crate() {
             // Proc macro crates do not have any *target* native libraries.
             vec![]
@@ -1438,7 +1446,7 @@ fn get_native_libraries(&self, sess: &Session) -> Vec<NativeLib> {
         }
     }
 
-    fn get_proc_macro_quoted_span(&self, index: usize, sess: &Session) -> Span {
+    fn get_proc_macro_quoted_span(self, index: usize, sess: &Session) -> Span {
         self.root
             .tables
             .proc_macro_quoted_spans
@@ -1447,7 +1455,7 @@ fn get_proc_macro_quoted_span(&self, index: usize, sess: &Session) -> Span {
             .decode((self, sess))
     }
 
-    fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> Lrc<FxHashMap<DefId, ForeignModule>> {
+    fn get_foreign_modules(self, tcx: TyCtxt<'tcx>) -> Lrc<FxHashMap<DefId, ForeignModule>> {
         if self.root.is_proc_macro_crate() {
             // Proc macro crates do not have any *target* foreign modules.
             Lrc::new(FxHashMap::default())
@@ -1459,7 +1467,7 @@ fn get_foreign_modules(&self, tcx: TyCtxt<'tcx>) -> Lrc<FxHashMap<DefId, Foreign
     }
 
     fn get_dylib_dependency_formats(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
     ) -> &'tcx [(CrateNum, LinkagePreference)] {
         tcx.arena.alloc_from_iter(
@@ -1470,7 +1478,7 @@ fn get_dylib_dependency_formats(
         )
     }
 
-    fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
+    fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
         if self.root.is_proc_macro_crate() {
             // Proc macro crates do not depend on any target weak lang-items.
             &[]
@@ -1479,7 +1487,7 @@ fn get_missing_lang_items(&self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangIt
         }
     }
 
-    fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] {
+    fn get_fn_param_names(self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] {
         let param_names = match self.kind(id) {
             EntryKind::Fn(data) | EntryKind::ForeignFn(data) => data.decode(self).param_names,
             EntryKind::AssocFn(data) => data.decode(self).fn_data.param_names,
@@ -1489,7 +1497,7 @@ fn get_fn_param_names(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [Ident] {
     }
 
     fn exported_symbols(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
     ) -> &'tcx [(ExportedSymbol<'tcx>, SymbolExportLevel)] {
         if self.root.is_proc_macro_crate() {
@@ -1501,7 +1509,7 @@ fn exported_symbols(
         }
     }
 
-    fn get_rendered_const(&self, id: DefIndex) -> String {
+    fn get_rendered_const(self, id: DefIndex) -> String {
         match self.kind(id) {
             EntryKind::AnonConst(_, data)
             | EntryKind::Const(_, data)
@@ -1510,7 +1518,7 @@ fn get_rendered_const(&self, id: DefIndex) -> String {
         }
     }
 
-    fn get_macro(&self, id: DefIndex, sess: &Session) -> MacroDef {
+    fn get_macro(self, id: DefIndex, sess: &Session) -> MacroDef {
         match self.kind(id) {
             EntryKind::MacroDef(macro_def) => macro_def.decode((self, sess)),
             _ => bug!(),
@@ -1519,7 +1527,7 @@ fn get_macro(&self, id: DefIndex, sess: &Session) -> MacroDef {
 
     // This replicates some of the logic of the crate-local `is_const_fn_raw` query, because we
     // don't serialize constness for tuple variant and tuple struct constructors.
-    fn is_const_fn_raw(&self, id: DefIndex) -> bool {
+    fn is_const_fn_raw(self, id: DefIndex) -> bool {
         let constness = match self.kind(id) {
             EntryKind::AssocFn(data) => data.decode(self).fn_data.constness,
             EntryKind::Fn(data) => data.decode(self).constness,
@@ -1530,7 +1538,7 @@ fn is_const_fn_raw(&self, id: DefIndex) -> bool {
         constness == hir::Constness::Const
     }
 
-    fn asyncness(&self, id: DefIndex) -> hir::IsAsync {
+    fn asyncness(self, id: DefIndex) -> hir::IsAsync {
         match self.kind(id) {
             EntryKind::Fn(data) => data.decode(self).asyncness,
             EntryKind::AssocFn(data) => data.decode(self).fn_data.asyncness,
@@ -1539,7 +1547,7 @@ fn asyncness(&self, id: DefIndex) -> hir::IsAsync {
         }
     }
 
-    fn is_foreign_item(&self, id: DefIndex) -> bool {
+    fn is_foreign_item(self, id: DefIndex) -> bool {
         match self.kind(id) {
             EntryKind::ForeignImmStatic | EntryKind::ForeignMutStatic | EntryKind::ForeignFn(_) => {
                 true
@@ -1548,7 +1556,7 @@ fn is_foreign_item(&self, id: DefIndex) -> bool {
         }
     }
 
-    fn static_mutability(&self, id: DefIndex) -> Option<hir::Mutability> {
+    fn static_mutability(self, id: DefIndex) -> Option<hir::Mutability> {
         match self.kind(id) {
             EntryKind::ImmStatic | EntryKind::ForeignImmStatic => Some(hir::Mutability::Not),
             EntryKind::MutStatic | EntryKind::ForeignMutStatic => Some(hir::Mutability::Mut),
@@ -1556,19 +1564,19 @@ fn static_mutability(&self, id: DefIndex) -> Option<hir::Mutability> {
         }
     }
 
-    fn generator_kind(&self, id: DefIndex) -> Option<hir::GeneratorKind> {
+    fn generator_kind(self, id: DefIndex) -> Option<hir::GeneratorKind> {
         match self.kind(id) {
             EntryKind::Generator(data) => Some(data),
             _ => None,
         }
     }
 
-    fn fn_sig(&self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
+    fn fn_sig(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> ty::PolyFnSig<'tcx> {
         self.root.tables.fn_sig.get(self, id).unwrap().decode((self, tcx))
     }
 
     #[inline]
-    fn def_key(&self, index: DefIndex) -> DefKey {
+    fn def_key(self, index: DefIndex) -> DefKey {
         *self
             .def_key_cache
             .lock()
@@ -1577,13 +1585,13 @@ fn def_key(&self, index: DefIndex) -> DefKey {
     }
 
     // Returns the path leading to the thing with this `id`.
-    fn def_path(&self, id: DefIndex) -> DefPath {
+    fn def_path(self, id: DefIndex) -> DefPath {
         debug!("def_path(cnum={:?}, id={:?})", self.cnum, id);
         DefPath::make(self.cnum, id, |parent| self.def_key(parent))
     }
 
     fn def_path_hash_unlocked(
-        &self,
+        self,
         index: DefIndex,
         def_path_hashes: &mut FxHashMap<DefIndex, DefPathHash>,
     ) -> DefPathHash {
@@ -1593,17 +1601,17 @@ fn def_path_hash_unlocked(
     }
 
     #[inline]
-    fn def_path_hash(&self, index: DefIndex) -> DefPathHash {
+    fn def_path_hash(self, index: DefIndex) -> DefPathHash {
         let mut def_path_hashes = self.def_path_hash_cache.lock();
         self.def_path_hash_unlocked(index, &mut def_path_hashes)
     }
 
     #[inline]
-    fn def_path_hash_to_def_index(&self, hash: DefPathHash) -> DefIndex {
+    fn def_path_hash_to_def_index(self, hash: DefPathHash) -> DefIndex {
         self.def_path_hash_map.def_path_hash_to_def_index(&hash)
     }
 
-    fn expn_hash_to_expn_id(&self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId {
+    fn expn_hash_to_expn_id(self, sess: &Session, index_guess: u32, hash: ExpnHash) -> ExpnId {
         debug_assert_eq!(ExpnId::from_hash(hash), None);
         let index_guess = ExpnIndex::from_u32(index_guess);
         let old_hash = self.root.expn_hashes.get(self, index_guess).map(|lazy| lazy.decode(self));
@@ -1661,7 +1669,7 @@ fn expn_hash_to_expn_id(&self, sess: &Session, index_guess: u32, hash: ExpnHash)
     ///
     /// Proc macro crates don't currently export spans, so this function does not have
     /// to work for them.
-    fn imported_source_files(&self, sess: &Session) -> &'a [ImportedSourceFile] {
+    fn imported_source_files(self, sess: &Session) -> &'a [ImportedSourceFile] {
         // Translate the virtual `/rustc/$hash` prefix back to a real directory
         // that should hold actual sources, where possible.
         //
index 7ffc586fda3a5e88c4064d0dbbdc83181415dc07..a639772fde70990f0150c60f4459d4e60cf88ea7 100644 (file)
@@ -4,12 +4,13 @@
 
 use rustc_ast as ast;
 use rustc_data_structures::stable_map::FxHashMap;
-use rustc_hir::def::{CtorKind, DefKind};
+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};
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
 use rustc_middle::middle::stability::DeprecationEntry;
+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};
@@ -103,12 +104,7 @@ fn into_args(self) -> (DefId, DefId) {
         tcx.calculate_dtor(def_id, |_,_| Ok(()))
     }
     variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) }
-    associated_item_def_ids => {
-        let mut result = SmallVec::<[_; 8]>::new();
-        cdata.each_child_of_item(def_id.index,
-          |child| result.push(child.res.def_id()), tcx.sess);
-        tcx.arena.alloc_slice(&result)
-    }
+    associated_item_def_ids => { cdata.get_associated_item_def_ids(tcx, def_id.index) }
     associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) }
     impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
     impl_polarity => { cdata.get_impl_polarity(def_id.index) }
@@ -133,9 +129,7 @@ fn into_args(self) -> (DefId, DefId) {
     generator_kind => { cdata.generator_kind(def_id.index) }
     opt_def_kind => { Some(cdata.def_kind(def_id.index)) }
     def_span => { cdata.get_span(def_id.index, &tcx.sess) }
-    def_ident_span => {
-        cdata.try_item_ident(def_id.index, &tcx.sess).ok().map(|ident| ident.span)
-    }
+    def_ident_span => { cdata.opt_item_ident(def_id.index, &tcx.sess).map(|ident| ident.span) }
     lookup_stability => {
         cdata.get_stability(def_id.index).map(|s| tcx.intern_stability(s))
     }
@@ -145,9 +139,7 @@ fn into_args(self) -> (DefId, DefId) {
     lookup_deprecation_entry => {
         cdata.get_deprecation(def_id.index).map(DeprecationEntry::external)
     }
-    item_attrs => { tcx.arena.alloc_from_iter(
-        cdata.get_item_attrs(def_id.index, tcx.sess)
-    ) }
+    item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
     fn_arg_names => { cdata.get_fn_param_names(tcx, def_id.index) }
     rendered_const => { cdata.get_rendered_const(def_id.index) }
     impl_parent => { cdata.get_parent_impl(def_id.index) }
@@ -196,23 +188,16 @@ fn into_args(self) -> (DefId, DefId) {
     extra_filename => { cdata.root.extra_filename.clone() }
 
     traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
-
-    implementations_of_trait => {
-        cdata.get_implementations_for_trait(tcx, Some(other))
-    }
-
-    all_trait_implementations => {
-        cdata.get_implementations_for_trait(tcx, None)
-    }
+    implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
 
     visibility => { cdata.get_visibility(def_id.index) }
     dep_kind => {
         let r = *cdata.dep_kind.lock();
         r
     }
-    item_children => {
+    module_children => {
         let mut result = SmallVec::<[_; 8]>::new();
-        cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess);
+        cdata.for_each_module_child(def_id.index, |child| result.push(child), tcx.sess);
         tcx.arena.alloc_slice(&result)
     }
     defined_lib_features => { cdata.get_lib_features(tcx) }
@@ -323,35 +308,40 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                 bfs_queue.push_back(DefId { krate: cnum, index: CRATE_DEF_INDEX });
             }
 
-            let mut add_child = |bfs_queue: &mut VecDeque<_>, export: &Export, parent: DefId| {
-                if !export.vis.is_public() {
+            let mut add_child = |bfs_queue: &mut VecDeque<_>, child: &ModChild, parent: DefId| {
+                if !child.vis.is_public() {
                     return;
                 }
 
-                if let Some(child) = export.res.opt_def_id() {
-                    if export.ident.name == kw::Underscore {
-                        fallback_map.insert(child, parent);
+                if let Some(def_id) = child.res.opt_def_id() {
+                    if child.ident.name == kw::Underscore {
+                        fallback_map.insert(def_id, parent);
                         return;
                     }
 
-                    match visible_parent_map.entry(child) {
+                    match visible_parent_map.entry(def_id) {
                         Entry::Occupied(mut entry) => {
                             // If `child` is defined in crate `cnum`, ensure
                             // that it is mapped to a parent in `cnum`.
-                            if child.is_local() && entry.get().is_local() {
+                            if def_id.is_local() && entry.get().is_local() {
                                 entry.insert(parent);
                             }
                         }
                         Entry::Vacant(entry) => {
                             entry.insert(parent);
-                            bfs_queue.push_back(child);
+                            if matches!(
+                                child.res,
+                                Res::Def(DefKind::Mod | DefKind::Enum | DefKind::Trait, _)
+                            ) {
+                                bfs_queue.push_back(def_id);
+                            }
                         }
                     }
                 }
             };
 
             while let Some(def) = bfs_queue.pop_front() {
-                for child in tcx.item_children(def).iter() {
+                for child in tcx.module_children(def).iter() {
                     add_child(bfs_queue, child, def);
                 }
             }
@@ -362,7 +352,7 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
                 visible_parent_map.entry(child).or_insert(parent);
             }
 
-            visible_parent_map
+            Lrc::new(visible_parent_map)
         },
 
         dependency_formats: |tcx, ()| Lrc::new(crate::dependency_format::calculate(tcx)),
@@ -397,9 +387,9 @@ pub fn visibility_untracked(&self, def: DefId) -> Visibility {
         self.get_crate_data(def.krate).get_visibility(def.index)
     }
 
-    pub fn item_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<Export> {
+    pub fn module_children_untracked(&self, def_id: DefId, sess: &Session) -> Vec<ModChild> {
         let mut result = vec![];
-        self.get_crate_data(def_id.krate).each_child_of_item(
+        self.get_crate_data(def_id.krate).for_each_module_child(
             def_id.index,
             |child| result.push(child),
             sess,
@@ -470,7 +460,7 @@ pub fn num_def_ids_untracked(&self, cnum: CrateNum) -> usize {
         self.get_crate_data(cnum).num_def_ids()
     }
 
-    pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
+    pub fn item_attrs_untracked(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> {
         self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect()
     }
 
@@ -482,6 +472,17 @@ pub fn get_proc_macro_quoted_span_untracked(
     ) -> Span {
         self.get_crate_data(cnum).get_proc_macro_quoted_span(id, sess)
     }
+
+    pub fn traits_in_crate_untracked(&self, cnum: CrateNum) -> Vec<DefId> {
+        self.get_crate_data(cnum).get_traits().collect()
+    }
+
+    pub fn trait_impls_in_crate_untracked(
+        &self,
+        cnum: CrateNum,
+    ) -> Vec<(DefId, Option<SimplifiedType>)> {
+        self.get_crate_data(cnum).get_trait_impls().collect()
+    }
 }
 
 impl CrateStore for CStore {
index e2aaa88f548f1156fd3f61d098317d79c1ac7b25..fb5bd316319036f1d17750f5eb07f8d6ec57780c 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, SimplifyParams, StripReferences};
+use rustc_middle::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
 use rustc_serialize::{opaque, Encodable, Encoder};
@@ -404,24 +404,24 @@ fn emit_lazy_distance<T: ?Sized + LazyMeta>(
         &mut self,
         lazy: Lazy<T>,
     ) -> Result<(), <Self as Encoder>::Error> {
-        let min_end = lazy.position.get() + T::min_size(lazy.meta);
+        let pos = lazy.position.get();
         let distance = match self.lazy_state {
             LazyState::NoNode => bug!("emit_lazy_distance: outside of a metadata node"),
             LazyState::NodeStart(start) => {
                 let start = start.get();
-                assert!(min_end <= start);
-                start - min_end
+                assert!(pos <= start);
+                start - pos
             }
-            LazyState::Previous(last_min_end) => {
+            LazyState::Previous(last_pos) => {
                 assert!(
-                    last_min_end <= lazy.position,
+                    last_pos <= lazy.position,
                     "make sure that the calls to `lazy*` \
                      are in the same order as the metadata fields",
                 );
-                lazy.position.get() - last_min_end.get()
+                lazy.position.get() - last_pos.get()
             }
         };
-        self.lazy_state = LazyState::Previous(NonZeroUsize::new(min_end).unwrap());
+        self.lazy_state = LazyState::Previous(NonZeroUsize::new(pos).unwrap());
         self.emit_usize(distance)
     }
 
@@ -436,7 +436,7 @@ fn lazy<T: ?Sized + LazyMeta>(
         let meta = value.encode_contents_for_lazy(self);
         self.lazy_state = LazyState::NoNode;
 
-        assert!(pos.get() + <T>::min_size(meta) <= self.position());
+        assert!(pos.get() <= self.position());
 
         Lazy::from_position_and_meta(pos, meta)
     }
@@ -721,7 +721,7 @@ fn encode_crate_root(&mut self) -> Lazy<CrateRoot<'tcx>> {
             no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
             panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
             profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
-            symbol_mangling_version: tcx.sess.opts.debugging_opts.get_symbol_mangling_version(),
+            symbol_mangling_version: tcx.sess.opts.get_symbol_mangling_version(),
 
             crate_deps,
             dylib_dependency_formats,
@@ -1052,7 +1052,7 @@ fn encode_enum_variant_info(&mut self, def: &ty::AdtDef, index: VariantIdx) {
             assert!(f.did.is_local());
             f.did.index
         }));
-        self.encode_ident_span(def_id, variant.ident);
+        self.encode_ident_span(def_id, variant.ident(tcx));
         self.encode_item_type(def_id);
         if variant.ctor_kind == CtorKind::Fn {
             // FIXME(eddyb) encode signature only in `encode_enum_variant_ctor`.
@@ -1094,7 +1094,7 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
         // code uses it). However, we skip encoding anything relating to child
         // items - we encode information about proc-macros later on.
         let reexports = if !self.is_proc_macro {
-            match tcx.module_exports(local_def_id) {
+            match tcx.module_reexports(local_def_id) {
                 Some(exports) => self.lazy(exports),
                 _ => Lazy::empty(),
             }
@@ -1104,7 +1104,6 @@ fn encode_info_for_mod(&mut self, local_def_id: LocalDefId, md: &hir::Mod<'_>) {
 
         record!(self.tables.kind[def_id] <- EntryKind::Mod(reexports));
         if self.is_proc_macro {
-            record!(self.tables.children[def_id] <- &[]);
             // Encode this here because we don't do it in encode_def_ids.
             record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
         } else {
@@ -1139,7 +1138,7 @@ fn encode_field(
         debug!("EncodeContext::encode_field({:?})", def_id);
 
         record!(self.tables.kind[def_id] <- EntryKind::Field);
-        self.encode_ident_span(def_id, field.ident);
+        self.encode_ident_span(def_id, field.ident(self.tcx));
         self.encode_item_type(def_id);
     }
 
@@ -1294,6 +1293,9 @@ fn encode_info_for_impl_item(&mut self, def_id: DefId) {
         }
         self.encode_ident_span(def_id, impl_item.ident);
         self.encode_item_type(def_id);
+        if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
+            record!(self.tables.trait_item_def_id[def_id] <- trait_item_def_id);
+        }
         if impl_item.kind == ty::AssocKind::Fn {
             record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id));
         }
@@ -1577,12 +1579,12 @@ fn encode_info_for_generic_param(&mut self, def_id: DefId, kind: EntryKind, enco
         }
     }
 
-    fn encode_info_for_closure(&mut self, def_id: LocalDefId) {
+    fn encode_info_for_closure(&mut self, hir_id: hir::HirId) {
+        let def_id = self.tcx.hir().local_def_id(hir_id);
         debug!("EncodeContext::encode_info_for_closure({:?})", def_id);
 
         // NOTE(eddyb) `tcx.type_of(def_id)` isn't used because it's fully generic,
         // including on the signature, which is inferred in `typeck.
-        let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
         let ty = self.tcx.typeck(def_id).node_type(hir_id);
 
         match ty.kind() {
@@ -1603,9 +1605,9 @@ fn encode_info_for_closure(&mut self, def_id: LocalDefId) {
         }
     }
 
-    fn encode_info_for_anon_const(&mut self, def_id: LocalDefId) {
+    fn encode_info_for_anon_const(&mut self, id: hir::HirId) {
+        let def_id = self.tcx.hir().local_def_id(id);
         debug!("EncodeContext::encode_info_for_anon_const({:?})", def_id);
-        let id = self.tcx.hir().local_def_id_to_hir_id(def_id);
         let body_id = self.tcx.hir().body_owned_by(id);
         let const_data = self.encode_rendered_const_for_body(body_id);
         let qualifs = self.tcx.mir_const_qualif(def_id);
@@ -1926,8 +1928,7 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
     }
     fn visit_anon_const(&mut self, c: &'tcx AnonConst) {
         intravisit::walk_anon_const(self, c);
-        let def_id = self.tcx.hir().local_def_id(c.hir_id);
-        self.encode_info_for_anon_const(def_id);
+        self.encode_info_for_anon_const(c.hir_id);
     }
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
         intravisit::walk_item(self, item);
@@ -1981,8 +1982,7 @@ fn encode_info_for_generics(&mut self, generics: &hir::Generics<'tcx>) {
 
     fn encode_info_for_expr(&mut self, expr: &hir::Expr<'_>) {
         if let hir::ExprKind::Closure(..) = expr.kind {
-            let def_id = self.tcx.hir().local_def_id(expr.hir_id);
-            self.encode_info_for_closure(def_id);
+            self.encode_info_for_closure(expr.hir_id);
         }
     }
 
@@ -2055,7 +2055,7 @@ fn encode_addl_info_for_item(&mut self, item: &hir::Item<'_>) {
 
 struct ImplsVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
-    impls: FxHashMap<DefId, Vec<(DefIndex, Option<fast_reject::SimplifiedType>)>>,
+    impls: FxHashMap<DefId, Vec<(DefIndex, Option<SimplifiedType>)>>,
 }
 
 impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplsVisitor<'tcx> {
index 35016453369b59468abead6823818507868fca88..75c5880f05d927a0b4e05978dd963f1a8acebd80 100644 (file)
 use rustc_hir::definitions::DefKey;
 use rustc_hir::lang_items;
 use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc_middle::mir;
 use rustc_middle::thir;
+use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, ReprOptions, Ty};
 use rustc_serialize::opaque::Encoder;
 /// e.g. for `Lazy<[T]>`, this is the length (count of `T` values).
 trait LazyMeta {
     type Meta: Copy + 'static;
-
-    /// Returns the minimum encoded size.
-    // FIXME(eddyb) Give better estimates for certain types.
-    fn min_size(meta: Self::Meta) -> usize;
 }
 
 impl<T> LazyMeta for T {
     type Meta = ();
-
-    fn min_size(_: ()) -> usize {
-        assert_ne!(std::mem::size_of::<T>(), 0);
-        1
-    }
 }
 
 impl<T> LazyMeta for [T] {
     type Meta = usize;
-
-    fn min_size(len: usize) -> usize {
-        len * T::min_size(())
-    }
 }
 
 /// A value of type T referred to by its absolute position
@@ -160,8 +148,7 @@ enum LazyState {
     NodeStart(NonZeroUsize),
 
     /// Inside a metadata node, with a previous `Lazy`.
-    /// The position is a conservative estimate of where that
-    /// previous `Lazy` would end (see their comments).
+    /// The position is where that previous `Lazy` would start.
     Previous(NonZeroUsize),
 }
 
@@ -261,7 +248,7 @@ macro_rules! Lazy {
 #[derive(MetadataEncodable, MetadataDecodable)]
 crate struct TraitImpls {
     trait_id: (u32, DefIndex),
-    impls: Lazy<[(DefIndex, Option<ty::fast_reject::SimplifiedType>)]>,
+    impls: Lazy<[(DefIndex, Option<SimplifiedType>)]>,
 }
 
 /// Define `LazyTables` and `TableBuilders` at the same time.
@@ -301,6 +288,7 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> {
     ty: Table<DefIndex, Lazy!(Ty<'tcx>)>,
     fn_sig: Table<DefIndex, Lazy!(ty::PolyFnSig<'tcx>)>,
     impl_trait_ref: Table<DefIndex, Lazy!(ty::TraitRef<'tcx>)>,
+    trait_item_def_id: Table<DefIndex, Lazy<DefId>>,
     inherent_impls: Table<DefIndex, Lazy<[DefIndex]>>,
     variances: Table<DefIndex, Lazy<[ty::Variance]>>,
     generics: Table<DefIndex, Lazy<ty::Generics>>,
@@ -348,7 +336,7 @@ enum EntryKind {
     Union(Lazy<VariantData>, ReprOptions),
     Fn(Lazy<FnData>),
     ForeignFn(Lazy<FnData>),
-    Mod(Lazy<[Export]>),
+    Mod(Lazy<[ModChild]>),
     MacroDef(Lazy<MacroDef>),
     ProcMacro(MacroKind),
     Closure,
index 4dfefda490b3deeea6878c4f97787aecd747da5c..265ca5a6d8d1369c5d14945ba88b864d913918f3 100644 (file)
@@ -183,10 +183,6 @@ impl<I: Idx, T> LazyMeta for Table<I, T>
     Option<T>: FixedSizeEncoding,
 {
     type Meta = usize;
-
-    fn min_size(len: usize) -> usize {
-        len
-    }
 }
 
 impl<I: Idx, T> Lazy<Table<I, T>>
index f8d3fb6c48de713c829b55567d92caf0c1205e9f..30664784ed8f8540a0a91e59ddac373a5f4f5d84 100644 (file)
@@ -10,10 +10,10 @@ doctest = false
 rustc_arena = { path = "../rustc_arena" }
 bitflags = "1.2.1"
 either = "1.5.0"
-gsgdt = "0.1.3"
+gsgdt = "0.1.2"
 tracing = "0.1"
-rustc-rayon = "0.3.1"
-rustc-rayon-core = "0.3.1"
+rustc-rayon = "0.3.2"
+rustc-rayon-core = "0.3.2"
 polonius-engine = "0.13.0"
 rustc_apfloat = { path = "../rustc_apfloat" }
 rustc_attr = { path = "../rustc_attr" }
index 79d7ca32f35553ba9e525404bd5b7f0cdda71e67..cf50378ad606baa93e44abc69d7bbf0ff098aac5 100644 (file)
@@ -1,6 +1,5 @@
 use crate::ty::{self, TyCtxt};
 use rustc_data_structures::profiling::SelfProfilerRef;
-use rustc_data_structures::sync::Lock;
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::Session;
 
@@ -17,6 +16,7 @@
 
 pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
 pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
+pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>;
 pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
 pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
 pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
@@ -45,7 +45,7 @@ fn debug_node(node: &DepNode, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Resu
         write!(f, ")")
     }
 
-    fn with_deps<OP, R>(task_deps: Option<&Lock<TaskDeps>>, op: OP) -> R
+    fn with_deps<OP, R>(task_deps: TaskDepsRef<'_>, op: OP) -> R
     where
         OP: FnOnce() -> R,
     {
@@ -58,7 +58,7 @@ fn with_deps<OP, R>(task_deps: Option<&Lock<TaskDeps>>, op: OP) -> R
 
     fn read_deps<OP>(op: OP)
     where
-        OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps>>),
+        OP: for<'a> FnOnce(TaskDepsRef<'a>),
     {
         ty::tls::with_context_opt(|icx| {
             let icx = if let Some(icx) = icx { icx } else { return };
diff --git a/compiler/rustc_middle/src/hir/exports.rs b/compiler/rustc_middle/src/hir/exports.rs
deleted file mode 100644 (file)
index f37b976..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-use crate::ty;
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def::Res;
-use rustc_hir::def_id::LocalDefId;
-use rustc_macros::HashStable;
-use rustc_span::symbol::Ident;
-use rustc_span::Span;
-
-use std::fmt::Debug;
-
-/// This is the replacement export map. It maps a module to all of the exports
-/// within.
-pub type ExportMap = FxHashMap<LocalDefId, Vec<Export>>;
-
-#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
-pub struct Export {
-    /// The name of the target.
-    pub ident: Ident,
-    /// The resolution of the target.
-    /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
-    pub res: Res<!>,
-    /// The span of the target.
-    pub span: Span,
-    /// The visibility of the export.
-    /// We include non-`pub` exports for hygienic macros that get used from extern crates.
-    pub vis: ty::Visibility,
-}
index 394a1fc227095ba0a6125ae3f8adeb5e91c7e8a2..aac9595ae6bacfae0d0ce0a752c368db8732e80d 100644 (file)
@@ -117,13 +117,13 @@ pub struct ParentOwnerIterator<'hir> {
 }
 
 impl<'hir> Iterator for ParentOwnerIterator<'hir> {
-    type Item = (HirId, OwnerNode<'hir>);
+    type Item = (LocalDefId, OwnerNode<'hir>);
 
     fn next(&mut self) -> Option<Self::Item> {
         if self.current_id.local_id.index() != 0 {
             self.current_id.local_id = ItemLocalId::new(0);
             if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
-                return Some((self.current_id, node.node));
+                return Some((self.current_id.owner, node.node));
             }
         }
         if self.current_id == CRATE_HIR_ID {
@@ -141,7 +141,7 @@ fn next(&mut self) -> Option<Self::Item> {
 
             // If this `HirId` doesn't have an entry, skip it and look for its `parent_id`.
             if let Some(node) = self.map.tcx.hir_owner(self.current_id.owner) {
-                return Some((self.current_id, node.node));
+                return Some((self.current_id.owner, node.node));
             }
         }
     }
@@ -200,8 +200,12 @@ pub fn local_def_id(&self, hir_id: HirId) -> LocalDefId {
 
     #[inline]
     pub fn opt_local_def_id(&self, hir_id: HirId) -> Option<LocalDefId> {
-        // FIXME(#85914) is this access safe for incr. comp.?
-        self.tcx.untracked_resolutions.definitions.opt_hir_id_to_local_def_id(hir_id)
+        if hir_id.local_id == ItemLocalId::new(0) {
+            Some(hir_id.owner)
+        } else {
+            // FIXME(#85914) is this access safe for incr. comp.?
+            self.tcx.untracked_resolutions.definitions.opt_hir_id_to_local_def_id(hir_id)
+        }
     }
 
     #[inline]
@@ -336,17 +340,28 @@ 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>> {
+        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> {
         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> {
+        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>> {
         id.as_local().and_then(|id| self.find(self.local_def_id_to_hir_id(id)))
     }
 
-    pub fn get_generics(&self, id: DefId) -> Option<&'hir Generics<'hir>> {
-        let id = id.as_local()?;
+    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),
@@ -530,10 +545,12 @@ pub fn par_body_owners<F: Fn(LocalDefId) + Sync + Send>(self, f: F) {
         });
     }
 
-    pub fn ty_param_owner(&self, id: HirId) -> HirId {
+    pub fn ty_param_owner(&self, id: HirId) -> LocalDefId {
         match self.get(id) {
-            Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => id,
-            Node::GenericParam(_) => self.get_parent_node(id),
+            Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => {
+                id.expect_owner()
+            }
+            Node::GenericParam(_) => self.get_parent_item(id),
             _ => bug!("ty_param_owner: {} not a type parameter", self.node_to_string(id)),
         }
     }
@@ -776,23 +793,23 @@ 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) -> HirId {
-        if let Some((hir_id, _node)) = self.parent_owner_iter(hir_id).next() {
-            hir_id
+    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 {
-            CRATE_HIR_ID
+            CRATE_DEF_ID
         }
     }
 
     /// 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) -> HirId {
-        for (hir_id, node) in self.parent_owner_iter(hir_id) {
+    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 hir_id;
+                return def_id;
             }
         }
-        CRATE_HIR_ID
+        CRATE_DEF_ID
     }
 
     /// When on an if expression, a match arm tail expression or a match arm, give back
@@ -855,19 +872,18 @@ pub fn get_defining_scope(&self, id: HirId) -> HirId {
         }
     }
 
-    pub fn get_parent_did(&self, id: HirId) -> LocalDefId {
-        self.local_def_id(self.get_parent_item(id))
-    }
-
     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(self.local_def_id(parent)) {
+        if let Some(node) = self.tcx.hir_owner(parent) {
             if let OwnerNode::Item(Item { kind: ItemKind::ForeignMod { abi, .. }, .. }) = node.node
             {
                 return *abi;
             }
         }
-        bug!("expected foreign mod or inlined parent, found {}", self.node_to_string(parent))
+        bug!(
+            "expected foreign mod or inlined parent, found {}",
+            self.node_to_string(HirId::make_owner(parent))
+        )
     }
 
     pub fn expect_item(&self, id: LocalDefId) -> &'hir Item<'hir> {
@@ -925,7 +941,7 @@ pub fn opt_name(&self, id: HirId) -> Option<Symbol> {
             Node::Lifetime(lt) => lt.name.ident().name,
             Node::GenericParam(param) => param.name.ident().name,
             Node::Binding(&Pat { kind: PatKind::Binding(_, _, l, _), .. }) => l.name,
-            Node::Ctor(..) => self.name(self.get_parent_item(id)),
+            Node::Ctor(..) => self.name(HirId::make_owner(self.get_parent_item(id))),
             _ => return None,
         })
     }
index 95d7273b17b446372976332c2a846aaf066e60f8..8164eefd6cb2e317bf6e8631f5e33444d5ba1f24 100644 (file)
@@ -2,7 +2,6 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
 
-pub mod exports;
 pub mod map;
 pub mod place;
 
@@ -59,13 +58,13 @@ pub fn parent_module(self, id: HirId) -> LocalDefId {
 pub fn provide(providers: &mut Providers) {
     providers.parent_module_from_def_id = |tcx, id| {
         let hir = tcx.hir();
-        hir.local_def_id(hir.get_module_parent_node(hir.local_def_id_to_hir_id(id)))
+        hir.get_module_parent_node(hir.local_def_id_to_hir_id(id))
     };
     providers.hir_crate = |tcx, ()| tcx.untracked_crate;
     providers.crate_hash = map::crate_hash;
     providers.hir_module_items = map::hir_module_items;
     providers.hir_owner = |tcx, id| {
-        let owner = tcx.hir_crate(()).owners[id].as_ref()?;
+        let owner = tcx.hir_crate(()).owners.get(id)?.as_ref()?;
         let node = owner.node();
         Some(Owner { node, hash_without_bodies: owner.nodes.hash_without_bodies })
     };
index e6dd4e484cc9ce7ff7d28fb58f00948eb747ec8d..920eca7a717729e72cd1d49bfaea752a0ae74a06 100644 (file)
@@ -84,6 +84,7 @@
 pub mod hir;
 pub mod infer;
 pub mod lint;
+pub mod metadata;
 pub mod middle;
 pub mod mir;
 pub mod thir;
diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs
new file mode 100644 (file)
index 0000000..6dcdc58
--- /dev/null
@@ -0,0 +1,24 @@
+use crate::ty;
+
+use rustc_hir::def::Res;
+use rustc_macros::HashStable;
+use rustc_span::symbol::Ident;
+use rustc_span::Span;
+
+/// This structure is supposed to keep enough data to re-create `NameBinding`s for other crates
+/// during name resolution. Right now the bindings are not recreated entirely precisely so we may
+/// need to add more data in the future to correctly support macros 2.0, for example.
+/// Module child can be either a proper item or a reexport (including private imports).
+/// In case of reexport all the fields describe the reexport item itself, not what it refers to.
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct ModChild {
+    /// Name of the item.
+    pub ident: Ident,
+    /// Resolution result corresponding to the item.
+    /// Local variables cannot be exported, so this `Res` doesn't need the ID parameter.
+    pub res: Res<!>,
+    /// Visibility of the item.
+    pub vis: ty::Visibility,
+    /// Span of the item.
+    pub span: Span,
+}
index f33bd3438b96836f54d20b224937592a3f85022f..ff993ac392cf7fe2e18565d8e13d447de6841057 100644 (file)
@@ -28,7 +28,7 @@ pub enum AccessLevel {
 }
 
 /// Holds a map of accessibility levels for reachable HIR nodes.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct AccessLevels<Id = LocalDefId> {
     pub map: FxHashMap<Id, AccessLevel>,
 }
index 175d31d69d91629b7b168b5bb33ca53d31a095ec..6d531d3e7d620fa68a52d06c25d4bd038ca2edf9 100644 (file)
@@ -348,7 +348,7 @@ pub fn eval_stability(
         // Deprecated attributes apply in-crate and cross-crate.
         if let Some(id) = id {
             if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
-                let parent_def_id = self.hir().local_def_id(self.hir().get_parent_item(id));
+                let parent_def_id = self.hir().get_parent_item(id);
                 let skip = self
                     .lookup_deprecation_entry(parent_def_id.to_def_id())
                     .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
index 44d0ce935df7fd2328b0891a1c1f23213159b34a..770b52a4d4b0fbb3ffc26e9bdf3030b23e2d7e4c 100644 (file)
@@ -55,7 +55,7 @@ fn bb_to_graph_node(block: BasicBlock, body: &Body<'_>, dark_mode: bool) -> Node
     data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
     stmts.push(terminator_head);
 
-    Node::from_list(stmts, label, title, style)
+    Node::new(stmts, label, title, style)
 }
 
 // Must match `[0-9A-Za-z_]*`. This does not appear in the rendered graph, so
index f9831855633151ad1cf368d865dee4d2252900a8..ec0f5b7d0595cb070a576d85111a675ce53e25f9 100644 (file)
@@ -38,7 +38,7 @@ pub fn const_eval_resolve(
         ct: ty::Unevaluated<'tcx>,
         span: Option<Span>,
     ) -> EvalToConstValueResult<'tcx> {
-        match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs(self)) {
+        match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
             Ok(Some(instance)) => {
                 let cid = GlobalId { instance, promoted: ct.promoted };
                 self.const_eval_global_id(param_env, cid, span)
index c7c306e7d06cc518f82879234746c3f71a80e9d5..899386d2bc8f29622218c495f52cc09a42c7c772 100644 (file)
@@ -288,7 +288,6 @@ pub struct Body<'tcx> {
 
 impl<'tcx> Body<'tcx> {
     pub fn new(
-        tcx: TyCtxt<'tcx>,
         source: MirSource<'tcx>,
         basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
         source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
@@ -331,7 +330,7 @@ pub fn new(
             predecessor_cache: PredecessorCache::new(),
             is_cyclic: GraphIsCyclicCache::new(),
         };
-        body.is_polymorphic = body.definitely_has_param_types_or_consts(tcx);
+        body.is_polymorphic = body.has_param_types_or_consts();
         body
     }
 
@@ -341,7 +340,7 @@ pub fn new(
     /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different
     /// crate.
     pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) -> Self {
-        Body {
+        let mut body = Body {
             phase: MirPhase::Build,
             source: MirSource::item(DefId::local(CRATE_DEF_INDEX)),
             basic_blocks,
@@ -357,7 +356,9 @@ pub fn new_cfg_only(basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>) ->
             is_polymorphic: false,
             predecessor_cache: PredecessorCache::new(),
             is_cyclic: GraphIsCyclicCache::new(),
-        }
+        };
+        body.is_polymorphic = body.has_param_types_or_consts();
+        body
     }
 
     #[inline]
@@ -2336,8 +2337,6 @@ pub enum NullOp {
     SizeOf,
     /// Returns the minimum alignment of a type
     AlignOf,
-    /// Creates a new uninitialized box for a value of that type
-    Box,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
@@ -2441,7 +2440,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
                                 CtorKind::Fictive => {
                                     let mut struct_fmt = fmt.debug_struct(&name);
                                     for (field, place) in iter::zip(&variant_def.fields, places) {
-                                        struct_fmt.field(field.ident.as_str(), place);
+                                        struct_fmt.field(field.name.as_str(), place);
                                     }
                                     struct_fmt.finish()
                                 }
@@ -2451,7 +2450,6 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
 
                     AggregateKind::Closure(def_id, substs) => ty::tls::with(|tcx| {
                         if let Some(def_id) = def_id.as_local() {
-                            let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
                             let name = if tcx.sess.opts.debugging_opts.span_free_formats {
                                 let substs = tcx.lift(substs).unwrap();
                                 format!(
@@ -2459,7 +2457,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
                                     tcx.def_path_str_with_substs(def_id.to_def_id(), substs),
                                 )
                             } else {
-                                let span = tcx.hir().span(hir_id);
+                                let span = tcx.def_span(def_id);
                                 format!(
                                     "[closure@{}]",
                                     tcx.sess.source_map().span_to_diagnostic_string(span)
@@ -2483,8 +2481,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
 
                     AggregateKind::Generator(def_id, _, _) => ty::tls::with(|tcx| {
                         if let Some(def_id) = def_id.as_local() {
-                            let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-                            let name = format!("[generator@{:?}]", tcx.hir().span(hir_id));
+                            let name = format!("[generator@{:?}]", tcx.def_span(def_id));
                             let mut struct_fmt = fmt.debug_struct(&name);
 
                             // FIXME(project-rfc-2229#48): This should be a list of capture names/places
@@ -2787,7 +2784,7 @@ pub(crate) fn variant(
         field: Field,
     ) -> Self {
         self.projs.push(ProjectionElem::Downcast(
-            Some(adt_def.variants[variant_index].ident.name),
+            Some(adt_def.variants[variant_index].name),
             variant_index,
         ));
         self.projs.push(ProjectionElem::Field(field, ()));
index 1422537cd50609dfe37719ecd0d2c11ca0440b7e..892808386deef4c79bc5b3cad93d7fd711d066d1 100644 (file)
@@ -179,15 +179,11 @@ pub fn is_instantiable(&self, tcx: TyCtxt<'tcx>) -> bool {
 
     pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option<Span> {
         match *self {
-            MonoItem::Fn(Instance { def, .. }) => {
-                def.def_id().as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
-            }
-            MonoItem::Static(def_id) => {
-                def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
-            }
-            MonoItem::GlobalAsm(item_id) => Some(item_id.hir_id()),
+            MonoItem::Fn(Instance { def, .. }) => def.def_id().as_local(),
+            MonoItem::Static(def_id) => def_id.as_local(),
+            MonoItem::GlobalAsm(item_id) => Some(item_id.def_id),
         }
-        .map(|hir_id| tcx.hir().span(hir_id))
+        .map(|def_id| tcx.def_span(def_id))
     }
 
     // Only used by rustc_codegen_cranelift
@@ -247,6 +243,9 @@ pub struct CodegenUnit<'tcx> {
     items: FxHashMap<MonoItem<'tcx>, (Linkage, Visibility)>,
     size_estimate: Option<usize>,
     primary: bool,
+    /// True if this is CGU is used to hold code coverage information for dead code,
+    /// false otherwise.
+    is_code_coverage_dead_code_cgu: bool,
 }
 
 /// Specifies the linkage type for a `MonoItem`.
@@ -277,7 +276,13 @@ pub enum Visibility {
 impl<'tcx> CodegenUnit<'tcx> {
     #[inline]
     pub fn new(name: Symbol) -> CodegenUnit<'tcx> {
-        CodegenUnit { name, items: Default::default(), size_estimate: None, primary: false }
+        CodegenUnit {
+            name,
+            items: Default::default(),
+            size_estimate: None,
+            primary: false,
+            is_code_coverage_dead_code_cgu: false,
+        }
     }
 
     pub fn name(&self) -> Symbol {
@@ -304,6 +309,15 @@ pub fn items_mut(&mut self) -> &mut FxHashMap<MonoItem<'tcx>, (Linkage, Visibili
         &mut self.items
     }
 
+    pub fn is_code_coverage_dead_code_cgu(&self) -> bool {
+        self.is_code_coverage_dead_code_cgu
+    }
+
+    /// Marks this CGU as the one used to contain code coverage information for dead code.
+    pub fn make_code_coverage_dead_code_cgu(&mut self) {
+        self.is_code_coverage_dead_code_cgu = true;
+    }
+
     pub fn mangle_name(human_readable_name: &str) -> String {
         // We generate a 80 bit hash from the name. This should be enough to
         // avoid collisions and is still reasonably short for filenames.
@@ -404,9 +418,11 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
             // The size estimate is not relevant to the hash
             size_estimate: _,
             primary: _,
+            is_code_coverage_dead_code_cgu,
         } = *self;
 
         name.hash_stable(hcx, hasher);
+        is_code_coverage_dead_code_cgu.hash_stable(hcx, hasher);
 
         let mut items: Vec<(Fingerprint, _)> = items
             .iter()
index 8cc705384b03e7bb8bdabf0c826bc087cb0b7c9a..f2ad591071114bb043961e8c8679a4211447c2e2 100644 (file)
@@ -476,8 +476,8 @@ fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) {
                 ty::ConstKind::Unevaluated(uv) => format!(
                     "Unevaluated({}, {:?}, {:?})",
                     self.tcx.def_path_str(uv.def.did),
-                    uv.substs(self.tcx),
-                    uv.promoted
+                    uv.substs,
+                    uv.promoted,
                 ),
                 ty::ConstKind::Value(val) => format!("Value({:?})", val),
                 ty::ConstKind::Error(_) => "Error".to_string(),
@@ -683,12 +683,6 @@ fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> +
     }
     struct CollectAllocIds(BTreeSet<AllocId>);
     impl<'tcx> TypeVisitor<'tcx> for CollectAllocIds {
-        fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-            // `AllocId`s are only inside of `ConstKind::Value` which
-            // can't be part of the anon const default substs.
-            None
-        }
-
         fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             if let ty::ConstKind::Value(val) = c.val {
                 self.0.extend(alloc_ids_from_const(val));
index 507f9971981b0a5b6270715faeae44b6596ab931..e76cf5d94d32edfdbc358ad311b99c9f19b670af 100644 (file)
@@ -665,9 +665,7 @@ fn trim_span_hi(span: Span, to_pos: BytePos) -> Span {
 }
 
 fn fn_span<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Span {
-    let hir_id =
-        tcx.hir().local_def_id_to_hir_id(def_id.as_local().expect("expected DefId is local"));
-    let fn_decl_span = tcx.hir().span(hir_id);
+    let fn_decl_span = tcx.def_span(def_id);
     if let Some(body_span) = hir_body(tcx, def_id).map(|hir_body| hir_body.value.span) {
         if fn_decl_span.ctxt() == body_span.ctxt() { fn_decl_span.to(body_span) } else { body_span }
     } else {
index e577df482055674770ff57bdd874b5f41a9364fb..dc53dc8de9de95129a800945dff0240da0a42bf2 100644 (file)
@@ -195,7 +195,6 @@ pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
             }
             Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
             Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
-            Rvalue::NullaryOp(NullOp::Box, t) => tcx.mk_box(t),
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize,
             Rvalue::Aggregate(ref ak, ref ops) => match **ak {
                 AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64),
@@ -215,9 +214,7 @@ pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
     /// whether its only shallowly initialized (`Rvalue::Box`).
     pub fn initialization_state(&self) -> RvalueInitializationState {
         match *self {
-            Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::ShallowInitBox(_, _) => {
-                RvalueInitializationState::Shallow
-            }
+            Rvalue::ShallowInitBox(_, _) => RvalueInitializationState::Shallow,
             _ => RvalueInitializationState::Deep,
         }
     }
index 027c0c64924b830200a3f179716b3fc936f3842f..5dc7b21964266f3b67269fbf3076ea67ce2f76f3 100644 (file)
         separate_provide_extern
     }
 
-    query default_anon_const_substs(key: DefId) -> SubstsRef<'tcx> {
-        desc { |tcx| "computing the default generic arguments for `{}`", tcx.def_path_str(key) }
-    }
-
     /// Records the type of every item.
     query type_of(key: DefId) -> Ty<'tcx> {
         desc { |tcx|
         storage(ArenaCacheSelector<'tcx>)
     }
 
-    /// Returns the name of the file that contains the function body, if instrumented for coverage.
-    query covered_file_name(key: DefId) -> Option<Symbol> {
-        desc {
-            |tcx| "retrieving the covered file name, if instrumented, for `{}`",
-            tcx.def_path_str(key)
-        }
-        storage(ArenaCacheSelector<'tcx>)
-        cache_on_disk_if { key.is_local() }
-    }
-
     /// Returns the `CodeRegions` for a function that has instrumented coverage, in case the
     /// function was optimized out before codegen, and before being added to the Coverage Map.
     query covered_code_regions(key: DefId) -> Vec<&'tcx mir::coverage::CodeRegion> {
         desc { |tcx| "collecting associated items of {}", tcx.def_path_str(key) }
     }
 
+    /// Maps from associated items on a trait to the corresponding associated
+    /// item on the impl specified by `impl_id`.
+    ///
+    /// For example, with the following code
+    ///
+    /// ```
+    /// struct Type {}
+    ///                         // DefId
+    /// trait Trait {           // trait_id
+    ///     fn f();             // trait_f
+    ///     fn g() {}           // trait_g
+    /// }
+    ///
+    /// impl Trait for Type {   // impl_id
+    ///     fn f() {}           // impl_f
+    ///     fn g() {}           // impl_g
+    /// }
+    /// ```
+    ///
+    /// 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>)
+    }
+
     /// Given an `impl_id`, return the trait it implements.
     /// Return `None` if this is an inherent impl.
     query impl_trait_ref(impl_id: DefId) -> Option<ty::TraitRef<'tcx>> {
         desc { "traits in scope at a block" }
     }
 
-    query module_exports(def_id: LocalDefId) -> Option<&'tcx [Export]> {
-        desc { |tcx| "looking up items exported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
+    query module_reexports(def_id: LocalDefId) -> Option<&'tcx [ModChild]> {
+        desc { |tcx| "looking up reexports of module `{}`", tcx.def_path_str(def_id.to_def_id()) }
     }
 
     query impl_defaultness(def_id: DefId) -> hir::Defaultness {
 
     /// Given a crate and a trait, look up all impls of that trait in the crate.
     /// Return `(impl_id, self_ty)`.
-    query implementations_of_trait(_: (CrateNum, DefId))
-        -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
+    query implementations_of_trait(_: (CrateNum, DefId)) -> &'tcx [(DefId, Option<SimplifiedType>)] {
         desc { "looking up implementations of a trait in a crate" }
         separate_provide_extern
     }
 
-    /// Given a crate, look up all trait impls in that crate.
-    /// Return `(impl_id, self_ty)`.
-    query all_trait_implementations(_: CrateNum)
-        -> &'tcx [(DefId, Option<ty::fast_reject::SimplifiedType>)] {
-        desc { "looking up all (?) trait implementations" }
-        separate_provide_extern
-    }
-
     query is_dllimport_foreign_item(def_id: DefId) -> bool {
         desc { |tcx| "is_dllimport_foreign_item({})", tcx.def_path_str(def_id) }
     }
         desc { "fetching what a crate is named" }
         separate_provide_extern
     }
-    query item_children(def_id: DefId) -> &'tcx [Export] {
-        desc { |tcx| "collecting child items of `{}`", tcx.def_path_str(def_id) }
+    query module_children(def_id: DefId) -> &'tcx [ModChild] {
+        desc { |tcx| "collecting child items of module `{}`", tcx.def_path_str(def_id) }
         separate_provide_extern
     }
     query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
         desc { "calculating the missing lang items in a crate" }
         separate_provide_extern
     }
-    query visible_parent_map(_: ()) -> DefIdMap<DefId> {
-        storage(ArenaCacheSelector<'tcx>)
+    query visible_parent_map(_: ()) -> Lrc<DefIdMap<DefId>> {
         desc { "calculating the visible parent map" }
     }
     query trimmed_def_paths(_: ()) -> FxHashMap<DefId, Symbol> {
index 8d6fd1e729d3b52b5e4ec75dc6bd775317101924..d2e3ce97d12652bf97ba623d9854f268dda35de8 100644 (file)
@@ -726,7 +726,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 };
 
                 if let Some(variant) = variant {
-                    write!(f, "{}", variant.ident)?;
+                    write!(f, "{}", variant.name)?;
 
                     // Only for Adt we can have `S {...}`,
                     // which we handle separately here.
@@ -738,7 +738,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                             if let PatKind::Wild = *p.pattern.kind {
                                 continue;
                             }
-                            let name = variant.fields[p.field.index()].ident;
+                            let name = variant.fields[p.field.index()].name;
                             write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?;
                             printed += 1;
                         }
index 3e9cd6b46b211c4c207f848ec66f280d13875749..087be313b26def87e4806eac693175ff3780ef97 100644 (file)
@@ -4,7 +4,6 @@
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::ErrorReported;
 use rustc_hir::def_id::{DefId, DefIdMap};
-use rustc_span::symbol::Ident;
 
 /// A per-trait graph of impls in specialization order. At the moment, this
 /// graph forms a tree rooted with the trait itself, with all other nodes
@@ -75,34 +74,28 @@ pub enum Node {
     Trait(DefId),
 }
 
-impl<'tcx> Node {
+impl Node {
     pub fn is_from_trait(&self) -> bool {
         matches!(self, Node::Trait(..))
     }
 
-    /// Iterate over the items defined directly by the given (impl or trait) node.
-    pub fn items(&self, tcx: TyCtxt<'tcx>) -> impl 'tcx + Iterator<Item = &'tcx ty::AssocItem> {
-        tcx.associated_items(self.def_id()).in_definition_order()
-    }
-
-    /// Finds an associated item defined in this node.
+    /// Trys to find the associated item that implements `trait_item_def_id`
+    /// defined in this node.
     ///
     /// If this returns `None`, the item can potentially still be found in
     /// parents of this node.
-    pub fn item(
+    pub fn item<'tcx>(
         &self,
         tcx: TyCtxt<'tcx>,
-        trait_item_name: Ident,
-        trait_item_kind: ty::AssocKind,
-        trait_def_id: DefId,
-    ) -> Option<ty::AssocItem> {
-        tcx.associated_items(self.def_id())
-            .filter_by_name_unhygienic(trait_item_name.name)
-            .find(move |impl_item| {
-                trait_item_kind == impl_item.kind
-                    && tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id)
-            })
-            .copied()
+        trait_item_def_id: DefId,
+    ) -> Option<&'tcx ty::AssocItem> {
+        match *self {
+            Node::Trait(_) => Some(tcx.associated_item(trait_item_def_id)),
+            Node::Impl(impl_def_id) => {
+                let id = tcx.impl_item_implementor_ids(impl_def_id).get(&trait_item_def_id)?;
+                Some(tcx.associated_item(*id))
+            }
+        }
     }
 
     pub fn def_id(&self) -> DefId {
@@ -181,17 +174,11 @@ pub fn is_final(&self) -> bool {
 impl<'tcx> Ancestors<'tcx> {
     /// Finds the bottom-most (ie. most specialized) definition of an associated
     /// item.
-    pub fn leaf_def(
-        mut self,
-        tcx: TyCtxt<'tcx>,
-        trait_item_name: Ident,
-        trait_item_kind: ty::AssocKind,
-    ) -> Option<LeafDef> {
-        let trait_def_id = self.trait_def_id;
+    pub fn leaf_def(mut self, tcx: TyCtxt<'tcx>, trait_item_def_id: DefId) -> Option<LeafDef> {
         let mut finalizing_node = None;
 
         self.find_map(|node| {
-            if let Some(item) = node.item(tcx, trait_item_name, trait_item_kind, trait_def_id) {
+            if let Some(item) = node.item(tcx, trait_item_def_id) {
                 if finalizing_node.is_none() {
                     let is_specializable = item.defaultness.is_default()
                         || tcx.impl_defaultness(node.def_id()).is_default();
@@ -201,7 +188,7 @@ pub fn leaf_def(
                     }
                 }
 
-                Some(LeafDef { item, defining_node: node, finalizing_node })
+                Some(LeafDef { item: *item, defining_node: node, finalizing_node })
             } else {
                 // Item not mentioned. This "finalizes" any defaulted item provided by an ancestor.
                 finalizing_node = Some(node);
index 5cde54c9328d16295b29259ce1c0c9b0d7cdd10d..6cec75d36e2c2f2063ff543c34dce6f9aca9b178 100644 (file)
@@ -4,6 +4,7 @@
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::HashingControls;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
@@ -136,12 +137,13 @@ fn hash<H: Hasher>(&self, s: &mut H) {
 impl<'a> HashStable<StableHashingContext<'a>> for AdtDef {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         thread_local! {
-            static CACHE: RefCell<FxHashMap<usize, Fingerprint>> = Default::default();
+            static CACHE: RefCell<FxHashMap<(usize, HashingControls), Fingerprint>> = Default::default();
         }
 
         let hash: Fingerprint = CACHE.with(|cache| {
             let addr = self as *const AdtDef as usize;
-            *cache.borrow_mut().entry(addr).or_insert_with(|| {
+            let hashing_controls = hcx.hashing_controls();
+            *cache.borrow_mut().entry((addr, hashing_controls)).or_insert_with(|| {
                 let ty::AdtDef { did, ref variants, ref flags, ref repr } = *self;
 
                 let mut hasher = StableHasher::new();
index bf5a3e68250a02e4aec066c0fb8c4159af062b92..8563bac0bbf8740b7e268f9e4582a519e4eba19a 100644 (file)
@@ -40,6 +40,7 @@ pub fn id(&self) -> DefId {
     }
 }
 
+/// Information about an associated item
 #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
 pub struct AssocItem {
     pub def_id: DefId,
@@ -50,6 +51,10 @@ pub struct AssocItem {
     pub defaultness: hir::Defaultness,
     pub container: AssocItemContainer,
 
+    /// If this is an item in an impl of a trait then this is the `DefId` of
+    /// the associated item on the trait that this implements.
+    pub trait_item_def_id: Option<DefId>,
+
     /// Whether this is a method with an explicit self
     /// as its first parameter, allowing method calls.
     pub fn_has_self_parameter: bool,
@@ -134,21 +139,6 @@ pub fn filter_by_name_unhygienic(
         self.items.get_by_key(name).copied()
     }
 
-    /// Returns an iterator over all associated items with the given name.
-    ///
-    /// Multiple items may have the same name if they are in different `Namespace`s. For example,
-    /// an associated type can have the same name as a method. Use one of the `find_by_name_and_*`
-    /// methods below if you know which item you are looking for.
-    pub fn filter_by_name<'a>(
-        &'a self,
-        tcx: TyCtxt<'a>,
-        ident: Ident,
-        parent_def_id: DefId,
-    ) -> impl 'a + Iterator<Item = &'a ty::AssocItem> {
-        self.filter_by_name_unhygienic(ident.name)
-            .filter(move |item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
-    }
-
     /// Returns the associated item with the given name and `AssocKind`, if one exists.
     pub fn find_by_name_and_kind(
         &self,
index 771acc29649139d0e03d7caf993796c3c60fa4a2..0ac2ea4db5e77c38cfc53e2dbf7bbf0d1c42d817 100644 (file)
@@ -52,35 +52,18 @@ pub fn new(var_hir_id: hir::HirId, closure_def_id: LocalDefId) -> UpvarId {
 /// Information describing the capture of an upvar. This is computed
 /// during `typeck`, specifically by `regionck`.
 #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
-pub enum UpvarCapture<'tcx> {
+pub enum UpvarCapture {
     /// Upvar is captured by value. This is always true when the
     /// closure is labeled `move`, but can also be true in other cases
     /// depending on inference.
-    ///
-    /// If the upvar was inferred to be captured by value (e.g. `move`
-    /// was not used), then the `Span` points to a usage that
-    /// required it. There may be more than one such usage
-    /// (e.g. `|| { a; a; }`), in which case we pick an
-    /// arbitrary one.
-    ByValue(Option<Span>),
+    ByValue,
 
     /// Upvar is captured by reference.
-    ByRef(UpvarBorrow<'tcx>),
-}
-
-#[derive(PartialEq, Clone, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
-pub struct UpvarBorrow<'tcx> {
-    /// The kind of borrow: by-ref upvars have access to shared
-    /// immutable borrows, which are not part of the normal language
-    /// syntax.
-    pub kind: BorrowKind,
-
-    /// Region of the resulting reference.
-    pub region: ty::Region<'tcx>,
+    ByRef(BorrowKind),
 }
 
 pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
-pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
+pub type UpvarCaptureMap = FxHashMap<UpvarId, UpvarCapture>;
 
 /// Given the closure DefId this map provides a map of root variables to minimum
 /// set of `CapturedPlace`s that need to be tracked to support all captures of that closure.
@@ -150,10 +133,13 @@ pub struct CapturedPlace<'tcx> {
     pub place: HirPlace<'tcx>,
 
     /// `CaptureKind` and expression(s) that resulted in such capture of `place`.
-    pub info: CaptureInfo<'tcx>,
+    pub info: CaptureInfo,
 
     /// Represents if `place` can be mutated or not.
     pub mutability: hir::Mutability,
+
+    /// Region of the resulting reference if the upvar is captured by ref.
+    pub region: Option<ty::Region<'tcx>>,
 }
 
 impl<'tcx> CapturedPlace<'tcx> {
@@ -178,7 +164,7 @@ fn to_symbol(&self, tcx: TyCtxt<'tcx>) -> Symbol {
                         write!(
                             &mut symbol,
                             "__{}",
-                            def.variants[variant].fields[idx as usize].ident.name.as_str(),
+                            def.variants[variant].fields[idx as usize].name.as_str(),
                         )
                         .unwrap();
                     }
@@ -287,7 +273,7 @@ pub fn is_ancestor_or_same_capture(
 /// for a particular capture as well as identifying the part of the source code
 /// that triggered this capture to occur.
 #[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, TypeFoldable, HashStable)]
-pub struct CaptureInfo<'tcx> {
+pub struct CaptureInfo {
     /// Expr Id pointing to use that resulted in selecting the current capture kind
     ///
     /// Eg:
@@ -325,7 +311,7 @@ pub struct CaptureInfo<'tcx> {
     pub path_expr_id: Option<hir::HirId>,
 
     /// Capture mode that was selected
-    pub capture_kind: UpvarCapture<'tcx>,
+    pub capture_kind: UpvarCapture,
 }
 
 pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tcx>) -> String {
@@ -344,7 +330,7 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc
                     curr_string = format!(
                         "{}.{}",
                         curr_string,
-                        def.variants[variant].fields[idx as usize].ident.name.as_str()
+                        def.variants[variant].fields[idx as usize].name.as_str()
                     );
                 }
                 ty::Tuple(_) => {
index 27e22ccac02a7fb7c771700ada2318eeace3a841..75705d40a6c80209b9904df4ecf02ec12652bbca 100644 (file)
@@ -42,9 +42,7 @@ pub fn from_opt_const_arg_anon_const(
     ) -> &'tcx Self {
         debug!("Const::from_anon_const(def={:?})", def);
 
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
-
-        let body_id = match tcx.hir().get(hir_id) {
+        let body_id = match tcx.hir().get_by_def_id(def.did) {
             hir::Node::AnonConst(ac) => ac.body,
             _ => span_bug!(
                 tcx.def_span(def.did.to_def_id()),
@@ -61,7 +59,7 @@ pub fn from_opt_const_arg_anon_const(
             None => tcx.mk_const(ty::Const {
                 val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                     def: def.to_global(),
-                    substs_: None,
+                    substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
                     promoted: None,
                 }),
                 ty,
@@ -153,14 +151,14 @@ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
                 tcx.mk_const(ty::Const {
                     val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                         def: ty::WithOptConstParam::unknown(def_id).to_global(),
-                        substs_: Some(substs),
+                        substs,
                         promoted: None,
                     }),
                     ty,
                 })
             }
         };
-        debug_assert!(!ret.has_free_regions(tcx));
+        debug_assert!(!ret.has_free_regions());
         ret
     }
 
@@ -260,8 +258,7 @@ pub fn eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u64 {
 }
 
 pub fn const_param_default<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Const<'tcx> {
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-    let default_def_id = match tcx.hir().get(hir_id) {
+    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 7188eed5445516bd28a58d089b47a175df2f84ab..af7c2c5cb4cff0637d75d190d0d4a14c13f07a29 100644 (file)
@@ -1,5 +1,4 @@
 use std::convert::TryInto;
-use std::fmt;
 
 use crate::mir::interpret::{AllocId, ConstValue, Scalar};
 use crate::mir::Promoted;
 
 use super::ScalarInt;
 /// An unevaluated, potentially generic, constant.
-///
-/// If `substs_` is `None` it means that this anon const
-/// still has its default substs.
-///
-/// We check for all possible substs in `fn default_anon_const_substs`,
-/// so refer to that check for more info.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
 #[derive(Hash, HashStable)]
 pub struct Unevaluated<'tcx, P = Option<Promoted>> {
     pub def: ty::WithOptConstParam<DefId>,
-    pub substs_: Option<SubstsRef<'tcx>>,
+    pub substs: SubstsRef<'tcx>,
     pub promoted: P,
 }
 
@@ -31,34 +24,21 @@ impl<'tcx> Unevaluated<'tcx> {
     #[inline]
     pub fn shrink(self) -> Unevaluated<'tcx, ()> {
         debug_assert_eq!(self.promoted, None);
-        Unevaluated { def: self.def, substs_: self.substs_, promoted: () }
+        Unevaluated { def: self.def, substs: self.substs, promoted: () }
     }
 }
 
 impl<'tcx> Unevaluated<'tcx, ()> {
     #[inline]
     pub fn expand(self) -> Unevaluated<'tcx> {
-        Unevaluated { def: self.def, substs_: self.substs_, promoted: None }
+        Unevaluated { def: self.def, substs: self.substs, promoted: None }
     }
 }
 
 impl<'tcx, P: Default> Unevaluated<'tcx, P> {
     #[inline]
     pub fn new(def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>) -> Unevaluated<'tcx, P> {
-        Unevaluated { def, substs_: Some(substs), promoted: Default::default() }
-    }
-}
-
-impl<'tcx, P: Default + PartialEq + fmt::Debug> Unevaluated<'tcx, P> {
-    #[inline]
-    pub fn substs(self, tcx: TyCtxt<'tcx>) -> SubstsRef<'tcx> {
-        self.substs_.unwrap_or_else(|| {
-            // We must not use the parents default substs for promoted constants
-            // as that can result in incorrect substs and calls the `default_anon_const_substs`
-            // for something that might not actually be a constant.
-            debug_assert_eq!(self.promoted, Default::default());
-            tcx.default_anon_const_substs(self.def.did)
-        })
+        Unevaluated { def, substs, promoted: Default::default() }
     }
 }
 
@@ -173,7 +153,7 @@ pub(super) fn try_eval(
             let param_env_and = if param_env_and.needs_infer() {
                 tcx.param_env(unevaluated.def.did).and(ty::Unevaluated {
                     def: unevaluated.def,
-                    substs_: Some(InternalSubsts::identity_for_item(tcx, unevaluated.def.did)),
+                    substs: InternalSubsts::identity_for_item(tcx, unevaluated.def.did),
                     promoted: unevaluated.promoted,
                 })
             } else {
index dd571e29bf69506401adfff0dd8029a16615f4f3..9f38421294d9e56c39cb819ffdccb28ef862cafc 100644 (file)
@@ -1461,8 +1461,7 @@ pub fn is_suitable_region(self, region: Region<'tcx>) -> Option<FreeRegionInfo>
             _ => return None, // not a free region
         };
 
-        let hir_id = self.hir().local_def_id_to_hir_id(suitable_region_binding_scope);
-        let is_impl_item = match self.hir().find(hir_id) {
+        let is_impl_item = match self.hir().find_by_def_id(suitable_region_binding_scope) {
             Some(Node::Item(..) | Node::TraitItem(..)) => false,
             Some(Node::ImplItem(..)) => {
                 self.is_bound_region_in_impl_item(suitable_region_binding_scope)
@@ -1495,8 +1494,7 @@ pub fn return_type_impl_or_dyn_traits(
 
     pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> {
         // `type_of()` will fail on these (#55796, #86483), so only allow `fn`s or closures.
-        let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
-        match self.hir().get(hir_id) {
+        match self.hir().get_by_def_id(scope_def_id) {
             Node::Item(&hir::Item { kind: ItemKind::Fn(..), .. }) => {}
             Node::TraitItem(&hir::TraitItem { kind: TraitItemKind::Fn(..), .. }) => {}
             Node::ImplItem(&hir::ImplItem { kind: ImplItemKind::Fn(..), .. }) => {}
@@ -1510,6 +1508,7 @@ pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx
                 let sig = ret_ty.fn_sig(self);
                 let output = self.erase_late_bound_regions(sig.output());
                 if output.is_impl_trait() {
+                    let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
                     let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap();
                     Some((output, fn_decl.output.span()))
                 } else {
@@ -1661,7 +1660,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, TaskDeps};
+    use crate::dep_graph::{DepKind, TaskDepsRef};
     use crate::ty::query;
     use rustc_data_structures::sync::{self, Lock};
     use rustc_data_structures::thin_vec::ThinVec;
@@ -1697,13 +1696,19 @@ pub struct ImplicitCtxt<'a, 'tcx> {
 
         /// The current dep graph task. This is used to add dependencies to queries
         /// when executing them.
-        pub task_deps: Option<&'a Lock<TaskDeps>>,
+        pub task_deps: TaskDepsRef<'a>,
     }
 
     impl<'a, 'tcx> ImplicitCtxt<'a, 'tcx> {
         pub fn new(gcx: &'tcx GlobalCtxt<'tcx>) -> Self {
             let tcx = TyCtxt { gcx };
-            ImplicitCtxt { tcx, query: None, diagnostics: None, layout_depth: 0, task_deps: None }
+            ImplicitCtxt {
+                tcx,
+                query: None,
+                diagnostics: None,
+                layout_depth: 0,
+                task_deps: TaskDepsRef::Ignore,
+            }
         }
     }
 
@@ -2452,7 +2457,7 @@ pub fn mk_place_downcast(
     ) -> Place<'tcx> {
         self.mk_place_elem(
             place,
-            PlaceElem::Downcast(Some(adt_def.variants[variant_index].ident.name), variant_index),
+            PlaceElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index),
         )
     }
 
@@ -2820,7 +2825,8 @@ pub fn provide(providers: &mut ty::query::Providers) {
     providers.in_scope_traits_map =
         |tcx, id| tcx.hir_crate(()).owners[id].as_ref().map(|owner_info| &owner_info.trait_map);
     providers.resolutions = |tcx, ()| &tcx.untracked_resolutions;
-    providers.module_exports = |tcx, id| tcx.resolutions(()).export_map.get(&id).map(|v| &v[..]);
+    providers.module_reexports =
+        |tcx, id| tcx.resolutions(()).reexport_map.get(&id).map(|v| &v[..]);
     providers.crate_name = |tcx, id| {
         assert_eq!(id, LOCAL_CRATE);
         tcx.crate_name
index 0d290752e8fd81c130f4b06040ae3abbdd71800a..ef4f77c8a69e11ae06ae0193e9e8891850316242 100644 (file)
@@ -21,9 +21,7 @@ pub fn erase_regions<T>(self, value: T) -> T
         T: TypeFoldable<'tcx>,
     {
         // If there's nothing to erase avoid performing the query at all
-        if !value
-            .has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_POTENTIAL_FREE_REGIONS)
-        {
+        if !value.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND | TypeFlags::HAS_FREE_REGIONS) {
             return value;
         }
         debug!("erase_regions({:?})", value);
index df6e739dc201180229ad422fb232152a57448d75..5bb687512f3cbe5dbaa4b578e39d7a9ba15dbd09 100644 (file)
@@ -869,7 +869,7 @@ fn point_at_associated_type(
         // When `body_owner` is an `impl` or `trait` item, look in its associated types for
         // `expected` and point at it.
         let parent_id = self.hir().get_parent_item(hir_id);
-        let item = self.hir().find(parent_id);
+        let item = self.hir().find_by_def_id(parent_id);
         debug!("expected_projection parent item {:?}", item);
         match item {
             Some(hir::Node::Item(hir::Item { kind: hir::ItemKind::Trait(.., items), .. })) => {
index 04011552e31edc61cc5bb17852dd76f26787d722..daf9156a15f347f047500450a608ca88dec54013 100644 (file)
@@ -143,6 +143,18 @@ pub fn simplify_type(
 }
 
 impl<D: Copy + Debug + Ord + Eq> SimplifiedTypeGen<D> {
+    pub fn def(self) -> Option<D> {
+        match self {
+            AdtSimplifiedType(d)
+            | ForeignSimplifiedType(d)
+            | TraitSimplifiedType(d)
+            | ClosureSimplifiedType(d)
+            | GeneratorSimplifiedType(d)
+            | OpaqueSimplifiedType(d) => Some(d),
+            _ => None,
+        }
+    }
+
     pub fn map_def<U, F>(self, map: F) -> SimplifiedTypeGen<U>
     where
         F: Fn(D) -> U,
index 617c522ac81971e27be38caa66622e34a1e361cc..b6e673983fd4ed32d6bb7896c38d8f8ce7e78114 100644 (file)
@@ -97,7 +97,7 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
             &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
 
             &ty::Param(_) => {
-                self.add_flags(TypeFlags::HAS_KNOWN_TY_PARAM);
+                self.add_flags(TypeFlags::HAS_TY_PARAM);
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
             }
 
@@ -298,7 +298,7 @@ fn add_const(&mut self, c: &ty::Const<'_>) {
                 self.add_bound_var(debruijn);
             }
             ty::ConstKind::Param(_) => {
-                self.add_flags(TypeFlags::HAS_KNOWN_CT_PARAM);
+                self.add_flags(TypeFlags::HAS_CT_PARAM);
                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
             }
             ty::ConstKind::Placeholder(_) => {
@@ -311,23 +311,7 @@ fn add_const(&mut self, c: &ty::Const<'_>) {
     }
 
     fn add_unevaluated_const<P>(&mut self, ct: ty::Unevaluated<'_, P>) {
-        // The generic arguments of unevaluated consts are a bit special,
-        // see the `rustc-dev-guide` for more information.
-        //
-        // FIXME(@lcnr): Actually add a link here.
-        if let Some(substs) = ct.substs_ {
-            // If they are available, we treat them as ordinary generic arguments.
-            self.add_substs(substs);
-        } else {
-            // Otherwise, we add `HAS_UNKNOWN_DEFAULT_CONST_SUBSTS` to signify
-            // that our const may potentially refer to generic parameters.
-            //
-            // Note that depending on which generic parameters are actually
-            // used in this constant, we may not actually refer to any generic
-            // parameters at all.
-            self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
-            self.add_flags(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS);
-        }
+        self.add_substs(ct.substs);
         self.add_flags(TypeFlags::HAS_CT_PROJECTION);
     }
 
index f5be8b21e8acae5b7103553d4bec742fccfc66a3..3133cdfdd7a7211222a0e9336aa4240a798e0121 100644 (file)
@@ -95,15 +95,9 @@ fn has_escaping_bound_vars(&self) -> bool {
         self.has_vars_bound_at_or_above(ty::INNERMOST)
     }
 
-    fn definitely_has_type_flags(&self, tcx: TyCtxt<'tcx>, flags: TypeFlags) -> bool {
-        self.visit_with(&mut HasTypeFlagsVisitor { tcx: Some(tcx), flags }).break_value()
-            == Some(FoundFlags)
-    }
-
     #[instrument(level = "trace")]
     fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        self.visit_with(&mut HasTypeFlagsVisitor { tcx: None, flags }).break_value()
-            == Some(FoundFlags)
+        self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags)
     }
     fn has_projections(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_PROJECTION)
@@ -114,18 +108,8 @@ fn has_opaque_types(&self) -> bool {
     fn references_error(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_ERROR)
     }
-    fn potentially_has_param_types_or_consts(&self) -> bool {
-        self.has_type_flags(
-            TypeFlags::HAS_KNOWN_TY_PARAM
-                | TypeFlags::HAS_KNOWN_CT_PARAM
-                | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS,
-        )
-    }
-    fn definitely_has_param_types_or_consts(&self, tcx: TyCtxt<'tcx>) -> bool {
-        self.definitely_has_type_flags(
-            tcx,
-            TypeFlags::HAS_KNOWN_TY_PARAM | TypeFlags::HAS_KNOWN_CT_PARAM,
-        )
+    fn has_param_types_or_consts(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_CT_PARAM)
     }
     fn has_infer_regions(&self) -> bool {
         self.has_type_flags(TypeFlags::HAS_RE_INFER)
@@ -146,18 +130,13 @@ fn has_placeholders(&self) -> bool {
                 | TypeFlags::HAS_CT_PLACEHOLDER,
         )
     }
-    fn potentially_needs_subst(&self) -> bool {
-        self.has_type_flags(
-            TypeFlags::KNOWN_NEEDS_SUBST | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS,
-        )
-    }
-    fn definitely_needs_subst(&self, tcx: TyCtxt<'tcx>) -> bool {
-        self.definitely_has_type_flags(tcx, TypeFlags::KNOWN_NEEDS_SUBST)
+    fn needs_subst(&self) -> bool {
+        self.has_type_flags(TypeFlags::NEEDS_SUBST)
     }
     /// "Free" regions in this context means that it has any region
     /// that is not (a) erased or (b) late-bound.
-    fn has_free_regions(&self, tcx: TyCtxt<'tcx>) -> bool {
-        self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS)
+    fn has_free_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
     }
 
     fn has_erased_regions(&self) -> bool {
@@ -165,25 +144,15 @@ fn has_erased_regions(&self) -> bool {
     }
 
     /// True if there are any un-erased free regions.
-    fn has_erasable_regions(&self, tcx: TyCtxt<'tcx>) -> bool {
-        self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_REGIONS)
-    }
-
-    /// Indicates whether this value definitely references only 'global'
-    /// generic parameters that are the same regardless of what fn we are
-    /// in. This is used for caching.
-    ///
-    /// Note that this function is pessimistic and may incorrectly return
-    /// `false`.
-    fn is_known_global(&self) -> bool {
-        !self.has_type_flags(TypeFlags::HAS_POTENTIAL_FREE_LOCAL_NAMES)
+    fn has_erasable_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
     }
 
     /// Indicates whether this value references only 'global'
     /// generic parameters that are the same regardless of what fn we are
     /// in. This is used for caching.
-    fn is_global(&self, tcx: TyCtxt<'tcx>) -> bool {
-        !self.definitely_has_type_flags(tcx, TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES)
+    fn is_global(&self) -> bool {
+        !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
     }
 
     /// True if there are any late-bound regions
@@ -361,17 +330,6 @@ fn try_fold_mir_const(
 
 pub trait TypeVisitor<'tcx>: Sized {
     type BreakTy = !;
-    /// Supplies the `tcx` for an unevaluated anonymous constant in case its default substs
-    /// are not yet supplied.
-    ///
-    /// Returning `None` for this method is only recommended if the `TypeVisitor`
-    /// does not care about default anon const substs, as it ignores generic parameters,
-    /// and fetching the default substs would cause a query cycle.
-    ///
-    /// For visitors which return `None` we completely skip the default substs in `ty::Unevaluated::super_visit_with`.
-    /// This means that incorrectly returning `None` can very quickly lead to ICE or other critical bugs, so be careful and
-    /// try to return an actual `tcx` if possible.
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>>;
 
     fn visit_binder<T: TypeFoldable<'tcx>>(
         &mut self,
@@ -488,8 +446,7 @@ pub fn any_free_region_meets(
         value: &impl TypeFoldable<'tcx>,
         callback: impl FnMut(ty::Region<'tcx>) -> bool,
     ) -> bool {
-        struct RegionVisitor<'tcx, F> {
-            tcx: TyCtxt<'tcx>,
+        struct RegionVisitor<F> {
             /// The index of a binder *just outside* the things we have
             /// traversed. If we encounter a bound region bound by this
             /// binder or one outer to it, it appears free. Example:
@@ -511,16 +468,12 @@ struct RegionVisitor<'tcx, F> {
             callback: F,
         }
 
-        impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<'tcx, F>
+        impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor<F>
         where
             F: FnMut(ty::Region<'tcx>) -> bool,
         {
             type BreakTy = ();
 
-            fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-                Some(self.tcx)
-            }
-
             fn visit_binder<T: TypeFoldable<'tcx>>(
                 &mut self,
                 t: &Binder<'tcx, T>,
@@ -548,7 +501,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
 
             fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                 // We're only interested in types involving regions
-                if ty.flags().intersects(TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
+                if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
                     ty.super_visit_with(self)
                 } else {
                     ControlFlow::CONTINUE
@@ -556,9 +509,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             }
         }
 
-        value
-            .visit_with(&mut RegionVisitor { tcx: self, outer_index: ty::INNERMOST, callback })
-            .is_break()
+        value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
     }
 }
 
@@ -897,7 +848,7 @@ fn collect_late_bound_regions<T>(
     where
         T: TypeFoldable<'tcx>,
     {
-        let mut collector = LateBoundRegionsCollector::new(self, just_constraint);
+        let mut collector = LateBoundRegionsCollector::new(just_constraint);
         let result = value.as_ref().skip_binder().visit_with(&mut collector);
         assert!(result.is_continue()); // should never have stopped early
         collector.regions
@@ -964,11 +915,6 @@ pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self {
 impl<'tcx> TypeVisitor<'tcx> for ValidateBoundVars<'tcx> {
     type BreakTy = ();
 
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        // Anonymous constants do not contain bound vars in their substs by default.
-        None
-    }
-
     fn visit_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: &Binder<'tcx, T>,
@@ -1183,11 +1129,6 @@ struct HasEscapingVarsVisitor {
 impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
     type BreakTy = FoundEscapingVars;
 
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        // Anonymous constants do not contain bound vars in their substs by default.
-        None
-    }
-
     fn visit_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: &Binder<'tcx, T>,
@@ -1252,35 +1193,32 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Sel
 struct FoundFlags;
 
 // FIXME: Optimize for checking for infer flags
-struct HasTypeFlagsVisitor<'tcx> {
-    tcx: Option<TyCtxt<'tcx>>,
+struct HasTypeFlagsVisitor {
     flags: ty::TypeFlags,
 }
 
-impl<'tcx> std::fmt::Debug for HasTypeFlagsVisitor<'tcx> {
+impl std::fmt::Debug for HasTypeFlagsVisitor {
     fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         self.flags.fmt(fmt)
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor<'tcx> {
+impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
     type BreakTy = FoundFlags;
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        bug!("we shouldn't call this method as we manually look at ct substs");
-    }
 
     #[inline]
     #[instrument(level = "trace")]
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        let flags = t.flags();
-        trace!(t.flags=?t.flags());
-        if flags.intersects(self.flags) {
+    fn visit_ty(&mut self, t: Ty<'_>) -> ControlFlow<Self::BreakTy> {
+        debug!(
+            "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}",
+            t,
+            t.flags(),
+            self.flags
+        );
+        if t.flags().intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
-            match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
-                true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, t),
-                _ => ControlFlow::CONTINUE,
-            }
+            ControlFlow::CONTINUE
         }
     }
 
@@ -1304,10 +1242,7 @@ fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
-            match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
-                true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, c),
-                _ => ControlFlow::CONTINUE,
-            }
+            ControlFlow::CONTINUE
         }
     }
 
@@ -1319,128 +1254,28 @@ fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<
         if flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
         } else {
-            match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
-                true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, uv),
-                _ => ControlFlow::CONTINUE,
-            }
+            ControlFlow::CONTINUE
         }
     }
 
     #[inline]
     #[instrument(level = "trace")]
     fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
-        let flags = predicate.inner.flags;
-        trace!(predicate.flags=?flags);
-        if flags.intersects(self.flags) {
+        debug!(
+            "HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
+            predicate, predicate.inner.flags, self.flags
+        );
+        if predicate.inner.flags.intersects(self.flags) {
             ControlFlow::Break(FoundFlags)
-        } else {
-            match flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
-                true if self.tcx.is_some() => UnknownConstSubstsVisitor::search(&self, predicate),
-                _ => ControlFlow::CONTINUE,
-            }
-        }
-    }
-}
-
-struct UnknownConstSubstsVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    flags: ty::TypeFlags,
-}
-
-impl<'tcx> UnknownConstSubstsVisitor<'tcx> {
-    /// This is fairly cold and we don't want to
-    /// bloat the size of the `HasTypeFlagsVisitor`.
-    #[inline(never)]
-    pub fn search<T: TypeFoldable<'tcx>>(
-        visitor: &HasTypeFlagsVisitor<'tcx>,
-        v: T,
-    ) -> ControlFlow<FoundFlags> {
-        if visitor.flags.intersects(TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS) {
-            v.super_visit_with(&mut UnknownConstSubstsVisitor {
-                tcx: visitor.tcx.unwrap(),
-                flags: visitor.flags,
-            })
         } else {
             ControlFlow::CONTINUE
         }
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for UnknownConstSubstsVisitor<'tcx> {
-    type BreakTy = FoundFlags;
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        bug!("we shouldn't call this method as we manually look at ct substs");
-    }
-
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if t.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
-            t.super_visit_with(self)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    #[inline]
-    fn visit_unevaluated_const(&mut self, uv: ty::Unevaluated<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if uv.substs_.is_none() {
-            self.tcx
-                .default_anon_const_substs(uv.def.did)
-                .visit_with(&mut HasTypeFlagsVisitor { tcx: Some(self.tcx), flags: self.flags })
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-
-    #[inline]
-    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if predicate.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
-            predicate.super_visit_with(self)
-        } else {
-            ControlFlow::CONTINUE
-        }
-    }
-}
-
-impl<'tcx> TyCtxt<'tcx> {
-    /// This is a HACK(const_generics) and should probably not be needed.
-    /// Might however be perf relevant, so who knows.
-    ///
-    /// FIXME(@lcnr): explain this function a bit more
-    pub fn expose_default_const_substs<T: TypeFoldable<'tcx>>(self, v: T) -> T {
-        v.fold_with(&mut ExposeDefaultConstSubstsFolder { tcx: self })
-    }
-}
-
-struct ExposeDefaultConstSubstsFolder<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> TypeFolder<'tcx> for ExposeDefaultConstSubstsFolder<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if ty.flags().intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
-            ty.super_fold_with(self)
-        } else {
-            ty
-        }
-    }
-
-    fn fold_predicate(&mut self, pred: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
-        if pred.inner.flags.intersects(TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS) {
-            pred.super_fold_with(self)
-        } else {
-            pred
-        }
-    }
-}
-
 /// Collects all the late-bound regions at the innermost binding level
 /// into a hash set.
-struct LateBoundRegionsCollector<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct LateBoundRegionsCollector {
     current_index: ty::DebruijnIndex,
     regions: FxHashSet<ty::BoundRegionKind>,
 
@@ -1454,10 +1289,9 @@ struct LateBoundRegionsCollector<'tcx> {
     just_constrained: bool,
 }
 
-impl<'tcx> LateBoundRegionsCollector<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, just_constrained: bool) -> Self {
+impl LateBoundRegionsCollector {
+    fn new(just_constrained: bool) -> Self {
         LateBoundRegionsCollector {
-            tcx,
             current_index: ty::INNERMOST,
             regions: Default::default(),
             just_constrained,
@@ -1465,11 +1299,7 @@ fn new(tcx: TyCtxt<'tcx>, just_constrained: bool) -> Self {
     }
 }
 
-impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector<'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.tcx)
-    }
-
+impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
     fn visit_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: &Binder<'tcx, T>,
index 1c3a01e2cfadf99aa1017fe3a38bf5696b908a3a..0bd96f8f865fcaa33f4882a1c1f5535802300765 100644 (file)
@@ -31,6 +31,13 @@ pub fn to_ord(&self) -> ast::ParamKindOrd {
             GenericParamDefKind::Const { .. } => ast::ParamKindOrd::Const,
         }
     }
+
+    pub fn is_ty_or_const(&self) -> bool {
+        match self {
+            GenericParamDefKind::Lifetime => false,
+            GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => true,
+        }
+    }
 }
 
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
index 9f47ed89f13fa65781888bd703e9aa3b5ba9f7ed..00ce15bea3f28cb54acf0bfaf65f58d9b69d7b3a 100644 (file)
@@ -6,6 +6,7 @@
 use crate::ty;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::HashingControls;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_query_system::ich::StableHashingContext;
 use std::cell::RefCell;
@@ -17,12 +18,12 @@ impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for &'tcx ty::List<T>
 {
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
         thread_local! {
-            static CACHE: RefCell<FxHashMap<(usize, usize), Fingerprint>> =
+            static CACHE: RefCell<FxHashMap<(usize, usize, HashingControls), Fingerprint>> =
                 RefCell::new(Default::default());
         }
 
         let hash = CACHE.with(|cache| {
-            let key = (self.as_ptr() as usize, self.len());
+            let key = (self.as_ptr() as usize, self.len(), hcx.hashing_controls());
             if let Some(&hash) = cache.borrow().get(&key) {
                 return hash;
             }
index f31c7dd743d8290da2f303b89f894a815cfa7f01..55807874705f6253e603e4362e9712f01c3d5c9d 100644 (file)
@@ -1,6 +1,6 @@
 use crate::ty::context::TyCtxt;
 use crate::ty::{DefId, DefIdTree};
-use rustc_hir::CRATE_HIR_ID;
+use rustc_span::def_id::CRATE_DEF_ID;
 use smallvec::SmallVec;
 use std::mem;
 use std::sync::Arc;
@@ -43,8 +43,8 @@ pub fn empty() -> DefIdForest {
     /// Creates a forest consisting of a single tree representing the entire
     /// crate.
     #[inline]
-    pub fn full(tcx: TyCtxt<'tcx>) -> DefIdForest {
-        DefIdForest::from_id(tcx.hir().local_def_id(CRATE_HIR_ID).to_def_id())
+    pub fn full() -> DefIdForest {
+        DefIdForest::from_id(CRATE_DEF_ID.to_def_id())
     }
 
     /// Creates a forest containing a `DefId` and all its descendants.
@@ -96,7 +96,7 @@ pub fn intersection<I>(tcx: TyCtxt<'tcx>, iter: I) -> DefIdForest
         let mut ret: SmallVec<[_; 1]> = if let Some(first) = iter.next() {
             SmallVec::from_slice(first.as_slice())
         } else {
-            return DefIdForest::full(tcx);
+            return DefIdForest::full();
         };
 
         let mut next_ret: SmallVec<[_; 1]> = SmallVec::new();
index 77d82ee6eae6ffab0c06633f0d3cfc36f7f5fb68..167a54e42a0156bdd1b9e08c0fb128624325ee14 100644 (file)
@@ -205,7 +205,7 @@ pub(crate) fn type_uninhabited_from<'tcx>(
     match *ty.kind() {
         Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
 
-        Never => DefIdForest::full(tcx),
+        Never => DefIdForest::full(),
 
         Tuple(ref tys) => DefIdForest::union(
             tcx,
index 196fe7ce1b6ac46a2e6fe1c605eb197b5ba38390..caf33fa5d213b49559068fd8070e9ced4c50a42a 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_session::{config::OptLevel, DataTypeKind, FieldInfo, SizeKind, VariantInfo};
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::call::{
     ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, Conv, FnAbi, PassMode, Reg, RegKind,
@@ -1769,9 +1769,7 @@ fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) {
         // Ignore layouts that are done with non-empty environments or
         // non-monomorphic layouts, as the user only wants to see the stuff
         // resulting from the final codegen session.
-        if layout.ty.definitely_has_param_types_or_consts(self.tcx)
-            || !self.param_env.caller_bounds().is_empty()
-        {
+        if layout.ty.has_param_types_or_consts() || !self.param_env.caller_bounds().is_empty() {
             return;
         }
 
@@ -1810,7 +1808,7 @@ fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) {
         let adt_kind = adt_def.adt_kind();
         let adt_packed = adt_def.repr.pack.is_some();
 
-        let build_variant_info = |n: Option<Ident>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
+        let build_variant_info = |n: Option<Symbol>, flds: &[Symbol], layout: TyAndLayout<'tcx>| {
             let mut min_size = Size::ZERO;
             let field_info: Vec<_> = flds
                 .iter()
@@ -1845,15 +1843,15 @@ fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) {
                 if !adt_def.variants.is_empty() && layout.fields != FieldsShape::Primitive {
                     debug!(
                         "print-type-size `{:#?}` variant {}",
-                        layout, adt_def.variants[index].ident
+                        layout, adt_def.variants[index].name
                     );
                     let variant_def = &adt_def.variants[index];
-                    let fields: Vec<_> = variant_def.fields.iter().map(|f| f.ident.name).collect();
+                    let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
                     record(
                         adt_kind.into(),
                         adt_packed,
                         None,
-                        vec![build_variant_info(Some(variant_def.ident), &fields, layout)],
+                        vec![build_variant_info(Some(variant_def.name), &fields, layout)],
                     );
                 } else {
                     // (This case arises for *empty* enums; so give it
@@ -1872,10 +1870,9 @@ fn record_layout_for_printing_outlined(&self, layout: TyAndLayout<'tcx>) {
                     .variants
                     .iter_enumerated()
                     .map(|(i, variant_def)| {
-                        let fields: Vec<_> =
-                            variant_def.fields.iter().map(|f| f.ident.name).collect();
+                        let fields: Vec<_> = variant_def.fields.iter().map(|f| f.name).collect();
                         build_variant_info(
-                            Some(variant_def.ident),
+                            Some(variant_def.name),
                             &fields,
                             layout.for_variant(self, i),
                         )
@@ -1937,7 +1934,7 @@ pub fn compute(
                 let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
                 match tail.kind() {
                     ty::Param(_) | ty::Projection(_) => {
-                        debug_assert!(tail.definitely_has_param_types_or_consts(tcx));
+                        debug_assert!(tail.has_param_types_or_consts());
                         Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
                     }
                     _ => bug!(
index 78ccfbd5e8cdcd42b1ab2587a564119d553de641..ceb8795a1a826ceecd12179dfbdf2cdb021d7fdd 100644 (file)
@@ -19,7 +19,8 @@
 pub use generics::*;
 pub use vtable::*;
 
-use crate::hir::exports::ExportMap;
+use crate::metadata::ModChild;
+use crate::middle::privacy::AccessLevels;
 use crate::mir::{Body, GeneratorLayout};
 use crate::traits::{self, Reveal};
 use crate::ty;
@@ -56,8 +57,8 @@
 pub use self::closure::{
     is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo,
     CapturedPlace, ClosureKind, MinCaptureInformationMap, MinCaptureList,
-    RootVariableMinCaptureList, UpvarBorrow, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap,
-    UpvarPath, CAPTURE_STRUCT_LOCAL,
+    RootVariableMinCaptureList, UpvarCapture, UpvarCaptureMap, UpvarId, UpvarListMap, UpvarPath,
+    CAPTURE_STRUCT_LOCAL,
 };
 pub use self::consts::{Const, ConstInt, ConstKind, InferConst, ScalarInt, Unevaluated, ValTree};
 pub use self::context::{
@@ -123,10 +124,11 @@ pub struct ResolverOutputs {
     pub definitions: rustc_hir::definitions::Definitions,
     pub cstore: Box<CrateStoreDyn>,
     pub visibilities: FxHashMap<LocalDefId, Visibility>,
+    pub access_levels: AccessLevels,
     pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
     pub maybe_unused_trait_imports: FxHashSet<LocalDefId>,
     pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
-    pub export_map: ExportMap,
+    pub reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
     pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
     /// Extern prelude entries. The value is `true` if the entry was introduced
     /// via `extern crate` item and not `--extern` option or compiler built-in.
@@ -1415,7 +1417,7 @@ pub fn and<T: TypeFoldable<'tcx>>(self, value: T) -> ParamEnvAnd<'tcx, T> {
             Reveal::UserFacing => ParamEnvAnd { param_env: self, value },
 
             Reveal::All => {
-                if value.is_known_global() {
+                if value.is_global() {
                     ParamEnvAnd { param_env: self.without_caller_bounds(), value }
                 } else {
                     ParamEnvAnd { param_env: self, value }
@@ -1502,8 +1504,7 @@ pub struct VariantDef {
     /// If this variant is a struct variant, then this is `None`.
     pub ctor_def_id: Option<DefId>,
     /// Variant or struct name.
-    #[stable_hasher(project(name))]
-    pub ident: Ident,
+    pub name: Symbol,
     /// Discriminant of this variant.
     pub discr: VariantDiscr,
     /// Fields of this variant.
@@ -1532,7 +1533,7 @@ impl VariantDef {
     /// If someone speeds up attribute loading to not be a performance concern, they can
     /// remove this hack and use the constructor `DefId` everywhere.
     pub fn new(
-        ident: Ident,
+        name: Symbol,
         variant_did: Option<DefId>,
         ctor_def_id: Option<DefId>,
         discr: VariantDiscr,
@@ -1544,9 +1545,9 @@ pub fn new(
         is_field_list_non_exhaustive: bool,
     ) -> Self {
         debug!(
-            "VariantDef::new(ident = {:?}, variant_did = {:?}, ctor_def_id = {:?}, discr = {:?},
+            "VariantDef::new(name = {:?}, variant_did = {:?}, ctor_def_id = {:?}, discr = {:?},
              fields = {:?}, ctor_kind = {:?}, adt_kind = {:?}, parent_did = {:?})",
-            ident, variant_did, ctor_def_id, discr, fields, ctor_kind, adt_kind, parent_did,
+            name, variant_did, ctor_def_id, discr, fields, ctor_kind, adt_kind, parent_did,
         );
 
         let mut flags = VariantFlags::NO_VARIANT_FLAGS;
@@ -1561,7 +1562,7 @@ pub fn new(
         VariantDef {
             def_id: variant_did.unwrap_or(parent_did),
             ctor_def_id,
-            ident,
+            name,
             discr,
             fields,
             ctor_kind,
@@ -1580,6 +1581,11 @@ pub fn is_field_list_non_exhaustive(&self) -> bool {
     pub fn is_recovered(&self) -> bool {
         self.flags.intersects(VariantFlags::IS_RECOVERED)
     }
+
+    /// Computes the `Ident` of this variant by looking up the `Span`
+    pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
+        Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
+    }
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
@@ -1598,8 +1604,7 @@ pub enum VariantDiscr {
 #[derive(Debug, HashStable, TyEncodable, TyDecodable)]
 pub struct FieldDef {
     pub did: DefId,
-    #[stable_hasher(project(name))]
-    pub ident: Ident,
+    pub name: Symbol,
     pub vis: Visibility,
 }
 
@@ -1774,6 +1779,11 @@ impl<'tcx> FieldDef {
     pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
         tcx.type_of(self.did).subst(tcx, subst)
     }
+
+    /// Computes the `Ident` of this variant by looking up the `Span`
+    pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
+        Ident::new(self.name, tcx.def_ident_span(self.did).unwrap())
+    }
 }
 
 pub type Attributes<'tcx> = &'tcx [ast::Attribute];
@@ -1890,7 +1900,10 @@ pub fn field_index(self, hir_id: hir::HirId, typeck_results: &TypeckResults<'_>)
     }
 
     pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option<usize> {
-        variant.fields.iter().position(|field| self.hygienic_eq(ident, field.ident, variant.def_id))
+        variant
+            .fields
+            .iter()
+            .position(|field| self.hygienic_eq(ident, field.ident(self), variant.def_id))
     }
 
     /// Returns `true` if the impls are the same polarity and the trait either
@@ -2069,8 +2082,7 @@ pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
     /// with the name of the crate containing the impl.
     pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
         if let Some(impl_did) = impl_did.as_local() {
-            let hir_id = self.hir().local_def_id_to_hir_id(impl_did);
-            Ok(self.hir().span(hir_id))
+            Ok(self.def_span(impl_did))
         } else {
             Err(self.crate_name(impl_did.krate))
         }
@@ -2117,7 +2129,7 @@ pub fn is_object_safe(self, key: DefId) -> bool {
 /// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition.
 pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId> {
     let def_id = def_id.as_local()?;
-    if let Node::Item(item) = tcx.hir().get(tcx.hir().local_def_id_to_hir_id(def_id)) {
+    if let Node::Item(item) = tcx.hir().get_by_def_id(def_id) {
         if let hir::ItemKind::OpaqueTy(ref opaque_ty) = item.kind {
             return match opaque_ty.origin {
                 hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
index 94127a144dfef5e55e3faf7a3597c744249b3169..7b5905fddc9e53329e7c81b9f016c61e24b68bf3 100644 (file)
@@ -188,6 +188,11 @@ 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
index 47a9234419c2d9ca5c066bbf5dba383ae1c915d4..94cd650e39e6f2a75466dffd9374321b2018a20e 100644 (file)
@@ -458,7 +458,7 @@ fn try_print_visible_def_path_recur(
                 // that's public and whose identifier isn't `_`.
                 let reexport = self
                     .tcx()
-                    .item_children(visible_parent)
+                    .module_children(visible_parent)
                     .iter()
                     .filter(|child| child.res.opt_def_id() == Some(def_id))
                     .find(|child| child.vis.is_public() && child.ident.name != kw::Underscore)
@@ -671,8 +671,7 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                     p!("generator");
                     // FIXME(eddyb) should use `def_span`.
                     if let Some(did) = did.as_local() {
-                        let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
-                        let span = self.tcx().hir().span(hir_id);
+                        let span = self.tcx().def_span(did);
                         p!(write(
                             "@{}",
                             // This may end up in stderr diagnostics but it may also be emitted
@@ -708,11 +707,10 @@ fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error>
                     p!(write("closure"));
                     // FIXME(eddyb) should use `def_span`.
                     if let Some(did) = did.as_local() {
-                        let hir_id = self.tcx().hir().local_def_id_to_hir_id(did);
                         if self.tcx().sess.opts.debugging_opts.span_free_formats {
                             p!("@", print_def_path(did.to_def_id(), substs));
                         } else {
-                            let span = self.tcx().hir().span(hir_id);
+                            let span = self.tcx().def_span(did);
                             p!(write(
                                 "@{}",
                                 // This may end up in stderr diagnostics but it may also be emitted
@@ -1153,28 +1151,29 @@ macro_rules! print_underscore {
         }
 
         match ct.val {
-            ty::ConstKind::Unevaluated(uv) => {
-                if let Some(promoted) = uv.promoted {
-                    let substs = uv.substs_.unwrap();
-                    p!(print_value_path(uv.def.did, substs));
-                    p!(write("::{:?}", promoted));
-                } else {
-                    let tcx = self.tcx();
-                    match tcx.def_kind(uv.def.did) {
-                        DefKind::Static | DefKind::Const | DefKind::AssocConst => {
-                            p!(print_value_path(uv.def.did, uv.substs(tcx)))
-                        }
-                        _ => {
-                            if uv.def.is_local() {
-                                let span = tcx.def_span(uv.def.did);
-                                if let Ok(snip) = tcx.sess.source_map().span_to_snippet(span) {
-                                    p!(write("{}", snip))
-                                } else {
-                                    print_underscore!()
-                                }
+            ty::ConstKind::Unevaluated(ty::Unevaluated {
+                def,
+                substs,
+                promoted: Some(promoted),
+            }) => {
+                p!(print_value_path(def.did, substs));
+                p!(write("::{:?}", promoted));
+            }
+            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted: None }) => {
+                match self.tcx().def_kind(def.did) {
+                    DefKind::Static | DefKind::Const | DefKind::AssocConst => {
+                        p!(print_value_path(def.did, substs))
+                    }
+                    _ => {
+                        if def.is_local() {
+                            let span = self.tcx().def_span(def.did);
+                            if let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span) {
+                                p!(write("{}", snip))
                             } else {
                                 print_underscore!()
                             }
+                        } else {
+                            print_underscore!()
                         }
                     }
                 }
@@ -1419,7 +1418,7 @@ fn pretty_print_const_value(
 
             // Aggregates, printed as array/tuple/struct/variant construction syntax.
             //
-            // NB: the `potentially_has_param_types_or_consts` check ensures that we can use
+            // NB: the `has_param_types_or_consts` check ensures that we can use
             // the `destructure_const` query with an empty `ty::ParamEnv` without
             // introducing ICEs (e.g. via `layout_of`) from missing bounds.
             // E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
@@ -1427,9 +1426,7 @@ 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.potentially_has_param_types_or_consts() =>
-            {
+            (_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
                 let contents = self.tcx().destructure_const(
                     ty::ParamEnv::reveal_all()
                         .and(self.tcx().mk_const(ty::Const { val: ty::ConstKind::Value(ct), ty })),
@@ -1475,7 +1472,7 @@ fn pretty_print_const_value(
                                     if !first {
                                         p!(", ");
                                     }
-                                    p!(write("{}: ", field_def.ident), print(field));
+                                    p!(write("{}: ", field_def.name), print(field));
                                     first = false;
                                 }
                                 p!(" }}");
@@ -1784,10 +1781,11 @@ fn path_generic_args(
         self = print_prefix(self)?;
 
         // 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,
-            _ => false,
-        });
+        let print_regions = self.tcx.sess.verbose()
+            || args.iter().any(|arg| match arg.unpack() {
+                GenericArgKind::Lifetime(r) => *r != ty::ReErased,
+                _ => false,
+            });
         let args = args.iter().cloned().filter(|arg| match arg.unpack() {
             GenericArgKind::Lifetime(_) => print_regions,
             _ => true,
@@ -2246,7 +2244,6 @@ fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>)
         T: TypeFoldable<'tcx>,
     {
         struct LateBoundRegionNameCollector<'a, 'tcx> {
-            tcx: TyCtxt<'tcx>,
             used_region_names: &'a mut FxHashSet<Symbol>,
             type_collector: SsoHashSet<Ty<'tcx>>,
         }
@@ -2254,10 +2251,6 @@ struct LateBoundRegionNameCollector<'a, 'tcx> {
         impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
             type BreakTy = ();
 
-            fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-                Some(self.tcx)
-            }
-
             #[instrument(skip(self), level = "trace")]
             fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
                 trace!("address: {:p}", r);
@@ -2288,7 +2281,6 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
 
         self.used_region_names.clear();
         let mut collector = LateBoundRegionNameCollector {
-            tcx: self.tcx,
             used_region_names: &mut self.used_region_names,
             type_collector: SsoHashSet::new(),
         };
@@ -2547,7 +2539,7 @@ pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPat
                 write("` implements the trait `{}`", kind))
             }
             ty::PredicateKind::ConstEvaluatable(uv) => {
-                p!("the constant `", print_value_path(uv.def.did, uv.substs_.map_or(&[], |x| x)), "` can be evaluated")
+                p!("the constant `", print_value_path(uv.def.did, uv.substs), "` can be evaluated")
             }
             ty::PredicateKind::ConstEquate(c1, c2) => {
                 p!("the constant `", print(c1), "` equals `", print(c2), "`")
@@ -2602,7 +2594,7 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
 
     // Iterate external crate defs but be mindful about visibility
     while let Some(def) = queue.pop() {
-        for child in tcx.item_children(def).iter() {
+        for child in tcx.module_children(def).iter() {
             if !child.vis.is_public() {
                 continue;
             }
@@ -2615,7 +2607,9 @@ fn for_each_def(tcx: TyCtxt<'_>, mut collect_fn: impl for<'b> FnMut(&'b Ident, N
                         collect_fn(&child.ident, ns, def_id);
                     }
 
-                    if seen_defs.insert(def_id) {
+                    if matches!(defkind, DefKind::Mod | DefKind::Enum | DefKind::Trait)
+                        && seen_defs.insert(def_id)
+                    {
                         queue.push(def_id);
                     }
                 }
index 2f91503afdfaf378ca4f84f5279136c7ef536ffe..4a38d1c422f923b64c1807642e21fb9aff01186c 100644 (file)
@@ -1,7 +1,7 @@
 use crate::dep_graph;
-use crate::hir::exports::Export;
 use crate::infer::canonical::{self, Canonical};
 use crate::lint::LintLevelMap;
+use crate::metadata::ModChild;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
 use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use crate::middle::lib_features::LibFeatures;
@@ -28,6 +28,7 @@
 };
 use crate::traits::specialization_graph;
 use crate::traits::{self, ImplSource};
+use crate::ty::fast_reject::SimplifiedType;
 use crate::ty::subst::{GenericArg, SubstsRef};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
index 63ed318cadb890932a851bcec4bb75a7966e3a65..9e381cabdfe8482995ecdf1ed05dc4238b02f85f 100644 (file)
@@ -599,13 +599,13 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
             let substs = relation.relate_with_variance(
                 ty::Variance::Invariant,
                 ty::VarianceDiagInfo::default(),
-                au.substs(tcx),
-                bu.substs(tcx),
+                au.substs,
+                bu.substs,
             )?;
             return Ok(tcx.mk_const(ty::Const {
                 val: ty::ConstKind::Unevaluated(ty::Unevaluated {
                     def: au.def,
-                    substs_: Some(substs),
+                    substs,
                     promoted: au.promoted,
                 }),
                 ty: a.ty,
index 98b1a8b4d7631f84d22f8b5863280c456a314a51..63ebbcbc5bb67f01d21635544fb7fc6aca32b0b1 100644 (file)
@@ -47,12 +47,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-impl<'tcx> fmt::Debug for ty::UpvarBorrow<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "UpvarBorrow({:?}, {:?})", self.kind, self.region)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         with_no_trimmed_paths(|| fmt::Display::fmt(self, f))
@@ -191,7 +185,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                 write!(f, "ClosureKind({:?}, {:?}, {:?})", closure_def_id, closure_substs, kind)
             }
             ty::PredicateKind::ConstEvaluatable(uv) => {
-                write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs_)
+                write!(f, "ConstEvaluatable({:?}, {:?})", uv.def, uv.substs)
             }
             ty::PredicateKind::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2),
             ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
@@ -1232,7 +1226,7 @@ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
     ) -> Result<Self, F::Error> {
         Ok(ty::Unevaluated {
             def: self.def,
-            substs_: Some(self.substs(folder.tcx()).try_fold_with(folder)?),
+            substs: self.substs.try_fold_with(folder)?,
             promoted: self.promoted,
         })
     }
@@ -1242,14 +1236,7 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::Br
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        if let Some(tcx) = visitor.tcx_for_anon_const_substs() {
-            self.substs(tcx).visit_with(visitor)
-        } else if let Some(substs) = self.substs_ {
-            substs.visit_with(visitor)
-        } else {
-            debug!("ignoring default substs of `{:?}`", self.def);
-            ControlFlow::CONTINUE
-        }
+        self.substs.visit_with(visitor)
     }
 }
 
@@ -1260,7 +1247,7 @@ fn try_super_fold_with<F: FallibleTypeFolder<'tcx>>(
     ) -> Result<Self, F::Error> {
         Ok(ty::Unevaluated {
             def: self.def,
-            substs_: Some(self.substs(folder.tcx()).try_fold_with(folder)?),
+            substs: self.substs.try_fold_with(folder)?,
             promoted: self.promoted,
         })
     }
@@ -1270,13 +1257,6 @@ fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::Br
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
-        if let Some(tcx) = visitor.tcx_for_anon_const_substs() {
-            self.substs(tcx).visit_with(visitor)
-        } else if let Some(substs) = self.substs_ {
-            substs.visit_with(visitor)
-        } else {
-            debug!("ignoring default substs of `{:?}`", self.def);
-            ControlFlow::CONTINUE
-        }
+        self.substs.visit_with(visitor)
     }
 }
index c24a1d8eb529f91ea8dda13569e9f6e6790b000b..92fb7612688c08c2f265d21dfa428bd2f7653f9c 100644 (file)
@@ -1642,26 +1642,26 @@ pub fn type_flags(&self) -> TypeFlags {
 
         match *self {
             ty::ReVar(..) => {
-                flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
-                flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
+                flags = flags | TypeFlags::HAS_FREE_REGIONS;
+                flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
                 flags = flags | TypeFlags::HAS_RE_INFER;
             }
             ty::RePlaceholder(..) => {
-                flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
-                flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
+                flags = flags | TypeFlags::HAS_FREE_REGIONS;
+                flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
                 flags = flags | TypeFlags::HAS_RE_PLACEHOLDER;
             }
             ty::ReEarlyBound(..) => {
-                flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
-                flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
-                flags = flags | TypeFlags::HAS_KNOWN_RE_PARAM;
+                flags = flags | TypeFlags::HAS_FREE_REGIONS;
+                flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
+                flags = flags | TypeFlags::HAS_RE_PARAM;
             }
             ty::ReFree { .. } => {
-                flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
-                flags = flags | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS;
+                flags = flags | TypeFlags::HAS_FREE_REGIONS;
+                flags = flags | TypeFlags::HAS_FREE_LOCAL_REGIONS;
             }
             ty::ReEmpty(_) | ty::ReStatic => {
-                flags = flags | TypeFlags::HAS_KNOWN_FREE_REGIONS;
+                flags = flags | TypeFlags::HAS_FREE_REGIONS;
             }
             ty::ReLateBound(..) => {
                 flags = flags | TypeFlags::HAS_RE_LATE_BOUND;
@@ -2143,9 +2143,12 @@ 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, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        // FIXME: should this normalize?
-        let tail = tcx.struct_tail_without_normalization(self);
+    pub fn ptr_metadata_ty(
+        &'tcx self,
+        tcx: TyCtxt<'tcx>,
+        normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
+    ) -> Ty<'tcx> {
+        let tail = tcx.struct_tail_with_normalize(self, normalize);
         match tail.kind() {
             // Sized types
             ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
index a71181149149d648b9a9bd45f95069d74aa62366..ab33fbcca15a3172513e2124b374632cf604b80a 100644 (file)
@@ -505,7 +505,7 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
     }
 
     fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        if !t.potentially_needs_subst() {
+        if !t.needs_subst() {
             return t;
         }
 
index cbb88def7e27dbd326a28ee891f5dbeab710cfc8..34d059f4ec849c28625f05730bf0cf5fb56891d4 100644 (file)
@@ -1,5 +1,5 @@
 use crate::traits::specialization_graph;
-use crate::ty::fast_reject::{self, SimplifyParams, StripReferences};
+use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
 use crate::ty::fold::TypeFoldable;
 use crate::ty::{Ty, TyCtxt};
 use rustc_hir as hir;
@@ -68,7 +68,7 @@ pub enum TraitSpecializationKind {
 pub struct TraitImpls {
     blanket_impls: Vec<DefId>,
     /// Impls indexed by their simplified self type, for fast lookup.
-    non_blanket_impls: FxIndexMap<fast_reject::SimplifiedType, Vec<DefId>>,
+    non_blanket_impls: FxIndexMap<SimplifiedType, Vec<DefId>>,
 }
 
 impl TraitImpls {
index 669065598f1498041fd6664b86d980203a9051c9..8793264a47fbb3438c0f82e00bca58444de6e594 100644 (file)
@@ -192,7 +192,7 @@ pub fn struct_tail_erasing_lifetimes(
     pub fn struct_tail_with_normalize(
         self,
         mut ty: Ty<'tcx>,
-        normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>,
+        mut normalize: impl FnMut(Ty<'tcx>) -> Ty<'tcx>,
     ) -> Ty<'tcx> {
         let recursion_limit = self.recursion_limit();
         for iteration in 0.. {
index ba5775fd773762ebe87ba0f9aabdf22fc7291989..6808316a23095208fbc12a4e68d67b486804f3b6 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, TyCtxt};
 use rustc_data_structures::sso::SsoHashSet;
 use smallvec::{self, SmallVec};
 
@@ -11,7 +11,6 @@
 type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>;
 
 pub struct TypeWalker<'tcx> {
-    expose_default_const_substs: Option<TyCtxt<'tcx>>,
     stack: TypeWalkerStack<'tcx>,
     last_subtree: usize,
     pub visited: SsoHashSet<GenericArg<'tcx>>,
@@ -26,13 +25,8 @@ pub struct TypeWalker<'tcx> {
 /// It maintains a set of visited types and
 /// skips any types that are already there.
 impl<'tcx> TypeWalker<'tcx> {
-    fn new(expose_default_const_substs: Option<TyCtxt<'tcx>>, root: GenericArg<'tcx>) -> Self {
-        Self {
-            expose_default_const_substs,
-            stack: smallvec![root],
-            last_subtree: 1,
-            visited: SsoHashSet::new(),
-        }
+    pub fn new(root: GenericArg<'tcx>) -> Self {
+        Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
     }
 
     /// Skips the subtree corresponding to the last type
@@ -61,7 +55,7 @@ fn next(&mut self) -> Option<GenericArg<'tcx>> {
             let next = self.stack.pop()?;
             self.last_subtree = self.stack.len();
             if self.visited.insert(next) {
-                push_inner(self.expose_default_const_substs, &mut self.stack, next);
+                push_inner(&mut self.stack, next);
                 debug!("next: stack={:?}", self.stack);
                 return Some(next);
             }
@@ -80,8 +74,8 @@ impl<'tcx> GenericArg<'tcx> {
     /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
     /// [isize] => { [isize], isize }
     /// ```
-    pub fn walk(self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> {
-        TypeWalker::new(Some(tcx), self)
+    pub fn walk(self) -> TypeWalker<'tcx> {
+        TypeWalker::new(self)
     }
 
     /// Iterator that walks the immediate children of `self`. Hence
@@ -93,21 +87,16 @@ pub fn walk(self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> {
     /// and skips any types that are already there.
     pub fn walk_shallow(
         self,
-        tcx: TyCtxt<'tcx>,
         visited: &mut SsoHashSet<GenericArg<'tcx>>,
     ) -> impl Iterator<Item = GenericArg<'tcx>> {
         let mut stack = SmallVec::new();
-        push_inner(Some(tcx), &mut stack, self);
+        push_inner(&mut stack, self);
         stack.retain(|a| visited.insert(*a));
         stack.into_iter()
     }
 }
 
 impl<'tcx> super::TyS<'tcx> {
-    pub fn walk_ignoring_default_const_substs(&'tcx self) -> TypeWalker<'tcx> {
-        TypeWalker::new(None, self.into())
-    }
-
     /// 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
@@ -118,8 +107,8 @@ pub fn walk_ignoring_default_const_substs(&'tcx self) -> TypeWalker<'tcx> {
     /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
     /// [isize] => { [isize], isize }
     /// ```
-    pub fn walk(&'tcx self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> {
-        TypeWalker::new(Some(tcx), self.into())
+    pub fn walk(&'tcx self) -> TypeWalker<'tcx> {
+        TypeWalker::new(self.into())
     }
 }
 
@@ -129,11 +118,7 @@ pub fn walk(&'tcx self, tcx: TyCtxt<'tcx>) -> TypeWalker<'tcx> {
 /// known to be significant to any code, but it seems like the
 /// natural order one would expect (basically, the order of the
 /// types as they are written).
-fn push_inner<'tcx>(
-    expose_default_const_substs: Option<TyCtxt<'tcx>>,
-    stack: &mut TypeWalkerStack<'tcx>,
-    parent: GenericArg<'tcx>,
-) {
+fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) {
     match parent.unpack() {
         GenericArgKind::Type(parent_ty) => match *parent_ty.kind() {
             ty::Bool
@@ -211,11 +196,7 @@ fn push_inner<'tcx>(
                 | ty::ConstKind::Error(_) => {}
 
                 ty::ConstKind::Unevaluated(ct) => {
-                    if let Some(tcx) = expose_default_const_substs {
-                        stack.extend(ct.substs(tcx).iter().rev());
-                    } else if let Some(substs) = ct.substs_ {
-                        stack.extend(substs.iter().rev());
-                    }
+                    stack.extend(ct.substs.iter().rev());
                 }
             }
         }
index c6a34ece24576e51aa85e42b2d179aa26943dcd1..2433a00232d7fb0b8004b8240e53d1a97a31d6d9 100644 (file)
@@ -217,10 +217,6 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
                 ty::ClosureKind::FnOnce => {}
             }
 
-            // We won't be building MIR if the closure wasn't local
-            let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
-            let closure_span = tcx.hir().span(closure_hir_id);
-
             let Some((capture_index, capture)) =
                 find_capture_matching_projections(
                     typeck_results,
@@ -228,6 +224,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
                     closure_def_id,
                     &from_builder.projection,
                 ) else {
+                let closure_span = tcx.def_span(closure_def_id);
                 if !enable_precise_capture(tcx, closure_span) {
                     bug!(
                         "No associated capture found for {:?}[{:#?}] even though \
@@ -244,6 +241,8 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
                 return Err(from_builder);
             };
 
+            // We won't be building MIR if the closure wasn't local
+            let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
             let closure_ty = typeck_results.node_type(closure_hir_id);
 
             let substs = match closure_ty.kind() {
@@ -266,7 +265,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
             // we need to deref it
             upvar_resolved_place_builder = match capture.info.capture_kind {
                 ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(),
-                ty::UpvarCapture::ByValue(_) => upvar_resolved_place_builder,
+                ty::UpvarCapture::ByValue => upvar_resolved_place_builder,
             };
 
             let next_projection = capture.place.projections.len();
@@ -336,10 +335,7 @@ fn expect_upvars_resolved<'a>(
     }
 
     crate fn downcast(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx) -> Self {
-        self.project(PlaceElem::Downcast(
-            Some(adt_def.variants[variant_index].ident.name),
-            variant_index,
-        ))
+        self.project(PlaceElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index))
     }
 
     fn index(self, index: Local) -> Self {
index a01df2372a0978499de8349d31b81ab467252f02..7ed5d1d67ab12e3d5681273e51ec8a096f0de0f3 100644 (file)
@@ -754,10 +754,8 @@ fn candidate_after_variant_switch<'pat>(
         // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
         // we want to create a set of derived match-patterns like
         // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
-        let elem = ProjectionElem::Downcast(
-            Some(adt_def.variants[variant_index].ident.name),
-            variant_index,
-        );
+        let elem =
+            ProjectionElem::Downcast(Some(adt_def.variants[variant_index].name), variant_index);
         let downcast_place = match_pair.place.project(elem); // `(x as Variant)`
         let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
             // e.g., `(x as Variant).0`
index cb94e759972378899e45da2959035b5b0368ecc3..e2a42de71b956701da9f1a490964b6a634b229f7 100644 (file)
@@ -244,10 +244,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
         // The exception is `body.user_type_annotations`, which is used unmodified
         // by borrow checking.
         debug_assert!(
-            !(body.local_decls.has_free_regions(tcx)
-                || body.basic_blocks().has_free_regions(tcx)
-                || body.var_debug_info.has_free_regions(tcx)
-                || body.yield_ty().has_free_regions(tcx)),
+            !(body.local_decls.has_free_regions()
+                || body.basic_blocks().has_free_regions()
+                || body.var_debug_info.has_free_regions()
+                || body.yield_ty().has_free_regions()),
             "Unexpected free regions in MIR: {:?}",
             body,
         );
@@ -760,7 +760,6 @@ fn construct_error<'a, 'tcx>(
     cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
 
     let mut body = Body::new(
-        tcx,
         MirSource::item(def.did.to_def_id()),
         cfg.basic_blocks,
         source_scopes,
@@ -849,7 +848,6 @@ fn finish(self) -> Body<'tcx> {
         }
 
         Body::new(
-            self.tcx,
             MirSource::item(self.def_id),
             self.cfg.basic_blocks,
             self.source_scopes,
@@ -930,7 +928,7 @@ fn args_and_body(
                     let mut projs = closure_env_projs.clone();
                     projs.push(ProjectionElem::Field(Field::new(i), ty));
                     match capture {
-                        ty::UpvarCapture::ByValue(_) => {}
+                        ty::UpvarCapture::ByValue => {}
                         ty::UpvarCapture::ByRef(..) => {
                             projs.push(ProjectionElem::Deref);
                         }
index e4c2d2dce67c7d3883b5614c3e23599a74626e59..d348aaa899e65d79d78b950bb8d3bd196cd231c5 100644 (file)
@@ -11,9 +11,8 @@
 
 crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     let def_id = body.source.def_id().expect_local();
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
-    if let Some(fn_kind) = tcx.hir().get(hir_id).fn_kind() {
+    if let Some(fn_kind) = tcx.hir().get_by_def_id(def_id).fn_kind() {
         if let FnKind::Closure = fn_kind {
             // closures can't recur, so they don't matter.
             return;
index 092fe131174703b32343eb75f608ed07900fd302..c62de1543883eb60e95be6852f5078b17669da24 100644 (file)
@@ -583,9 +583,12 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                 ExprKind::ConstBlock { value }
             }
             // Now comes the rote stuff:
-            hir::ExprKind::Repeat(ref v, ref count) => {
-                let count_def_id = self.tcx.hir().local_def_id(count.hir_id);
-                let count = ty::Const::from_anon_const(self.tcx, count_def_id);
+            hir::ExprKind::Repeat(ref v, _) => {
+                let ty = self.typeck_results().expr_ty(expr);
+                let count = match ty.kind() {
+                    ty::Array(_, ct) => ct,
+                    _ => span_bug!(expr.span, "unexpected repeat expr ty: {:?}", ty),
+                };
 
                 ExprKind::Repeat { value: self.mirror_expr(v), count }
             }
@@ -1105,9 +1108,9 @@ fn capture_upvar(
         let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id);
 
         match upvar_capture {
-            ty::UpvarCapture::ByValue(_) => captured_place_expr,
+            ty::UpvarCapture::ByValue => captured_place_expr,
             ty::UpvarCapture::ByRef(upvar_borrow) => {
-                let borrow_kind = match upvar_borrow.kind {
+                let borrow_kind = match upvar_borrow {
                     ty::BorrowKind::ImmBorrow => BorrowKind::Shared,
                     ty::BorrowKind::UniqueImmBorrow => BorrowKind::Unique,
                     ty::BorrowKind::MutBorrow => BorrowKind::Mut { allow_two_phase_borrow: false },
index 7a4fd6ffc4adef9d1a6f186860b4eb44b4ab870a..0980c669f337bae4d8537a486e6994c797c3b77b 100644 (file)
@@ -327,7 +327,7 @@ fn check_for_bindings_named_same_as_variants(
                 if let ty::Adt(edef, _) = pat_ty.kind() {
                     if edef.is_enum()
                         && edef.variants.iter().any(|variant| {
-                            variant.ident == ident && variant.ctor_kind == CtorKind::Const
+                            variant.ident(cx.tcx) == ident && variant.ctor_kind == CtorKind::Const
                         })
                     {
                         let variant_count = edef.variants.len();
@@ -627,7 +627,7 @@ fn maybe_point_at_variant<'a, 'p: 'a, 'tcx: 'a>(
                     continue;
                 }
             }
-            let sp = def.variants[*variant_index].ident.span;
+            let sp = def.variants[*variant_index].ident(cx.tcx).span;
             if covered.contains(&sp) {
                 // Don't point at variants that have already been covered due to other patterns to avoid
                 // visual clutter.
index dd16e3cde75aeff584ab37c15de47aeb22a94d62..d8c9a6fa3fe969d8cbb15a08c71d44f7b4365740 100644 (file)
@@ -120,34 +120,32 @@ fn adt_derive_msg(&self, adt_def: &AdtDef) -> String {
     }
 
     fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
-        traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty).map(
-            |non_sm_ty| {
-                with_no_trimmed_paths(|| match non_sm_ty {
-                    traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt),
-                    traits::NonStructuralMatchTy::Dynamic => {
-                        "trait objects cannot be used in patterns".to_string()
-                    }
-                    traits::NonStructuralMatchTy::Opaque => {
-                        "opaque types cannot be used in patterns".to_string()
-                    }
-                    traits::NonStructuralMatchTy::Closure => {
-                        "closures cannot be used in patterns".to_string()
-                    }
-                    traits::NonStructuralMatchTy::Generator => {
-                        "generators cannot be used in patterns".to_string()
-                    }
-                    traits::NonStructuralMatchTy::Param => {
-                        bug!("use of a constant whose type is a parameter inside a pattern")
-                    }
-                    traits::NonStructuralMatchTy::Projection => {
-                        bug!("use of a constant whose type is a projection inside a pattern")
-                    }
-                    traits::NonStructuralMatchTy::Foreign => {
-                        bug!("use of a value of a foreign type inside a pattern")
-                    }
-                })
-            },
-        )
+        traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| {
+            with_no_trimmed_paths(|| match non_sm_ty {
+                traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt),
+                traits::NonStructuralMatchTy::Dynamic => {
+                    "trait objects cannot be used in patterns".to_string()
+                }
+                traits::NonStructuralMatchTy::Opaque => {
+                    "opaque types cannot be used in patterns".to_string()
+                }
+                traits::NonStructuralMatchTy::Closure => {
+                    "closures cannot be used in patterns".to_string()
+                }
+                traits::NonStructuralMatchTy::Generator => {
+                    "generators cannot be used in patterns".to_string()
+                }
+                traits::NonStructuralMatchTy::Param => {
+                    bug!("use of a constant whose type is a parameter inside a pattern")
+                }
+                traits::NonStructuralMatchTy::Projection => {
+                    bug!("use of a constant whose type is a projection inside a pattern")
+                }
+                traits::NonStructuralMatchTy::Foreign => {
+                    bug!("use of a value of a foreign type inside a pattern")
+                }
+            })
+        })
     }
 
     fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
@@ -240,7 +238,7 @@ fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
         // code at the moment, because types like `for <'a> fn(&'a ())` do
         // not *yet* implement `PartialEq`. So for now we leave this here.
         has_impl
-            || ty.walk(self.tcx()).any(|t| match t.unpack() {
+            || ty.walk().any(|t| match t.unpack() {
                 ty::subst::GenericArgKind::Lifetime(_) => false,
                 ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(),
                 ty::subst::GenericArgKind::Const(_) => false,
index 368e3957dd0d99b55fab5f827f07d1e0ccd5683d..801c8778bff04c1335b30e2cc7f7db40db0ba06c 100644 (file)
@@ -1648,7 +1648,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                     };
 
                     if let Some(variant) = variant {
-                        write!(f, "{}", variant.ident)?;
+                        write!(f, "{}", variant.name)?;
                     }
 
                     // Without `cx`, we can't know which field corresponds to which, so we can't
index 11856f6e047e5c65a2db43954048045af31e7d88..501bc96401aa50339000a198e8906c3af26a1640 100644 (file)
@@ -491,7 +491,7 @@ fn open_drop_for_multivariant(
             if let Some(variant_path) = subpath {
                 let base_place = tcx.mk_place_elem(
                     self.place,
-                    ProjectionElem::Downcast(Some(variant.ident.name), variant_index),
+                    ProjectionElem::Downcast(Some(variant.name), variant_index),
                 );
                 let fields = self.move_paths_for_fields(base_place, variant_path, &variant, substs);
                 values.push(discr.val);
index feb85d4ffdfa881126ea178fc02d136df323d56e..2e00b4f9a5e7cbb4ba1ad3a7e3d122963d9c99c1 100644 (file)
@@ -343,19 +343,7 @@ fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
             | Rvalue::AddressOf(..)
             | Rvalue::Discriminant(..)
             | Rvalue::Len(..)
-            | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _)
-            | Rvalue::NullaryOp(NullOp::Box, _) => {
-                // This returns an rvalue with uninitialized contents. We can't
-                // move out of it here because it is an rvalue - assignments always
-                // completely initialize their place.
-                //
-                // However, this does not matter - MIR building is careful to
-                // only emit a shallow free for the partially-initialized
-                // temporary.
-                //
-                // In any case, if we want to fix this, we have to register a
-                // special move and change the `statement_effect` functions.
-            }
+            | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
         }
     }
 
index 7e56e062fc989b66dbb35868a6f03edf434bb2e1..14caf03d7aff3842d362904304f1de27ae833eb9 100644 (file)
@@ -76,10 +76,8 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         }
 
         let def_id = body.source.def_id().expect_local();
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
-        let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
-        let is_assoc_const = tcx.def_kind(def_id.to_def_id()) == DefKind::AssocConst;
+        let is_fn_like = tcx.hir().get_by_def_id(def_id).fn_kind().is_some();
+        let is_assoc_const = tcx.def_kind(def_id) == DefKind::AssocConst;
 
         // Only run const prop on functions, methods, closures and associated constants
         if !is_fn_like && !is_assoc_const {
@@ -126,7 +124,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             .predicates_of(def_id.to_def_id())
             .predicates
             .iter()
-            .filter_map(|(p, _)| if p.is_global(tcx) { Some(*p) } else { None });
+            .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
         if traits::impossible_predicates(
             tcx,
             traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
@@ -138,7 +136,6 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("ConstProp starting for {:?}", def_id);
 
         let dummy_body = &Body::new(
-            tcx,
             body.source,
             body.basic_blocks().clone(),
             body.source_scopes.clone(),
@@ -239,13 +236,6 @@ fn binary_ptr_op(
         throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
     }
 
-    fn box_alloc(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _dest: &PlaceTy<'tcx>,
-    ) -> InterpResult<'tcx> {
-        throw_machine_stop_str!("can't const prop heap allocations")
-    }
-
     fn access_local(
         _ecx: &InterpCx<'mir, 'tcx, Self>,
         frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
@@ -413,7 +403,7 @@ fn new(
             Instance::new(def_id, substs),
             dummy_body,
             ret.as_ref(),
-            StackPopCleanup::None { cleanup: false },
+            StackPopCleanup::Root { cleanup: false },
         )
         .expect("failed to push initial stack frame");
 
@@ -482,7 +472,7 @@ fn use_ecx<F, T>(&mut self, f: F) -> Option<T>
     /// Returns the value, if any, of evaluating `c`.
     fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
         // FIXME we need to revisit this for #67176
-        if c.definitely_needs_subst(self.tcx) {
+        if c.needs_subst() {
             return None;
         }
 
@@ -497,14 +487,14 @@ fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Opti
                             // Promoteds must lint and not error as the user didn't ask for them
                             ConstKind::Unevaluated(ty::Unevaluated {
                                 def: _,
-                                substs_: _,
+                                substs: _,
                                 promoted: Some(_),
                             }) => true,
                             // Out of backwards compatibility we cannot report hard errors in unused
                             // generic functions using associated constants of the generic parameters.
-                            _ => c.literal.definitely_needs_subst(*tcx),
+                            _ => c.literal.needs_subst(),
                         },
-                        ConstantKind::Val(_, ty) => ty.definitely_needs_subst(*tcx),
+                        ConstantKind::Val(_, ty) => ty.needs_subst(),
                     };
                     if lint_only {
                         // Out of backwards compatibility we cannot report hard errors in unused
@@ -735,7 +725,7 @@ fn const_prop(
         }
 
         // FIXME we need to revisit this for #67176
-        if rvalue.definitely_needs_subst(self.tcx) {
+        if rvalue.needs_subst() {
             return None;
         }
 
index b009e2fd0e4ade6889dd9c653e9951586c1355d2..82455654a8860c11501e8caf17bcf5cc5abca8fc 100644 (file)
@@ -66,8 +66,8 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
             return;
         }
 
-        let hir_id = tcx.hir().local_def_id_to_hir_id(mir_source.def_id().expect_local());
-        let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
+        let is_fn_like =
+            tcx.hir().get_by_def_id(mir_source.def_id().expect_local()).fn_kind().is_some();
 
         // Only instrument functions, methods, and closures (not constants since they are evaluated
         // at compile time by Miri).
index 1721fb5cde0e899e04c5acb82684c7803ed1d6d1..46de6d939a1df69fbc48754e4c02d94fb3b6225d 100644 (file)
@@ -9,7 +9,6 @@
 /// A `query` provider for retrieving coverage information injected into MIR.
 pub(crate) fn provide(providers: &mut Providers) {
     providers.coverageinfo = |tcx, def_id| coverageinfo(tcx, def_id);
-    providers.covered_file_name = |tcx, def_id| covered_file_name(tcx, def_id);
     providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id);
 }
 
@@ -137,25 +136,6 @@ fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) ->
     coverage_visitor.info
 }
 
-fn covered_file_name(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Symbol> {
-    if tcx.is_mir_available(def_id) {
-        let body = mir_body(tcx, def_id);
-        for bb_data in body.basic_blocks().iter() {
-            for statement in bb_data.statements.iter() {
-                if let StatementKind::Coverage(box ref coverage) = statement.kind {
-                    if let Some(code_region) = coverage.code_region.as_ref() {
-                        if is_inlined(body, statement) {
-                            continue;
-                        }
-                        return Some(code_region.file_name);
-                    }
-                }
-            }
-        }
-    }
-    return None;
-}
-
 fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> {
     let body = mir_body(tcx, def_id);
     body.basic_blocks()
index d346dfb1772199b3659a3962a7355fb056e357cb..7320b2738a76c2c0b222f162962f9a4f10937cb1 100644 (file)
@@ -316,12 +316,12 @@ fn collect_drop_flags(&mut self) {
                 LookupResult::Parent(Some(parent)) => {
                     let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent);
                     if maybe_dead {
-                        span_bug!(
+                        self.tcx.sess.delay_span_bug(
                             terminator.source_info.span,
-                            "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
-                            bb,
-                            place,
-                            path
+                            &format!(
+                                "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
+                                bb, place, path,
+                            ),
                         );
                     }
                     continue;
@@ -368,10 +368,9 @@ fn elaborate_drops(&mut self) {
                             bb,
                         ),
                         LookupResult::Parent(..) => {
-                            span_bug!(
+                            self.tcx.sess.delay_span_bug(
                                 terminator.source_info.span,
-                                "drop of untracked value {:?}",
-                                bb
+                                &format!("drop of untracked value {:?}", bb),
                             );
                         }
                     }
index 05834b443d0d9d0552d4b2e78fd6a6dabde1c7ff..f364a332a788cce900693575d3708fc0a5cf34a9 100644 (file)
@@ -49,7 +49,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     // Handle calls to `transmute`
                     if self.tcx.is_diagnostic_item(sym::transmute, def_id) {
                         let arg_ty = args[0].ty(self.body, self.tcx);
-                        for generic_inner_ty in arg_ty.walk(self.tcx) {
+                        for generic_inner_ty in arg_ty.walk() {
                             if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
                                 if let Some((fn_id, fn_substs)) =
                                     FunctionItemRefChecker::is_fn_ref(inner_ty)
@@ -110,7 +110,7 @@ fn check_bound_args(
                 let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs();
                 for (arg_num, arg_def) in arg_defs.iter().enumerate() {
                     // For all types reachable from the argument type in the fn sig
-                    for generic_inner_ty in arg_def.walk(self.tcx) {
+                    for generic_inner_ty in arg_def.walk() {
                         if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
                             // If the inner type matches the type bound by `Pointer`
                             if TyS::same_type(inner_ty, bound_ty) {
index bc9a104e849dc95a9b84c64c5f49814e696796db..08247e6f22af161113f92ddbc0d823e3c9e937d9 100644 (file)
@@ -726,9 +726,13 @@ fn sanitize_witness<'tcx>(
     saved_locals: &GeneratorSavedLocals,
 ) {
     let did = body.source.def_id();
-    let allowed_upvars = tcx.erase_regions(upvars);
+    let param_env = tcx.param_env(did);
+
+    let allowed_upvars = tcx.normalize_erasing_regions(param_env, upvars);
     let allowed = match witness.kind() {
-        &ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(s),
+        &ty::GeneratorWitness(interior_tys) => {
+            tcx.normalize_erasing_late_bound_regions(param_env, interior_tys)
+        }
         _ => {
             tcx.sess.delay_span_bug(
                 body.span,
@@ -738,8 +742,6 @@ fn sanitize_witness<'tcx>(
         }
     };
 
-    let param_env = tcx.param_env(did);
-
     for (local, decl) in body.local_decls.iter_enumerated() {
         // Ignore locals which are internal or not saved between yields.
         if !saved_locals.contains(local) || decl.internal {
index 747e760a18b92e8a88f6717614288d495e260612..44ded1647fc28f93aa0f3ff1b07ad4f4560d5f2f 100644 (file)
@@ -89,7 +89,7 @@ fn process<'tcx>(
                     // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to
                     // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this
                     // needs some more analysis.
-                    if callee.definitely_needs_subst(tcx) {
+                    if callee.needs_subst() {
                         continue;
                     }
                 }
index 638baa0b8d3768deac91407adea99054304853d5..93cc24b879d3505611fa32c17645479a3390cad2 100644 (file)
@@ -342,7 +342,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
         }
     }
 
-    debug_assert!(!body.has_free_regions(tcx), "Free regions in MIR for CTFE");
+    debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
 
     body
 }
@@ -366,8 +366,7 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
         tcx.ensure().mir_borrowck(def.did);
     }
 
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
-    let is_fn_like = tcx.hir().get(hir_id).fn_kind().is_some();
+    let is_fn_like = tcx.hir().get_by_def_id(def.did).fn_kind().is_some();
     if is_fn_like {
         let did = def.did.to_def_id();
         let def = ty::WithOptConstParam::unknown(did);
@@ -530,7 +529,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
         tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal();
     run_optimization_passes(tcx, &mut body);
 
-    debug_assert!(!body.has_free_regions(tcx), "Free regions in optimized MIR");
+    debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
 
     body
 }
@@ -557,7 +556,7 @@ fn promoted_mir<'tcx>(
         run_post_borrowck_cleanup_passes(tcx, body);
     }
 
-    debug_assert!(!promoted.has_free_regions(tcx), "Free regions in promoted MIR");
+    debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
 
     tcx.arena.alloc(promoted)
 }
index 58996dcd6735a20dbf6c12594529c5d97af219d5..919171db39e3160ac15bfe61f13b8cf523c8acf5 100644 (file)
@@ -171,7 +171,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
 
     let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty));
     let mut body =
-        new_body(tcx, source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
+        new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
 
     if ty.is_some() {
         // The first argument (index 0), but add 1 for the return value.
@@ -210,7 +210,6 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>)
 }
 
 fn new_body<'tcx>(
-    tcx: TyCtxt<'tcx>,
     source: MirSource<'tcx>,
     basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
     local_decls: IndexVec<Local, LocalDecl<'tcx>>,
@@ -218,7 +217,6 @@ fn new_body<'tcx>(
     span: Span,
 ) -> Body<'tcx> {
     Body::new(
-        tcx,
         source,
         basic_blocks,
         IndexVec::from_elem_n(
@@ -362,14 +360,7 @@ fn into_mir(self) -> Body<'tcx> {
             self.def_id,
             self.sig.inputs_and_output[0],
         ));
-        new_body(
-            self.tcx,
-            source,
-            self.blocks,
-            self.local_decls,
-            self.sig.inputs().len(),
-            self.span,
-        )
+        new_body(source, self.blocks, self.local_decls, self.sig.inputs().len(), self.span)
     }
 
     fn source_info(&self) -> SourceInfo {
@@ -719,14 +710,8 @@ fn build_call_shim<'tcx>(
         block(&mut blocks, vec![], TerminatorKind::Resume, true);
     }
 
-    let mut body = new_body(
-        tcx,
-        MirSource::from_instance(instance),
-        blocks,
-        local_decls,
-        sig.inputs().len(),
-        span,
-    );
+    let mut body =
+        new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span);
 
     if let Abi::RustCall = sig.abi {
         body.spread_arg = Some(Local::new(sig.inputs().len()));
@@ -791,7 +776,6 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
 
     let source = MirSource::item(ctor_id);
     let body = new_body(
-        tcx,
         source,
         IndexVec::from_elem_n(start_block, 1),
         local_decls,
index b1fa9041342a6e3744c3daa4e7c0714f344c7ad0..7e7f693870656ec4e8728248c8e82db15a6f64a2 100644 (file)
@@ -573,7 +573,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
     let type_length = instance
         .substs
         .iter()
-        .flat_map(|arg| arg.walk(tcx))
+        .flat_map(|arg| arg.walk())
         .filter(|arg| match arg.unpack() {
             GenericArgKind::Type(_) | GenericArgKind::Const(_) => true,
             GenericArgKind::Lifetime(_) => false,
@@ -688,15 +688,6 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                     _ => bug!(),
                 }
             }
-            mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => {
-                let tcx = self.tcx;
-                let exchange_malloc_fn_def_id =
-                    tcx.require_lang_item(LangItem::ExchangeMalloc, None);
-                let instance = Instance::mono(tcx, exchange_malloc_fn_def_id);
-                if should_codegen_locally(tcx, &instance) {
-                    self.output.push(create_fn_mono_item(self.tcx, instance, span));
-                }
-            }
             mir::Rvalue::ThreadLocalRef(def_id) => {
                 assert!(self.tcx.is_thread_local_static(def_id));
                 let instance = Instance::mono(self.tcx, def_id);
@@ -1319,10 +1310,9 @@ fn create_mono_items_for_default_impls<'tcx>(
             if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
                 let param_env = ty::ParamEnv::reveal_all();
                 let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
-                let overridden_methods: FxHashSet<_> =
-                    impl_.items.iter().map(|iiref| iiref.ident.normalize_to_macros_2_0()).collect();
+                let overridden_methods = tcx.impl_item_implementor_ids(item.def_id);
                 for method in tcx.provided_trait_methods(trait_ref.def_id) {
-                    if overridden_methods.contains(&method.ident.normalize_to_macros_2_0()) {
+                    if overridden_methods.contains_key(&method.def_id) {
                         continue;
                     }
 
index 516c9a9259d4fe17624e245b327b71e5b643961b..681271be7beb9be54bf9425cab8c835372bbf2eb 100644 (file)
@@ -303,9 +303,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
 
                 // When polymorphization is enabled, methods which do not depend on their generic
                 // parameters, but the self-type of their impl block do will fail to normalize.
-                if !tcx.sess.opts.debugging_opts.polymorphize
-                    || !instance.definitely_needs_subst(tcx)
-                {
+                if !tcx.sess.opts.debugging_opts.polymorphize || !instance.needs_subst() {
                     // This is a method within an impl, find out what the self-type is:
                     let impl_self_ty = tcx.subst_and_normalize_erasing_regions(
                         instance.substs,
index dc22ffc6747ac8c4eda8473265610e612bd9f9ef..67597a0d7b46b5dea8d40f9bce3480e6ebb68146 100644 (file)
@@ -201,6 +201,40 @@ pub fn partition<'tcx>(
         partitioner.internalize_symbols(cx, &mut post_inlining);
     }
 
+    let instrument_dead_code =
+        tcx.sess.instrument_coverage() && !tcx.sess.instrument_coverage_except_unused_functions();
+
+    if instrument_dead_code {
+        assert!(
+            post_inlining.codegen_units.len() > 0,
+            "There must be at least one CGU that code coverage data can be generated in."
+        );
+
+        // Find the smallest CGU that has exported symbols and put the dead
+        // function stubs in that CGU. We look for exported symbols to increase
+        // the likelihood the linker won't throw away the dead functions.
+        // FIXME(#92165): In order to truly resolve this, we need to make sure
+        // the object file (CGU) containing the dead function stubs is included
+        // in the final binary. This will probably require forcing these
+        // function symbols to be included via `-u` or `/include` linker args.
+        let mut cgus: Vec<_> = post_inlining.codegen_units.iter_mut().collect();
+        cgus.sort_by_key(|cgu| cgu.size_estimate());
+
+        let dead_code_cgu = if let Some(cgu) = cgus
+            .into_iter()
+            .rev()
+            .filter(|cgu| cgu.items().iter().any(|(_, (linkage, _))| *linkage == Linkage::External))
+            .next()
+        {
+            cgu
+        } else {
+            // If there are no CGUs that have externally linked items,
+            // then we just pick the first CGU as a fallback.
+            &mut post_inlining.codegen_units[0]
+        };
+        dead_code_cgu.make_code_coverage_dead_code_cgu();
+    }
+
     // Finally, sort by codegen unit name, so that we get deterministic results.
     let PostInliningPartitioning {
         codegen_units: mut result,
index 595080619da6faaac8be4cf5b91b93beb4cbf45a..4b17c22a68c268c8ee17b782c097af6dd67ceb06 100644 (file)
@@ -277,12 +277,9 @@ fn visit_ty(&mut self, ty: Ty<'tcx>, _: TyContext) {
 }
 
 impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.tcx)
-    }
     #[instrument(level = "debug", skip(self))]
     fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if !c.potentially_has_param_types_or_consts() {
+        if !c.has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
         }
 
@@ -292,7 +289,7 @@ fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
                 self.unused_parameters.clear(param.index);
                 ControlFlow::CONTINUE
             }
-            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted: Some(p)})
+            ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs: _, promoted: Some(p)})
                 // Avoid considering `T` unused when constants are of the form:
                 //   `<Self as Foo<T>>::foo::promoted[p]`
                 if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self =>
@@ -306,7 +303,7 @@ fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
             ty::ConstKind::Unevaluated(uv)
                 if matches!(self.tcx.def_kind(uv.def.did), DefKind::AnonConst | DefKind::InlineConst) =>
             {
-                self.visit_child_body(uv.def.did, uv.substs(self.tcx));
+                self.visit_child_body(uv.def.did, uv.substs);
                 ControlFlow::CONTINUE
             }
             _ => c.super_visit_with(self),
@@ -315,7 +312,7 @@ fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
 
     #[instrument(level = "debug", skip(self))]
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if !ty.potentially_has_param_types_or_consts() {
+        if !ty.has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
         }
 
@@ -343,21 +340,16 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
 }
 
 /// Visitor used to check if a generic parameter is used.
-struct HasUsedGenericParams<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct HasUsedGenericParams<'a> {
     unused_parameters: &'a FiniteBitSet<u32>,
 }
 
-impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a, 'tcx> {
+impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> {
     type BreakTy = ();
 
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.tcx)
-    }
-
     #[instrument(level = "debug", skip(self))]
     fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if !c.potentially_has_param_types_or_consts() {
+        if !c.has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
         }
 
@@ -375,7 +367,7 @@ fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> ControlFlow<Self::BreakTy> {
 
     #[instrument(level = "debug", skip(self))]
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if !ty.potentially_has_param_types_or_consts() {
+        if !ty.has_param_types_or_consts() {
             return ControlFlow::CONTINUE;
         }
 
index 6084cdda22768f7bf06ed30ba53a3ccbc7905063..27540395c07892054465dc5d1a1af0c866369e81 100644 (file)
@@ -49,8 +49,7 @@
             .map(|l| format!("{:?}", l.size.bytes()))
             .unwrap_or_else(|e| format!("Failed {:?}", e));
 
-        let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
-        let closure_span = tcx.hir().span(closure_hir_id);
+        let closure_span = tcx.def_span(closure_def_id);
         let src_file = tcx.sess.source_map().span_to_filename(closure_span);
         let line_nos = tcx
             .sess
index 9677e7642b88c9c4f522eb51dae3a4ac2b76fd0c..4121a759c37f9abd381386f61cb4ed87be26024d 100644 (file)
@@ -550,8 +550,8 @@ pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {
     /// a diagnostic to suggest removing them.
     ///
     /// ```ignore (diagnostic)
-    /// let _ = vec![1, 2, 3].into_iter().collect::<Vec<usize>>>>();
-    ///                                                        ^^ help: remove extra angle brackets
+    /// let _ = [1, 2, 3].into_iter().collect::<Vec<usize>>>>();
+    ///                                                    ^^ help: remove extra angle brackets
     /// ```
     ///
     /// If `true` is returned, then trailing brackets were recovered, tokens were consumed
index d335ef8788b87f9910147da2475ee2d2d96a0b0c..ade441b0e7d5c856fd8095e0f83261cb1030b30e 100644 (file)
@@ -27,7 +27,7 @@ impl<'a> Parser<'a> {
     /// Parses a source module as a crate. This is the main entry point for the parser.
     pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> {
         let (attrs, items, span) = self.parse_mod(&token::Eof)?;
-        Ok(ast::Crate { attrs, items, span, is_placeholder: None })
+        Ok(ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false })
     }
 
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
index d7b00699491d4d71f4efb8959b497aa8edd4f271..eca7d84e95d8e446e35b94a1ae65abd111314fbb 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_errors::{pluralize, struct_span_err, Applicability};
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
-use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID};
 use rustc_hir::{MethodKind, Target};
@@ -32,7 +32,7 @@ pub(crate) fn target_from_impl_item<'tcx>(
     match impl_item.kind {
         hir::ImplItemKind::Const(..) => Target::AssocConst,
         hir::ImplItemKind::Fn(..) => {
-            let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id()).expect_owner();
+            let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id());
             let containing_item = tcx.hir().expect_item(parent_hir_id);
             let containing_impl_is_for_trait = match &containing_item.kind {
                 hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
@@ -582,7 +582,7 @@ fn check_doc_alias_value(
             Target::Impl => Some("implementation block"),
             Target::ForeignMod => Some("extern block"),
             Target::AssocTy => {
-                let parent_hir_id = self.tcx.hir().get_parent_item(hir_id).expect_owner();
+                let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
                 let containing_item = self.tcx.hir().expect_item(parent_hir_id);
                 if Target::from_item(containing_item) == Target::Impl {
                     Some("type alias in implementation block")
@@ -591,7 +591,7 @@ fn check_doc_alias_value(
                 }
             }
             Target::AssocConst => {
-                let parent_hir_id = self.tcx.hir().get_parent_item(hir_id).expect_owner();
+                let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
                 let containing_item = self.tcx.hir().expect_item(parent_hir_id);
                 // We can't link to trait impl's consts.
                 let err = "associated constant in trait implementation block";
@@ -832,7 +832,7 @@ fn check_attr_crate_level(
                     let mut err = lint.build(
                         "this attribute can only be applied at the crate level",
                     );
-                    if attr.style == AttrStyle::Outer && self.tcx.hir().get_parent_item(hir_id) == CRATE_HIR_ID {
+                    if attr.style == AttrStyle::Outer && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID {
                         if let Ok(mut src) =
                             self.tcx.sess.source_map().span_to_snippet(attr.span)
                         {
index a5a65740707e65c94aa13332bfbe62b754c1ce2f..b755f686f6aac15e5222a016f1a99ed1081ce7d5 100644 (file)
@@ -93,26 +93,29 @@ fn visit_item<'hir>(&mut self, item: &'hir hir::Item<'hir>) {
                     for trait_item in self.tcx.associated_items(trait_def_id).in_definition_order()
                     {
                         if let ty::AssocItem {
-                            kind: ty::AssocKind::Fn, ident, defaultness, ..
-                        } = trait_item
+                            kind: ty::AssocKind::Fn,
+                            defaultness,
+                            def_id: trait_item_id,
+                            ..
+                        } = *trait_item
                         {
                             // we can ignore functions that do not have default bodies:
                             // if those are unimplemented it will be catched by typeck.
                             if !defaultness.has_value()
                                 || self
                                     .tcx
-                                    .has_attr(trait_item.def_id, sym::default_method_body_is_const)
+                                    .has_attr(trait_item_id, sym::default_method_body_is_const)
                             {
                                 continue;
                             }
 
                             let is_implemented = ancestors
-                                .leaf_def(self.tcx, trait_item.ident, trait_item.kind)
+                                .leaf_def(self.tcx, trait_item_id)
                                 .map(|node_item| !node_item.defining_node.is_from_trait())
                                 .unwrap_or(false);
 
                             if !is_implemented {
-                                to_implement.push(ident.to_string());
+                                to_implement.push(self.tcx.item_name(trait_item_id).to_string());
                             }
                         }
                     }
index 3b15332c678fdd9e4101a60c6560de47d8fff262..f17816eff9a7429321176126ace7066adb9622d9 100644 (file)
@@ -23,7 +23,7 @@
 // may need to be marked as live.
 fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     matches!(
-        tcx.hir().find(tcx.hir().local_def_id_to_hir_id(def_id)),
+        tcx.hir().find_by_def_id(def_id),
         Some(
             Node::Item(..)
                 | Node::ImplItem(..)
@@ -232,7 +232,7 @@ fn mark_live_symbols(&mut self) {
             // tuple struct constructor function
             let id = self.struct_constructors.get(&id).copied().unwrap_or(id);
 
-            if let Some(node) = self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(id)) {
+            if let Some(node) = self.tcx.hir().find_by_def_id(id) {
                 self.live_symbols.insert(id);
                 self.visit_node(node);
             }
index 63f9b3ed6b15c6c7b5828ab8e41da567621b94bc..fdabe41dafaedff61466dea6036b6be20c155163 100644 (file)
@@ -1,8 +1,8 @@
 use rustc_ast::entry::EntryPointType;
 use rustc_errors::struct_span_err;
-use rustc_hir::def_id::{DefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
-use rustc_hir::{ForeignItem, HirId, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
+use rustc_hir::{ForeignItem, ImplItem, Item, ItemKind, Node, TraitItem, CRATE_HIR_ID};
 use rustc_middle::hir::map::Map;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
@@ -18,14 +18,14 @@ struct EntryContext<'a, 'tcx> {
     map: Map<'tcx>,
 
     /// The function that has attribute named `main`.
-    attr_main_fn: Option<(HirId, Span)>,
+    attr_main_fn: Option<(LocalDefId, Span)>,
 
     /// The function that has the attribute 'start' on it.
-    start_fn: Option<(HirId, Span)>,
+    start_fn: Option<(LocalDefId, Span)>,
 
     /// The functions that one might think are `main` but aren't, e.g.
     /// main functions not defined at the top level. For diagnostics.
-    non_main_fns: Vec<(HirId, Span)>,
+    non_main_fns: Vec<Span>,
 }
 
 impl<'a, 'tcx> ItemLikeVisitor<'tcx> for EntryContext<'a, 'tcx> {
@@ -112,11 +112,11 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
         }
         EntryPointType::MainNamed => (),
         EntryPointType::OtherMain => {
-            ctxt.non_main_fns.push((item.hir_id(), item.span));
+            ctxt.non_main_fns.push(item.span);
         }
         EntryPointType::MainAttr => {
             if ctxt.attr_main_fn.is_none() {
-                ctxt.attr_main_fn = Some((item.hir_id(), item.span));
+                ctxt.attr_main_fn = Some((item.def_id, item.span));
             } else {
                 struct_span_err!(
                     ctxt.session,
@@ -131,7 +131,7 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
         }
         EntryPointType::Start => {
             if ctxt.start_fn.is_none() {
-                ctxt.start_fn = Some((item.hir_id(), item.span));
+                ctxt.start_fn = Some((item.def_id, item.span));
             } else {
                 struct_span_err!(ctxt.session, item.span, E0138, "multiple `start` functions")
                     .span_label(ctxt.start_fn.unwrap().1, "previous `#[start]` function here")
@@ -143,20 +143,19 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
 }
 
 fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) -> Option<(DefId, EntryFnType)> {
-    if let Some((hir_id, _)) = visitor.start_fn {
-        Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Start))
-    } else if let Some((hir_id, _)) = visitor.attr_main_fn {
-        Some((tcx.hir().local_def_id(hir_id).to_def_id(), EntryFnType::Main))
+    if let Some((def_id, _)) = visitor.start_fn {
+        Some((def_id.to_def_id(), EntryFnType::Start))
+    } else if let Some((def_id, _)) = visitor.attr_main_fn {
+        Some((def_id.to_def_id(), EntryFnType::Main))
     } else {
         if let Some(main_def) = tcx.resolutions(()).main_def {
             if let Some(def_id) = main_def.opt_fn_def_id() {
                 // non-local main imports are handled below
-                if def_id.is_local() {
-                    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-                    if matches!(tcx.hir().find(hir_id), Some(Node::ForeignItem(_))) {
+                if let Some(def_id) = def_id.as_local() {
+                    if matches!(tcx.hir().find_by_def_id(def_id), Some(Node::ForeignItem(_))) {
                         tcx.sess
                             .struct_span_err(
-                                tcx.hir().span(hir_id),
+                                tcx.def_span(def_id),
                                 "the `main` function cannot be declared in an `extern` block",
                             )
                             .emit();
@@ -201,7 +200,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_, '_>) {
     );
     let filename = &tcx.sess.local_crate_source_file;
     let note = if !visitor.non_main_fns.is_empty() {
-        for &(_, span) in &visitor.non_main_fns {
+        for &span in &visitor.non_main_fns {
             err.span_note(span, "here is a function named `main`");
         }
         err.note("you have one or more functions named `main` not defined at the crate level");
index 0e60ca9f900107a011ecfaa229c220b298de45b1..d8c984c06764e094402e1c39f4e76f8688fef96b 100644 (file)
@@ -57,22 +57,22 @@ fn new_inner_visitor(&self, hir_map: Map<'hir>) -> HirIdValidator<'a, 'hir> {
 impl<'a, 'hir> ItemLikeVisitor<'hir> for OuterVisitor<'a, 'hir> {
     fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
         let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.hir_id(), |this| intravisit::walk_item(this, i));
+        inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
     }
 
     fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
         let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.hir_id(), |this| intravisit::walk_trait_item(this, i));
+        inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
     }
 
     fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
         let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.hir_id(), |this| intravisit::walk_impl_item(this, i));
+        inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
     }
 
     fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
         let mut inner_visitor = self.new_inner_visitor(self.hir_map);
-        inner_visitor.check(i.hir_id(), |this| intravisit::walk_foreign_item(this, i));
+        inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
     }
 }
 
@@ -83,9 +83,8 @@ fn error(&self, f: impl FnOnce() -> String) {
         self.errors.lock().push(f());
     }
 
-    fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, hir_id: HirId, walk: F) {
+    fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, owner: LocalDefId, walk: F) {
         assert!(self.owner.is_none());
-        let owner = self.hir_map.local_def_id(hir_id);
         self.owner = Some(owner);
         walk(self);
 
index a808d6c8348a7da0941ba2201b0d49f398d53a85..0c934ecc91376b121e4b7f648280c51cbbcc1b69 100644 (file)
@@ -10,7 +10,6 @@
 use crate::check_attr::target_from_impl_item;
 use crate::weak_lang_items;
 
-use rustc_ast::Attribute;
 use rustc_errors::{pluralize, struct_span_err};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -57,8 +56,7 @@ fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> {
 
     fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
         let attrs = self.tcx.hir().attrs(hir_id);
-        let check_name = |attr: &Attribute, sym| attr.has_name(sym);
-        if let Some((value, span)) = extract(check_name, &attrs) {
+        if let Some((value, span)) = extract(&attrs) {
             match ITEM_REFS.get(&value).cloned() {
                 // Known lang item with attribute on correct target.
                 Some((item_index, expected_target)) if actual_target == expected_target => {
index 8a411f01d6ee2317c8cc086f4f0296c68be25dd6..3596210036a9c65aa13aef0e974b511912cf83ba 100644 (file)
@@ -6,6 +6,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(crate_visibility_modifier)]
+#![feature(let_else)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
 #![feature(nll)]
index 9ee305b712f61ba495a9db0356fe4c2627be2f0a..2e3bf7ea548ac347dd39a9b1167b53ad2381455b 100644 (file)
@@ -726,7 +726,7 @@ fn compute(&mut self, body: &hir::Body<'_>, hir_id: HirId) -> LiveNode {
                             );
                             self.acc(self.exit_ln, var, ACC_READ | ACC_USE);
                         }
-                        ty::UpvarCapture::ByValue(_) => {}
+                        ty::UpvarCapture::ByValue => {}
                     }
                 }
             }
@@ -1481,7 +1481,7 @@ fn warn_about_unused_upvars(&self, entry_ln: LiveNode) {
         for (&var_hir_id, min_capture_list) in closure_min_captures {
             for captured_place in min_capture_list {
                 match captured_place.info.capture_kind {
-                    ty::UpvarCapture::ByValue(_) => {}
+                    ty::UpvarCapture::ByValue => {}
                     ty::UpvarCapture::ByRef(..) => continue,
                 };
                 let span = captured_place.get_capture_kind_span(self.ir.tcx);
index 707e6b123daa2ea69c78ee7c7f4d67575dae4103..f4790c4335c12133f6e15d4625eedf42932f20b3 100644 (file)
@@ -52,7 +52,7 @@ fn method_might_be_inlined(
             return true;
         }
     }
-    match tcx.hir().find(tcx.hir().local_def_id_to_hir_id(impl_src)) {
+    match tcx.hir().find_by_def_id(impl_src) {
         Some(Node::Item(item)) => item_might_be_inlined(tcx, &item, codegen_fn_attrs),
         Some(..) | None => span_bug!(impl_item.span, "impl did is not an item"),
     }
@@ -140,14 +140,11 @@ fn typeck_results(&self) -> &'tcx ty::TypeckResults<'tcx> {
     // Returns true if the given def ID represents a local item that is
     // eligible for inlining and false otherwise.
     fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool {
-        let hir_id = match def_id.as_local() {
-            Some(def_id) => self.tcx.hir().local_def_id_to_hir_id(def_id),
-            None => {
-                return false;
-            }
+        let Some(def_id) = def_id.as_local() else {
+            return false;
         };
 
-        match self.tcx.hir().find(hir_id) {
+        match self.tcx.hir().find_by_def_id(def_id) {
             Some(Node::Item(item)) => match item.kind {
                 hir::ItemKind::Fn(..) => {
                     item_might_be_inlined(self.tcx, &item, self.tcx.codegen_fn_attrs(def_id))
@@ -169,7 +166,8 @@ fn def_id_represents_local_inlined_item(&self, def_id: DefId) -> bool {
                         if generics.requires_monomorphization(self.tcx) || attrs.requests_inline() {
                             true
                         } else {
-                            let impl_did = self.tcx.hir().get_parent_did(hir_id);
+                            let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+                            let impl_did = self.tcx.hir().get_parent_item(hir_id);
                             // Check the impl. If the generics on the self
                             // type of the impl require inlining, this method
                             // does too.
@@ -198,9 +196,7 @@ fn propagate(&mut self) {
                 continue;
             }
 
-            if let Some(ref item) =
-                self.tcx.hir().find(self.tcx.hir().local_def_id_to_hir_id(search_item))
-            {
+            if let Some(ref item) = self.tcx.hir().find_by_def_id(search_item) {
                 self.propagate_node(item, search_item);
             }
         }
index 5f19991f9c78b1f034d4e1eb05edf63be1618c66..270da883b8db45f3ec8f84342d2e50d156582f20 100644 (file)
@@ -629,7 +629,7 @@ fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
     }
 
     fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
-        let impl_def_id = self.tcx.hir().local_def_id(self.tcx.hir().get_parent_item(ii.hir_id()));
+        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);
         }
@@ -794,19 +794,12 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                     }
                 }
 
-                if let Res::Def(DefKind::Trait, trait_did) = t.path.res {
-                    for impl_item_ref in items {
-                        let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
-                        let trait_item_def_id = self
-                            .tcx
-                            .associated_items(trait_did)
-                            .filter_by_name_unhygienic(impl_item.ident.name)
-                            .next()
-                            .map(|item| item.def_id);
-                        if let Some(def_id) = trait_item_def_id {
-                            // Pass `None` to skip deprecation warnings.
-                            self.tcx.check_stability(def_id, None, impl_item.span, None);
-                        }
+                for impl_item_ref in items {
+                    let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
+
+                    if let Some(def_id) = impl_item.trait_item_def_id {
+                        // Pass `None` to skip deprecation warnings.
+                        self.tcx.check_stability(def_id, None, impl_item_ref.span, None);
                     }
                 }
             }
index 61c82f031dd5b055ae639ca5570afdaa0da79e71..21514d19f6aac2223b94e2f2927a23a1ac0137aa 100644 (file)
@@ -1,6 +1,5 @@
 //! Validity checking for weak lang items
 
-use rustc_ast::Attribute;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
@@ -103,9 +102,8 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
     }
 
     fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) {
-        let check_name = |attr: &Attribute, sym| attr.has_name(sym);
         let attrs = self.tcx.hir().attrs(i.hir_id());
-        if let Some((lang_item, _)) = lang_items::extract(check_name, attrs) {
+        if let Some((lang_item, _)) = lang_items::extract(attrs) {
             self.register(lang_item, i.span);
         }
         intravisit::walk_foreign_item(self, i)
index 183a5a205ec829f7cb2574cf9a15f0fc2d8bfc33..7577b77181a061e308bd8c2e96ed3b8052556c30 100644 (file)
@@ -11,8 +11,7 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet};
-use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, DeepVisitor, NestedVisitorMap, Visitor};
 use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
 use rustc_middle::bug;
@@ -26,7 +25,7 @@
 use rustc_middle::ty::{self, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeFoldable};
 use rustc_session::lint;
 use rustc_span::hygiene::Transparency;
-use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::traits::const_evaluatable::{self, AbstractConst};
 
@@ -178,10 +177,6 @@ impl<'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'tcx, V>
 {
     type BreakTy = V::BreakTy;
 
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.def_id_visitor.tcx())
-    }
-
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<V::BreakTy> {
         let tcx = self.def_id_visitor.tcx();
         // InternalSubsts are not visited here because they are visited below in `super_visit_with`.
@@ -436,6 +431,15 @@ fn get(&self, def_id: LocalDefId) -> Option<AccessLevel> {
         self.access_levels.map.get(&def_id).copied()
     }
 
+    fn update_with_hir_id(
+        &mut self,
+        hir_id: hir::HirId,
+        level: Option<AccessLevel>,
+    ) -> Option<AccessLevel> {
+        let def_id = self.tcx.hir().local_def_id(hir_id);
+        self.update(def_id, level)
+    }
+
     /// Updates node level and returns the updated level.
     fn update(&mut self, def_id: LocalDefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
         let old_level = self.get(def_id);
@@ -520,7 +524,7 @@ fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod
             let vis = self.tcx.visibility(item_id.def_id);
             self.update_macro_reachable_def(item_id.def_id, def_kind, vis, defining_mod);
         }
-        if let Some(exports) = self.tcx.module_exports(module_def_id) {
+        if let Some(exports) = self.tcx.module_reexports(module_def_id) {
             for export in exports {
                 if export.vis.is_accessible_from(defining_mod.to_def_id(), self.tcx) {
                     if let Res::Def(def_kind, def_id) = export.res {
@@ -623,54 +627,6 @@ fn update_macro_reachable_def(
             | DefKind::Generator => (),
         }
     }
-
-    /// Given the path segments of an `ItemKind::Use`, then we need
-    /// to update the visibility of the intermediate use so that it isn't linted
-    /// by `unreachable_pub`.
-    ///
-    /// This isn't trivial as `path.res` has the `DefId` of the eventual target
-    /// of the use statement not of the next intermediate use statement.
-    ///
-    /// To do this, consider the last two segments of the path to our intermediate
-    /// use statement. We expect the penultimate segment to be a module and the
-    /// last segment to be the name of the item we are exporting. We can then
-    /// look at the items contained in the module for the use statement with that
-    /// name and update that item's visibility.
-    ///
-    /// FIXME: This solution won't work with glob imports and doesn't respect
-    /// namespaces. See <https://github.com/rust-lang/rust/pull/57922#discussion_r251234202>.
-    fn update_visibility_of_intermediate_use_statements(
-        &mut self,
-        segments: &[hir::PathSegment<'_>],
-    ) {
-        if let [.., module, segment] = segments {
-            if let Some(item) = module
-                .res
-                .and_then(|res| res.mod_def_id())
-                // If the module is `self`, i.e. the current crate,
-                // there will be no corresponding item.
-                .filter(|def_id| def_id.index != CRATE_DEF_INDEX || def_id.krate != LOCAL_CRATE)
-                .and_then(|def_id| def_id.as_local())
-                .map(|module_hir_id| self.tcx.hir().expect_item(module_hir_id))
-            {
-                if let hir::ItemKind::Mod(m) = &item.kind {
-                    for &item_id in m.item_ids {
-                        let item = self.tcx.hir().item(item_id);
-                        if !self.tcx.hygienic_eq(
-                            segment.ident,
-                            item.ident,
-                            item_id.def_id.to_def_id(),
-                        ) {
-                            continue;
-                        }
-                        if let hir::ItemKind::Use(..) = item.kind {
-                            self.update(item.def_id, Some(AccessLevel::Exported));
-                        }
-                    }
-                }
-            }
-        }
-    }
 }
 
 impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
@@ -683,56 +639,25 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        let inherited_item_level = match item.kind {
+        let item_level = match item.kind {
             hir::ItemKind::Impl { .. } => {
-                Option::<AccessLevel>::of_impl(item.def_id, self.tcx, &self.access_levels)
-            }
-            // Only exported `macro_rules!` items are public, but they always are.
-            hir::ItemKind::Macro(MacroDef { macro_rules: true, .. }) => {
-                let def_id = item.def_id.to_def_id();
-                let is_macro_export = self.tcx.has_attr(def_id, sym::macro_export);
-                if is_macro_export { Some(AccessLevel::Public) } else { None }
-            }
-            // Foreign modules inherit level from parents.
-            hir::ItemKind::ForeignMod { .. } => self.prev_level,
-            // Other `pub` items inherit levels from parents.
-            hir::ItemKind::Const(..)
-            | hir::ItemKind::Enum(..)
-            | hir::ItemKind::ExternCrate(..)
-            | hir::ItemKind::GlobalAsm(..)
-            | hir::ItemKind::Fn(..)
-            | hir::ItemKind::Macro(..)
-            | hir::ItemKind::Mod(..)
-            | hir::ItemKind::Static(..)
-            | hir::ItemKind::Struct(..)
-            | hir::ItemKind::Trait(..)
-            | hir::ItemKind::TraitAlias(..)
-            | hir::ItemKind::OpaqueTy(..)
-            | hir::ItemKind::TyAlias(..)
-            | hir::ItemKind::Union(..)
-            | hir::ItemKind::Use(..) => {
-                if item.vis.node.is_pub() {
-                    self.prev_level
-                } else {
-                    None
-                }
+                let impl_level =
+                    Option::<AccessLevel>::of_impl(item.def_id, self.tcx, &self.access_levels);
+                self.update(item.def_id, impl_level)
             }
+            _ => self.get(item.def_id),
         };
 
-        // Update level of the item itself.
-        let item_level = self.update(item.def_id, inherited_item_level);
-
         // Update levels of nested things.
         match item.kind {
             hir::ItemKind::Enum(ref def, _) => {
                 for variant in def.variants {
-                    let variant_level =
-                        self.update(self.tcx.hir().local_def_id(variant.id), item_level);
+                    let variant_level = self.update_with_hir_id(variant.id, item_level);
                     if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
-                        self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
+                        self.update_with_hir_id(ctor_hir_id, item_level);
                     }
                     for field in variant.data.fields() {
-                        self.update(self.tcx.hir().local_def_id(field.hir_id), variant_level);
+                        self.update_with_hir_id(field.hir_id, variant_level);
                     }
                 }
             }
@@ -752,11 +677,11 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             }
             hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
                 if let Some(ctor_hir_id) = def.ctor_hir_id() {
-                    self.update(self.tcx.hir().local_def_id(ctor_hir_id), item_level);
+                    self.update_with_hir_id(ctor_hir_id, item_level);
                 }
                 for field in def.fields() {
                     if field.vis.node.is_pub() {
-                        self.update(self.tcx.hir().local_def_id(field.hir_id), item_level);
+                        self.update_with_hir_id(field.hir_id, item_level);
                     }
                 }
             }
@@ -789,14 +714,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
             hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {}
             // All nested items are checked by `visit_item`.
             hir::ItemKind::Mod(..) => {}
-            // Re-exports are handled in `visit_mod`. However, in order to avoid looping over
-            // all of the items of a mod in `visit_mod` looking for use statements, we handle
-            // making sure that intermediate use statements have their visibilities updated here.
-            hir::ItemKind::Use(path, _) => {
-                if item_level.is_some() {
-                    self.update_visibility_of_intermediate_use_statements(path.segments.as_ref());
-                }
-            }
+            // Handled in the access level of in rustc_resolve
+            hir::ItemKind::Use(..) => {}
             // The interface is empty.
             hir::ItemKind::GlobalAsm(..) => {}
             hir::ItemKind::OpaqueTy(..) => {
@@ -920,27 +839,6 @@ fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) {
         intravisit::walk_block(self, b);
         self.prev_level = orig_level;
     }
-
-    fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _sp: Span, id: hir::HirId) {
-        // This code is here instead of in visit_item so that the
-        // crate module gets processed as well.
-        if self.prev_level.is_some() {
-            let def_id = self.tcx.hir().local_def_id(id);
-            if let Some(exports) = self.tcx.module_exports(def_id) {
-                for export in exports.iter() {
-                    if export.vis.is_public() {
-                        if let Some(def_id) = export.res.opt_def_id() {
-                            if let Some(def_id) = def_id.as_local() {
-                                self.update(def_id, Some(AccessLevel::Exported));
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        intravisit::walk_mod(self, m, id);
-    }
 }
 
 impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
@@ -1045,7 +943,7 @@ fn check_field(
         let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did, hir_id).1;
         if !field.vis.is_accessible_from(def_id, self.tcx) {
             let label = if in_update_syntax {
-                format!("field `{}` is private", field.ident)
+                format!("field `{}` is private", field.name)
             } else {
                 "private field".to_string()
             };
@@ -1055,7 +953,7 @@ fn check_field(
                 span,
                 E0451,
                 "field `{}` of {} `{}` is private",
-                field.ident,
+                field.name,
                 def.variant_descr(),
                 self.tcx.def_path_str(def.did)
             )
@@ -2122,7 +2020,7 @@ fn visibility(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Visibility {
                 // Visibilities of trait impl items are inherited from their traits
                 // and are not filled in resolve.
                 Node::ImplItem(impl_item) => {
-                    match tcx.hir().get(tcx.hir().get_parent_item(hir_id)) {
+                    match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(hir_id)) {
                         Node::Item(hir::Item {
                             kind: hir::ItemKind::Impl(hir::Impl { of_trait: Some(tr), .. }),
                             ..
@@ -2166,11 +2064,12 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels {
     // items which are reachable from external crates based on visibility.
     let mut visitor = EmbargoVisitor {
         tcx,
-        access_levels: Default::default(),
+        access_levels: tcx.resolutions(()).access_levels.clone(),
         macro_reachable: Default::default(),
         prev_level: Some(AccessLevel::Public),
         changed: false,
     };
+
     loop {
         tcx.hir().walk_toplevel_module(&mut visitor);
         if visitor.changed {
@@ -2179,7 +2078,6 @@ fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels {
             break;
         }
     }
-    visitor.update(CRATE_DEF_ID, Some(AccessLevel::Public));
 
     tcx.arena.alloc(visitor.access_levels)
 }
index f984bb1872b2842ea21538bd86a57566c4ceed6a..f1899a6fb2b07488338b77e27a86757d01775b72 100644 (file)
@@ -8,7 +8,7 @@ doctest = false
 
 [dependencies]
 measureme = "10.0.0"
-rustc-rayon-core = "0.3.1"
+rustc-rayon-core = "0.3.2"
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
index 898a8caa3ca351018ed4b9b3bb589f9c2896a31b..79f791eb7545f4075562711eb415b88d3325b628 100644 (file)
@@ -9,7 +9,7 @@ doctest = false
 [dependencies]
 rustc_arena = { path = "../rustc_arena" }
 tracing = "0.1"
-rustc-rayon-core = "0.3.1"
+rustc-rayon-core = "0.3.2"
 rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
index a8be1ca34c04f0f0e8cd59a8777d90e15a6eae13..a080b4a3e9ab58b5eba37cba571782db85d4b7af 100644 (file)
@@ -9,6 +9,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use smallvec::{smallvec, SmallVec};
+use std::assert_matches::assert_matches;
 use std::collections::hash_map::Entry;
 use std::fmt::Debug;
 use std::hash::Hash;
@@ -88,6 +89,11 @@ struct DepGraphData<K: DepKind> {
     previous_work_products: FxHashMap<WorkProductId, WorkProduct>,
 
     dep_node_debug: Lock<FxHashMap<DepNode<K>, String>>,
+
+    /// Used by incremental compilation tests to assert that
+    /// a particular query result was decoded from disk
+    /// (not just marked green)
+    debug_loaded_from_disk: Lock<FxHashSet<DepNode<K>>>,
 }
 
 pub fn hash_result<R>(hcx: &mut StableHashingContext<'_>, result: &R) -> Fingerprint
@@ -135,6 +141,7 @@ pub fn new(
                 processed_side_effects: Default::default(),
                 previous: prev_graph,
                 colors: DepNodeColorMap::new(prev_graph_node_count),
+                debug_loaded_from_disk: Default::default(),
             })),
             virtual_dep_node_index: Lrc::new(AtomicU32::new(0)),
         }
@@ -159,7 +166,11 @@ pub fn with_query(&self, f: impl Fn(&DepGraphQuery<K>)) {
     pub fn assert_ignored(&self) {
         if let Some(..) = self.data {
             K::read_deps(|task_deps| {
-                assert!(task_deps.is_none(), "expected no task dependency tracking");
+                assert_matches!(
+                    task_deps,
+                    TaskDepsRef::Ignore,
+                    "expected no task dependency tracking"
+                );
             })
         }
     }
@@ -168,7 +179,60 @@ pub fn with_ignore<OP, R>(&self, op: OP) -> R
     where
         OP: FnOnce() -> R,
     {
-        K::with_deps(None, op)
+        K::with_deps(TaskDepsRef::Ignore, op)
+    }
+
+    /// Used to wrap the deserialization of a query result from disk,
+    /// This method enforces that no new `DepNodes` are created during
+    /// query result deserialization.
+    ///
+    /// Enforcing this makes the query dep graph simpler - all nodes
+    /// must be created during the query execution, and should be
+    /// created from inside the 'body' of a query (the implementation
+    /// provided by a particular compiler crate).
+    ///
+    /// Consider the case of three queries `A`, `B`, and `C`, where
+    /// `A` invokes `B` and `B` invokes `C`:
+    ///
+    /// `A -> B -> C`
+    ///
+    /// Suppose that decoding the result of query `B` required re-computing
+    /// the query `C`. If we did not create a fresh `TaskDeps` when
+    /// decoding `B`, we would still be using the `TaskDeps` for query `A`
+    /// (if we needed to re-execute `A`). This would cause us to create
+    /// a new edge `A -> C`. If this edge did not previously
+    /// exist in the `DepGraph`, then we could end up with a different
+    /// `DepGraph` at the end of compilation, even if there were no
+    /// meaningful changes to the overall program (e.g. a newline was added).
+    /// In addition, this edge might cause a subsequent compilation run
+    /// to try to force `C` before marking other necessary nodes green. If
+    /// `C` did not exist in the new compilation session, then we could
+    /// get an ICE. Normally, we would have tried (and failed) to mark
+    /// some other query green (e.g. `item_children`) which was used
+    /// to obtain `C`, which would prevent us from ever trying to force
+    /// a non-existent `D`.
+    ///
+    /// It might be possible to enforce that all `DepNode`s read during
+    /// deserialization already exist in the previous `DepGraph`. In
+    /// the above example, we would invoke `D` during the deserialization
+    /// of `B`. Since we correctly create a new `TaskDeps` from the decoding
+    /// of `B`, this would result in an edge `B -> D`. If that edge already
+    /// existed (with the same `DepPathHash`es), then it should be correct
+    /// to allow the invocation of the query to proceed during deserialization
+    /// of a query result. We would merely assert that the dep-graph fragment
+    /// that would have been added by invoking `C` while decoding `B`
+    /// is equivalent to the dep-graph fragment that we already instantiated for B
+    /// (at the point where we successfully marked B as green).
+    ///
+    /// However, this would require additional complexity
+    /// in the query infrastructure, and is not currently needed by the
+    /// decoding of any query results. Should the need arise in the future,
+    /// we should consider extending the query system with this functionality.
+    pub fn with_query_deserialization<OP, R>(&self, op: OP) -> R
+    where
+        OP: FnOnce() -> R,
+    {
+        K::with_deps(TaskDepsRef::Forbid, op)
     }
 
     /// Starts a new dep-graph task. Dep-graph tasks are specified
@@ -253,7 +317,13 @@ fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
                 phantom_data: PhantomData,
             }))
         };
-        let result = K::with_deps(task_deps.as_ref(), || task(cx, arg));
+
+        let task_deps_ref = match &task_deps {
+            Some(deps) => TaskDepsRef::Allow(deps),
+            None => TaskDepsRef::Ignore,
+        };
+
+        let result = K::with_deps(task_deps_ref, || task(cx, arg));
         let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
 
         let dcx = cx.dep_context();
@@ -306,7 +376,7 @@ pub fn with_anon_task<Ctxt: DepContext<DepKind = K>, OP, R>(
 
         if let Some(ref data) = self.data {
             let task_deps = Lock::new(TaskDeps::default());
-            let result = K::with_deps(Some(&task_deps), op);
+            let result = K::with_deps(TaskDepsRef::Allow(&task_deps), op);
             let task_deps = task_deps.into_inner();
             let task_deps = task_deps.reads;
 
@@ -359,42 +429,47 @@ pub fn with_anon_task<Ctxt: DepContext<DepKind = K>, OP, R>(
     pub fn read_index(&self, dep_node_index: DepNodeIndex) {
         if let Some(ref data) = self.data {
             K::read_deps(|task_deps| {
-                if let Some(task_deps) = task_deps {
-                    let mut task_deps = task_deps.lock();
-                    let task_deps = &mut *task_deps;
-                    if cfg!(debug_assertions) {
-                        data.current.total_read_count.fetch_add(1, Relaxed);
+                let mut task_deps = match task_deps {
+                    TaskDepsRef::Allow(deps) => deps.lock(),
+                    TaskDepsRef::Ignore => return,
+                    TaskDepsRef::Forbid => {
+                        panic!("Illegal read of: {:?}", dep_node_index)
                     }
+                };
+                let task_deps = &mut *task_deps;
 
-                    // As long as we only have a low number of reads we can avoid doing a hash
-                    // insert and potentially allocating/reallocating the hashmap
-                    let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP {
-                        task_deps.reads.iter().all(|other| *other != dep_node_index)
-                    } else {
-                        task_deps.read_set.insert(dep_node_index)
-                    };
-                    if new_read {
-                        task_deps.reads.push(dep_node_index);
-                        if task_deps.reads.len() == TASK_DEPS_READS_CAP {
-                            // Fill `read_set` with what we have so far so we can use the hashset
-                            // next time
-                            task_deps.read_set.extend(task_deps.reads.iter().copied());
-                        }
+                if cfg!(debug_assertions) {
+                    data.current.total_read_count.fetch_add(1, Relaxed);
+                }
+
+                // As long as we only have a low number of reads we can avoid doing a hash
+                // insert and potentially allocating/reallocating the hashmap
+                let new_read = if task_deps.reads.len() < TASK_DEPS_READS_CAP {
+                    task_deps.reads.iter().all(|other| *other != dep_node_index)
+                } else {
+                    task_deps.read_set.insert(dep_node_index)
+                };
+                if new_read {
+                    task_deps.reads.push(dep_node_index);
+                    if task_deps.reads.len() == TASK_DEPS_READS_CAP {
+                        // Fill `read_set` with what we have so far so we can use the hashset
+                        // next time
+                        task_deps.read_set.extend(task_deps.reads.iter().copied());
+                    }
 
-                        #[cfg(debug_assertions)]
-                        {
-                            if let Some(target) = task_deps.node {
-                                if let Some(ref forbidden_edge) = data.current.forbidden_edge {
-                                    let src = forbidden_edge.index_to_node.lock()[&dep_node_index];
-                                    if forbidden_edge.test(&src, &target) {
-                                        panic!("forbidden edge {:?} -> {:?} created", src, target)
-                                    }
+                    #[cfg(debug_assertions)]
+                    {
+                        if let Some(target) = task_deps.node {
+                            if let Some(ref forbidden_edge) = data.current.forbidden_edge {
+                                let src = forbidden_edge.index_to_node.lock()[&dep_node_index];
+                                if forbidden_edge.test(&src, &target) {
+                                    panic!("forbidden edge {:?} -> {:?} created", src, target)
                                 }
                             }
                         }
-                    } else if cfg!(debug_assertions) {
-                        data.current.total_duplicate_read_count.fetch_add(1, Relaxed);
                     }
+                } else if cfg!(debug_assertions) {
+                    data.current.total_duplicate_read_count.fetch_add(1, Relaxed);
                 }
             })
         }
@@ -438,6 +513,14 @@ pub fn previous_work_products(&self) -> &FxHashMap<WorkProductId, WorkProduct> {
         &self.data.as_ref().unwrap().previous_work_products
     }
 
+    pub fn mark_debug_loaded_from_disk(&self, dep_node: DepNode<K>) {
+        self.data.as_ref().unwrap().debug_loaded_from_disk.lock().insert(dep_node);
+    }
+
+    pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode<K>) -> bool {
+        self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node)
+    }
+
     #[inline(always)]
     pub fn register_dep_node_debug_str<F>(&self, dep_node: DepNode<K>, debug_str_gen: F)
     where
@@ -1109,7 +1192,26 @@ fn debug_assert_not_in_new_nodes(
 const TASK_DEPS_READS_CAP: usize = 8;
 type EdgesVec = SmallVec<[DepNodeIndex; TASK_DEPS_READS_CAP]>;
 
-pub struct TaskDeps<K> {
+#[derive(Debug, Clone, Copy)]
+pub enum TaskDepsRef<'a, K: DepKind> {
+    /// New dependencies can be added to the
+    /// `TaskDeps`. This is used when executing a 'normal' query
+    /// (no `eval_always` modifier)
+    Allow(&'a Lock<TaskDeps<K>>),
+    /// New dependencies are ignored. This is used when
+    /// executing an `eval_always` query, since there's no
+    /// need to track dependencies for a query that's always
+    /// re-executed. This is also used for `dep_graph.with_ignore`
+    Ignore,
+    /// Any attempt to add new dependencies will cause a panic.
+    /// This is used when decoding a query result from disk,
+    /// to ensure that the decoding process doesn't itself
+    /// require the execution of any queries.
+    Forbid,
+}
+
+#[derive(Debug)]
+pub struct TaskDeps<K: DepKind> {
     #[cfg(debug_assertions)]
     node: Option<DepNode<K>>,
     reads: EdgesVec,
@@ -1117,7 +1219,7 @@ pub struct TaskDeps<K> {
     phantom_data: PhantomData<DepNode<K>>,
 }
 
-impl<K> Default for TaskDeps<K> {
+impl<K: DepKind> Default for TaskDeps<K> {
     fn default() -> Self {
         Self {
             #[cfg(debug_assertions)]
index 047fc9f10cc2f0e1e7e61e3fa4190400186b6ae0..5907ae309ca377abb9c5e81966f8999fa6e18a94 100644 (file)
@@ -5,13 +5,14 @@
 mod serialized;
 
 pub use dep_node::{DepNode, DepNodeParams, WorkProductId};
-pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct};
+pub use graph::{
+    hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, TaskDepsRef, WorkProduct,
+};
 pub use query::DepGraphQuery;
 pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex};
 
 use crate::ich::StableHashingContext;
 use rustc_data_structures::profiling::SelfProfilerRef;
-use rustc_data_structures::sync::Lock;
 use rustc_serialize::{opaque::FileEncoder, Encodable};
 use rustc_session::Session;
 
@@ -90,12 +91,12 @@ pub trait DepKind: Copy + fmt::Debug + Eq + Hash + Send + Encodable<FileEncoder>
     fn debug_node(node: &DepNode<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result;
 
     /// Execute the operation with provided dependencies.
-    fn with_deps<OP, R>(deps: Option<&Lock<TaskDeps<Self>>>, op: OP) -> R
+    fn with_deps<OP, R>(deps: TaskDepsRef<'_, Self>, op: OP) -> R
     where
         OP: FnOnce() -> R;
 
     /// Access dependencies from current implicit context.
     fn read_deps<OP>(op: OP)
     where
-        OP: for<'a> FnOnce(Option<&'a Lock<TaskDeps<Self>>>);
+        OP: for<'a> FnOnce(TaskDepsRef<'a, Self>);
 }
index 5f31fa04b8a6e1c099a846cf76a28ffa09462e65..76e21be17bc68e1665a02cc7e91d8a9d03a62c9b 100644 (file)
@@ -3,6 +3,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{HashingControls, NodeIdHashingMode};
 use rustc_data_structures::sync::Lrc;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -26,20 +27,15 @@ fn compute_ignored_attr_names() -> FxHashSet<Symbol> {
 pub struct StableHashingContext<'a> {
     definitions: &'a Definitions,
     cstore: &'a dyn CrateStore,
+    // The value of `-Z incremental-ignore-spans`.
+    // This field should only be used by `debug_opts_incremental_ignore_span`
+    incremental_ignore_spans: bool,
     pub(super) body_resolver: BodyResolver<'a>,
-    hash_spans: bool,
-    pub(super) node_id_hashing_mode: NodeIdHashingMode,
-
     // Very often, we are hashing something that does not need the
     // `CachingSourceMapView`, so we initialize it lazily.
     raw_source_map: &'a SourceMap,
     caching_source_map: Option<CachingSourceMapView<'a>>,
-}
-
-#[derive(PartialEq, Eq, Clone, Copy)]
-pub enum NodeIdHashingMode {
-    Ignore,
-    HashDefPath,
+    pub(super) hashing_controls: HashingControls,
 }
 
 /// The `BodyResolver` allows mapping a `BodyId` to the corresponding `hir::Body`.
@@ -70,10 +66,13 @@ fn new_with_or_without_spans(
             body_resolver: BodyResolver::Forbidden,
             definitions,
             cstore,
+            incremental_ignore_spans: sess.opts.debugging_opts.incremental_ignore_spans,
             caching_source_map: None,
             raw_source_map: sess.source_map(),
-            hash_spans: hash_spans_initial,
-            node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
+            hashing_controls: HashingControls {
+                hash_spans: hash_spans_initial,
+                node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
+            },
         }
     }
 
@@ -133,10 +132,10 @@ pub fn with_hir_bodies(
 
     #[inline]
     pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self, hash_spans: bool, f: F) {
-        let prev_hash_spans = self.hash_spans;
-        self.hash_spans = hash_spans;
+        let prev_hash_spans = self.hashing_controls.hash_spans;
+        self.hashing_controls.hash_spans = hash_spans;
         f(self);
-        self.hash_spans = prev_hash_spans;
+        self.hashing_controls.hash_spans = prev_hash_spans;
     }
 
     #[inline]
@@ -145,10 +144,10 @@ pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(
         mode: NodeIdHashingMode,
         f: F,
     ) {
-        let prev = self.node_id_hashing_mode;
-        self.node_id_hashing_mode = mode;
+        let prev = self.hashing_controls.node_id_hashing_mode;
+        self.hashing_controls.node_id_hashing_mode = mode;
         f(self);
-        self.node_id_hashing_mode = prev;
+        self.hashing_controls.node_id_hashing_mode = prev;
     }
 
     #[inline]
@@ -183,6 +182,11 @@ pub fn is_ignored_attr(&self, name: Symbol) -> bool {
         }
         IGNORED_ATTRIBUTES.with(|attrs| attrs.contains(&name))
     }
+
+    #[inline]
+    pub fn hashing_controls(&self) -> HashingControls {
+        self.hashing_controls.clone()
+    }
 }
 
 impl<'a> HashStable<StableHashingContext<'a>> for ast::NodeId {
@@ -195,7 +199,12 @@ fn hash_stable(&self, _: &mut StableHashingContext<'a>, _: &mut StableHasher) {
 impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
     #[inline]
     fn hash_spans(&self) -> bool {
-        self.hash_spans
+        self.hashing_controls.hash_spans
+    }
+
+    #[inline]
+    fn debug_opts_incremental_ignore_spans(&self) -> bool {
+        self.incremental_ignore_spans
     }
 
     #[inline]
@@ -215,6 +224,11 @@ fn span_data_to_lines_and_cols(
     ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)> {
         self.source_map().span_data_to_lines_and_cols(span)
     }
+
+    #[inline]
+    fn hashing_controls(&self) -> HashingControls {
+        self.hashing_controls.clone()
+    }
 }
 
 impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}
index 3a0aab81fdb7b257b32908ba0aaf26482bc8195e..bf3cf6a48fd03d706f11ebba2f091d0bc2aa446f 100644 (file)
@@ -3,8 +3,7 @@
 
 use crate::ich::hcx::BodyResolver;
 use crate::ich::{NodeIdHashingMode, StableHashingContext};
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir as hir;
 use std::mem;
 
@@ -12,7 +11,7 @@ impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
     #[inline]
     fn hash_hir_id(&mut self, hir_id: hir::HirId, hasher: &mut StableHasher) {
         let hcx = self;
-        match hcx.node_id_hashing_mode {
+        match hcx.hashing_controls.node_id_hashing_mode {
             NodeIdHashingMode::Ignore => {
                 // Don't do anything.
             }
@@ -47,28 +46,6 @@ fn hash_reference_to_item(&mut self, id: hir::HirId, hasher: &mut StableHasher)
         })
     }
 
-    #[inline]
-    fn hash_hir_mod(&mut self, module: &hir::Mod<'_>, hasher: &mut StableHasher) {
-        let hcx = self;
-        let hir::Mod { inner: ref inner_span, ref item_ids } = *module;
-
-        inner_span.hash_stable(hcx, hasher);
-
-        // Combining the `DefPathHash`s directly is faster than feeding them
-        // into the hasher. Because we use a commutative combine, we also don't
-        // have to sort the array.
-        let item_ids_hash = item_ids
-            .iter()
-            .map(|id| {
-                let def_path_hash = id.to_stable_hash_key(hcx);
-                def_path_hash.0
-            })
-            .fold(Fingerprint::ZERO, |a, b| a.combine_commutative(b));
-
-        item_ids.len().hash_stable(hcx, hasher);
-        item_ids_hash.hash_stable(hcx, hasher);
-    }
-
     fn hash_hir_expr(&mut self, expr: &hir::Expr<'_>, hasher: &mut StableHasher) {
         self.while_hashing_hir_bodies(true, |hcx| {
             let hir::Expr { hir_id: _, ref span, ref kind } = *expr;
@@ -112,12 +89,12 @@ fn hash_hir_visibility_kind(
 
     #[inline]
     fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self, f: F) {
-        let prev_hash_node_ids = self.node_id_hashing_mode;
-        self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
+        let prev_hash_node_ids = self.hashing_controls.node_id_hashing_mode;
+        self.hashing_controls.node_id_hashing_mode = NodeIdHashingMode::Ignore;
 
         f(self);
 
-        self.node_id_hashing_mode = prev_hash_node_ids;
+        self.hashing_controls.node_id_hashing_mode = prev_hash_node_ids;
     }
 
     #[inline]
index 54416902e5fb63e0104d73fb8167b96efa399ed9..c42fcc9c82e1eeda9d437d744b47df8a4c720b6f 100644 (file)
@@ -1,6 +1,7 @@
 //! ICH - Incremental Compilation Hash
 
-pub use self::hcx::{NodeIdHashingMode, StableHashingContext};
+pub use self::hcx::StableHashingContext;
+pub use rustc_data_structures::stable_hasher::NodeIdHashingMode;
 use rustc_span::symbol::{sym, Symbol};
 
 mod hcx;
index b08db39e245a80ecb59dbd2a078e1bc3b9d83219..da1f3617647804b835a289dcbb6ca6218ee54326 100644 (file)
@@ -9,7 +9,6 @@
     report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo, QueryShardJobId,
 };
 use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
-
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHasher};
 #[cfg(parallel_compiler)]
@@ -515,10 +514,20 @@ fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
     // Some things are never cached on disk.
     if query.cache_on_disk {
         let prof_timer = tcx.dep_context().profiler().incr_cache_loading();
-        let result = query.try_load_from_disk(tcx, prev_dep_node_index);
+
+        // The call to `with_query_deserialization` enforces that no new `DepNodes`
+        // are created during deserialization. See the docs of that method for more
+        // details.
+        let result = dep_graph
+            .with_query_deserialization(|| query.try_load_from_disk(tcx, prev_dep_node_index));
+
         prof_timer.finish_with_query_invocation_id(dep_node_index.into());
 
         if let Some(result) = result {
+            if unlikely!(tcx.dep_context().sess().opts.debugging_opts.query_dep_graph) {
+                dep_graph.mark_debug_loaded_from_disk(*dep_node)
+            }
+
             let prev_fingerprint = tcx
                 .dep_context()
                 .dep_graph()
diff --git a/compiler/rustc_resolve/src/access_levels.rs b/compiler/rustc_resolve/src/access_levels.rs
new file mode 100644 (file)
index 0000000..60cc424
--- /dev/null
@@ -0,0 +1,237 @@
+use rustc_ast::ast;
+use rustc_ast::visit;
+use rustc_ast::visit::Visitor;
+use rustc_ast::Crate;
+use rustc_ast::EnumDef;
+use rustc_ast::ForeignMod;
+use rustc_ast::NodeId;
+use rustc_ast_lowering::ResolverAstLowering;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::CRATE_DEF_ID;
+use rustc_middle::middle::privacy::AccessLevel;
+use rustc_middle::ty::Visibility;
+use rustc_span::sym;
+
+use crate::imports::ImportKind;
+use crate::BindingKey;
+use crate::NameBinding;
+use crate::NameBindingKind;
+use crate::Resolver;
+
+pub struct AccessLevelsVisitor<'r, 'a> {
+    r: &'r mut Resolver<'a>,
+    prev_level: Option<AccessLevel>,
+    changed: bool,
+}
+
+impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
+    /// Fills the `Resolver::access_levels` table with public & exported items
+    /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
+    /// need access to a TyCtxt for that.
+    pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
+        let mut visitor =
+            AccessLevelsVisitor { r, changed: false, prev_level: Some(AccessLevel::Public) };
+
+        visitor.set_access_level_def_id(CRATE_DEF_ID, Some(AccessLevel::Public));
+        visitor.set_exports_access_level(CRATE_DEF_ID);
+
+        while visitor.changed {
+            visitor.reset();
+            visit::walk_crate(&mut visitor, krate);
+        }
+
+        tracing::info!("resolve::access_levels: {:#?}", r.access_levels);
+    }
+
+    fn reset(&mut self) {
+        self.changed = false;
+        self.prev_level = Some(AccessLevel::Public);
+    }
+
+    /// Update the access level of the exports of the given module accordingly. The module access
+    /// level has to be Exported or Public.
+    /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
+    fn set_exports_access_level(&mut self, module_id: LocalDefId) {
+        assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
+
+        // Set the given binding access level to `AccessLevel::Public` and
+        // sets the rest of the `use` chain to `AccessLevel::Exported` until
+        // we hit the actual exported item.
+        let set_import_binding_access_level =
+            |this: &mut Self, mut binding: &NameBinding<'a>, mut access_level| {
+                while let NameBindingKind::Import { binding: nested_binding, import, .. } =
+                    binding.kind
+                {
+                    this.set_access_level(import.id, access_level);
+                    if let ImportKind::Single { additional_ids, .. } = import.kind {
+                        this.set_access_level(additional_ids.0, access_level);
+                        this.set_access_level(additional_ids.1, access_level);
+                    }
+
+                    access_level = Some(AccessLevel::Exported);
+                    binding = nested_binding;
+                }
+            };
+
+        let module_level = self.r.access_levels.map.get(&module_id).copied();
+        assert!(module_level >= Some(AccessLevel::Exported));
+
+        if let Some(exports) = self.r.reexport_map.get(&module_id) {
+            let pub_exports = exports
+                .iter()
+                .filter(|ex| ex.vis == Visibility::Public)
+                .cloned()
+                .collect::<Vec<_>>();
+
+            let module = self.r.get_module(module_id.to_def_id()).unwrap();
+            for export in pub_exports.into_iter() {
+                if let Some(export_def_id) = export.res.opt_def_id().and_then(|id| id.as_local()) {
+                    self.set_access_level_def_id(export_def_id, Some(AccessLevel::Exported));
+                }
+
+                if let Some(ns) = export.res.ns() {
+                    let key = BindingKey { ident: export.ident, ns, disambiguator: 0 };
+                    let name_res = self.r.resolution(module, key);
+                    if let Some(binding) = name_res.borrow().binding() {
+                        set_import_binding_access_level(self, binding, module_level)
+                    }
+                }
+            }
+        }
+    }
+
+    /// Sets the access level of the `LocalDefId` corresponding to the given `NodeId`.
+    /// This function will panic if the `NodeId` does not have a `LocalDefId`
+    fn set_access_level(
+        &mut self,
+        node_id: NodeId,
+        access_level: Option<AccessLevel>,
+    ) -> Option<AccessLevel> {
+        self.set_access_level_def_id(self.r.local_def_id(node_id), access_level)
+    }
+
+    fn set_access_level_def_id(
+        &mut self,
+        def_id: LocalDefId,
+        access_level: Option<AccessLevel>,
+    ) -> Option<AccessLevel> {
+        let old_level = self.r.access_levels.map.get(&def_id).copied();
+        if old_level < access_level {
+            self.r.access_levels.map.insert(def_id, access_level.unwrap());
+            self.changed = true;
+            access_level
+        } else {
+            old_level
+        }
+    }
+}
+
+impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
+    fn visit_item(&mut self, item: &'ast ast::Item) {
+        let inherited_item_level = match item.kind {
+            // Resolved in rustc_privacy when types are available
+            ast::ItemKind::Impl(..) => return,
+
+            // Only exported `macro_rules!` items are public, but they always are
+            ast::ItemKind::MacroDef(..) => {
+                let is_macro_export =
+                    item.attrs.iter().any(|attr| attr.has_name(sym::macro_export));
+                if is_macro_export { Some(AccessLevel::Public) } else { None }
+            }
+
+            // Foreign modules inherit level from parents.
+            ast::ItemKind::ForeignMod(..) => self.prev_level,
+
+            // Other `pub` items inherit levels from parents.
+            ast::ItemKind::ExternCrate(..)
+            | ast::ItemKind::Use(..)
+            | ast::ItemKind::Static(..)
+            | ast::ItemKind::Const(..)
+            | ast::ItemKind::Fn(..)
+            | ast::ItemKind::Mod(..)
+            | ast::ItemKind::GlobalAsm(..)
+            | ast::ItemKind::TyAlias(..)
+            | ast::ItemKind::Enum(..)
+            | ast::ItemKind::Struct(..)
+            | ast::ItemKind::Union(..)
+            | ast::ItemKind::Trait(..)
+            | ast::ItemKind::TraitAlias(..) => {
+                if item.vis.kind.is_pub() {
+                    self.prev_level
+                } else {
+                    None
+                }
+            }
+
+            // Should be unreachable at this stage
+            ast::ItemKind::MacCall(..) => panic!(
+                "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
+            ),
+        };
+
+        let access_level = self.set_access_level(item.id, inherited_item_level);
+
+        // Set access level of nested items.
+        // If it's a mod, also make the visitor walk all of its items
+        match item.kind {
+            ast::ItemKind::Mod(..) => {
+                if access_level.is_some() {
+                    self.set_exports_access_level(self.r.local_def_id(item.id));
+                }
+
+                let orig_level = std::mem::replace(&mut self.prev_level, access_level);
+                visit::walk_item(self, item);
+                self.prev_level = orig_level;
+            }
+
+            ast::ItemKind::ForeignMod(ForeignMod { ref items, .. }) => {
+                for nested in items {
+                    if nested.vis.kind.is_pub() {
+                        self.set_access_level(nested.id, access_level);
+                    }
+                }
+            }
+            ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
+                for variant in variants {
+                    let variant_level = self.set_access_level(variant.id, access_level);
+                    if let Some(ctor_id) = variant.data.ctor_id() {
+                        self.set_access_level(ctor_id, access_level);
+                    }
+
+                    for field in variant.data.fields() {
+                        self.set_access_level(field.id, variant_level);
+                    }
+                }
+            }
+            ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
+                if let Some(ctor_id) = def.ctor_id() {
+                    self.set_access_level(ctor_id, access_level);
+                }
+
+                for field in def.fields() {
+                    if field.vis.kind.is_pub() {
+                        self.set_access_level(field.id, access_level);
+                    }
+                }
+            }
+            ast::ItemKind::Trait(ref trait_kind) => {
+                for nested in trait_kind.items.iter() {
+                    self.set_access_level(nested.id, access_level);
+                }
+            }
+
+            ast::ItemKind::ExternCrate(..)
+            | ast::ItemKind::Use(..)
+            | ast::ItemKind::Static(..)
+            | ast::ItemKind::Const(..)
+            | ast::ItemKind::GlobalAsm(..)
+            | ast::ItemKind::TyAlias(..)
+            | ast::ItemKind::TraitAlias(..)
+            | ast::ItemKind::MacroDef(..)
+            | ast::ItemKind::Fn(..) => return,
+
+            // Unreachable kinds
+            ast::ItemKind::Impl(..) | ast::ItemKind::MacCall(..) => unreachable!(),
+        }
+    }
+}
index d57591186d87cacd58e8479f0cbb498f986afdd4..052770b201a5b7f19e6b3acd74db2d0bbf46e799 100644 (file)
@@ -26,7 +26,7 @@
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
 use rustc_metadata::creader::LoadedMacro;
 use rustc_middle::bug;
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
 use rustc_middle::ty;
 use rustc_session::cstore::CrateStore;
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind};
@@ -214,7 +214,7 @@ pub fn expect_module(&mut self, def_id: DefId) -> Module<'a> {
     }
 
     crate fn build_reduced_graph_external(&mut self, module: Module<'a>) {
-        for child in self.cstore().item_children_untracked(module.def_id(), self.session) {
+        for child in self.cstore().module_children_untracked(module.def_id(), self.session) {
             let parent_scope = ParentScope::module(module, self);
             BuildReducedGraphVisitor { r: self, parent_scope }
                 .build_reduced_graph_for_external_crate_res(child);
@@ -383,8 +383,6 @@ fn add_import(
             used: Cell::new(false),
         });
 
-        debug!("add_import({:?})", import);
-
         self.r.indeterminate_imports.push(import);
         match import.kind {
             // Don't add unresolved underscore imports to modules
@@ -455,7 +453,7 @@ fn build_reduced_graph_for_use_tree(
             prefix.is_empty() || prefix.len() == 1 && prefix[0].ident.name == kw::PathRoot
         };
         match use_tree.kind {
-            ast::UseTreeKind::Simple(rename, ..) => {
+            ast::UseTreeKind::Simple(rename, id1, id2) => {
                 let mut ident = use_tree.ident();
                 let mut module_path = prefix;
                 let mut source = module_path.pop().unwrap();
@@ -565,7 +563,9 @@ fn build_reduced_graph_for_use_tree(
                     },
                     type_ns_only,
                     nested,
+                    additional_ids: (id1, id2),
                 };
+
                 self.add_import(
                     module_path,
                     kind,
@@ -938,9 +938,9 @@ fn build_reduced_graph_for_block(&mut self, block: &Block) {
     }
 
     /// Builds the reduced graph for a single item in an external crate.
-    fn build_reduced_graph_for_external_crate_res(&mut self, child: Export) {
+    fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) {
         let parent = self.parent_scope.module;
-        let Export { ident, res, vis, span } = child;
+        let ModChild { ident, res, vis, span } = child;
         let res = res.expect_non_local();
         let expansion = self.parent_scope.expansion;
         // Record primary definitions.
@@ -1512,8 +1512,8 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) {
     }
 
     fn visit_crate(&mut self, krate: &'b ast::Crate) {
-        if let Some(id) = krate.is_placeholder {
-            self.visit_invoc_in_module(id);
+        if krate.is_placeholder {
+            self.visit_invoc_in_module(krate.id);
         } else {
             visit::walk_crate(self, krate);
             self.contains_macro_use(&krate.attrs);
index 688b7b1a8c6d25593472d8beb5c436c1d5be0760..8ea5dca6f108a64ae7a5cabe661fc66059c1a2f6 100644 (file)
@@ -344,8 +344,8 @@ fn visit_field_def(&mut self, field: &'a FieldDef) {
     }
 
     fn visit_crate(&mut self, krate: &'a Crate) {
-        if let Some(id) = krate.is_placeholder {
-            self.visit_macro_invoc(id)
+        if krate.is_placeholder {
+            self.visit_macro_invoc(krate.id)
         } else {
             visit::walk_crate(self, krate)
         }
index babfa8015af6c359f7b93addc9d16261e47d69c9..941c2a70d11ef91b34f25bd74dcf1e0bdfb0f27b 100644 (file)
@@ -602,6 +602,25 @@ impl<'a> Resolver<'a> {
 
                 err
             }
+            ResolutionError::TraitImplMismatch {
+                name,
+                kind,
+                code,
+                trait_item_span,
+                trait_path,
+            } => {
+                let mut err = self.session.struct_span_err_with_code(
+                    span,
+                    &format!(
+                        "item `{}` is an associated {}, which doesn't match its trait `{}`",
+                        name, kind, trait_path,
+                    ),
+                    code,
+                );
+                err.span_label(span, "does not match trait");
+                err.span_label(trait_item_span, "item in trait");
+                err
+            }
         }
     }
 
@@ -895,8 +914,11 @@ fn lookup_import_candidates_from_module<FilterFn>(
                             // a note about editions
                             let note = if let Some(did) = did {
                                 let requires_note = !did.is_local()
-                                    && this.cstore().item_attrs(did, this.session).iter().any(
-                                        |attr| {
+                                    && this
+                                        .cstore()
+                                        .item_attrs_untracked(did, this.session)
+                                        .iter()
+                                        .any(|attr| {
                                             if attr.has_name(sym::rustc_diagnostic_item) {
                                                 [sym::TryInto, sym::TryFrom, sym::FromIterator]
                                                     .map(|x| Some(x))
@@ -904,8 +926,7 @@ fn lookup_import_candidates_from_module<FilterFn>(
                                             } else {
                                                 false
                                             }
-                                        },
-                                    );
+                                        });
 
                                 requires_note.then(|| {
                                     format!(
index bf4cece8bde8d7f563c247fd7927732cb2d752e8..e7f76a18ad31addf4cb8608b1b052c2ed4260f1f 100644 (file)
@@ -15,7 +15,7 @@
 use rustc_errors::{pluralize, struct_span_err, Applicability};
 use rustc_hir::def::{self, PartialRes};
 use rustc_hir::def_id::DefId;
-use rustc_middle::hir::exports::Export;
+use rustc_middle::metadata::ModChild;
 use rustc_middle::span_bug;
 use rustc_middle::ty;
 use rustc_session::lint::builtin::{PUB_USE_OF_PRIVATE_EXTERN_CRATE, UNUSED_IMPORTS};
@@ -48,6 +48,9 @@ pub enum ImportKind<'a> {
         type_ns_only: bool,
         /// Did this import result from a nested import? ie. `use foo::{bar, baz};`
         nested: bool,
+        /// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement
+        /// (eg. implicit struct constructors)
+        additional_ids: (NodeId, NodeId),
     },
     Glob {
         is_prelude: bool,
@@ -834,7 +837,6 @@ fn resolve_import(&mut self, import: &'b Import<'b>) -> bool {
                         import.span,
                     );
                     import.vis.set(orig_vis);
-
                     source_bindings[ns].set(binding);
                 } else {
                     return;
@@ -1409,7 +1411,7 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>) {
             if is_good_import || binding.is_macro_def() {
                 let res = binding.res().expect_non_local();
                 if res != def::Res::Err {
-                    reexports.push(Export { ident, res, span: binding.span, vis: binding.vis });
+                    reexports.push(ModChild { ident, res, vis: binding.vis, span: binding.span });
                 }
             }
         });
@@ -1418,7 +1420,7 @@ fn finalize_resolutions_in(&mut self, module: Module<'b>) {
             if let Some(def_id) = module.opt_def_id() {
                 // Call to `expect_local` should be fine because current
                 // code is only called for local modules.
-                self.r.export_map.insert(def_id.expect_local(), reexports);
+                self.r.reexport_map.insert(def_id.expect_local(), reexports);
             }
         }
     }
index 5098cef11e83b4b793d90f8948370bff30fe367d..ccaaa2eaf4672d71f719b468017aad57ee00ac65 100644 (file)
@@ -520,9 +520,16 @@ fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
     }
     fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, _: NodeId) {
         let rib_kind = match fn_kind {
-            // Bail if there's no body.
-            FnKind::Fn(.., None) => return visit::walk_fn(self, fn_kind, sp),
-            FnKind::Fn(FnCtxt::Free | FnCtxt::Foreign, ..) => FnItemRibKind,
+            // Bail if the function is foreign, and thus cannot validly have
+            // a body, or if there's no body for some other reason.
+            FnKind::Fn(FnCtxt::Foreign, _, sig, ..) | FnKind::Fn(_, _, sig, .., None) => {
+                // We don't need to deal with patterns in parameters, because
+                // they are not possible for foreign or bodiless functions.
+                self.visit_fn_header(&sig.header);
+                visit::walk_fn_decl(self, &sig.decl);
+                return;
+            }
+            FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind,
             FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind,
             FnKind::Closure(..) => ClosureOrAsyncRibKind,
         };
@@ -1240,15 +1247,14 @@ fn with_optional_trait_ref<T>(
             );
             let res = res.base_res();
             if res != Res::Err {
-                new_id = Some(res.def_id());
-                let span = trait_ref.path.span;
                 if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path(
                     &path,
                     Some(TypeNS),
-                    false,
-                    span,
+                    true,
+                    trait_ref.path.span,
                     CrateLint::SimplePath(trait_ref.ref_id),
                 ) {
+                    new_id = Some(res.def_id());
                     new_val = Some((module, trait_ref.clone()));
                 }
             }
@@ -1317,6 +1323,7 @@ fn resolve_implementation(
                                             // If this is a trait impl, ensure the const
                                             // exists in trait
                                             this.check_trait_item(
+                                                item.id,
                                                 item.ident,
                                                 &item.kind,
                                                 ValueNS,
@@ -1352,6 +1359,7 @@ fn resolve_implementation(
                                                     // If this is a trait impl, ensure the method
                                                     // exists in trait
                                                     this.check_trait_item(
+                                                        item.id,
                                                         item.ident,
                                                         &item.kind,
                                                         ValueNS,
@@ -1379,6 +1387,7 @@ fn resolve_implementation(
                                                     // If this is a trait impl, ensure the type
                                                     // exists in trait
                                                     this.check_trait_item(
+                                                        item.id,
                                                         item.ident,
                                                         &item.kind,
                                                         TypeNS,
@@ -1409,7 +1418,8 @@ fn resolve_implementation(
 
     fn check_trait_item<F>(
         &mut self,
-        ident: Ident,
+        id: NodeId,
+        mut ident: Ident,
         kind: &AssocItemKind,
         ns: Namespace,
         span: Span,
@@ -1417,26 +1427,62 @@ fn check_trait_item<F>(
     ) where
         F: FnOnce(Ident, &str, Option<Symbol>) -> ResolutionError<'_>,
     {
-        // If there is a TraitRef in scope for an impl, then the method must be in the
-        // trait.
-        if let Some((module, _)) = self.current_trait_ref {
-            if self
-                .r
-                .resolve_ident_in_module(
-                    ModuleOrUniformRoot::Module(module),
-                    ident,
-                    ns,
-                    &self.parent_scope,
-                    false,
-                    span,
-                )
-                .is_err()
-            {
-                let candidate = self.find_similarly_named_assoc_item(ident.name, kind);
-                let path = &self.current_trait_ref.as_ref().unwrap().1.path;
-                self.report_error(span, err(ident, &path_names_to_string(path), candidate));
+        // If there is a TraitRef in scope for an impl, then the method must be in the trait.
+        let Some((module, _)) = &self.current_trait_ref else { return; };
+        ident.span.normalize_to_macros_2_0_and_adjust(module.expansion);
+        let key = self.r.new_key(ident, ns);
+        let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
+        debug!(?binding);
+        if binding.is_none() {
+            // We could not find the trait item in the correct namespace.
+            // Check the other namespace to report an error.
+            let ns = match ns {
+                ValueNS => TypeNS,
+                TypeNS => ValueNS,
+                _ => ns,
+            };
+            let key = self.r.new_key(ident, ns);
+            binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
+            debug!(?binding);
+        }
+        let Some(binding) = binding else {
+            // We could not find the method: report an error.
+            let candidate = self.find_similarly_named_assoc_item(ident.name, kind);
+            let path = &self.current_trait_ref.as_ref().unwrap().1.path;
+            self.report_error(span, err(ident, &path_names_to_string(path), candidate));
+            return;
+        };
+
+        let res = binding.res();
+        let Res::Def(def_kind, _) = res else { bug!() };
+        match (def_kind, kind) {
+            (DefKind::AssocTy, AssocItemKind::TyAlias(..))
+            | (DefKind::AssocFn, AssocItemKind::Fn(..))
+            | (DefKind::AssocConst, AssocItemKind::Const(..)) => {
+                self.r.record_partial_res(id, PartialRes::new(res));
+                return;
             }
+            _ => {}
         }
+
+        // The method kind does not correspond to what appeared in the trait, report.
+        let path = &self.current_trait_ref.as_ref().unwrap().1.path;
+        let (code, kind) = match kind {
+            AssocItemKind::Const(..) => (rustc_errors::error_code!(E0323), "const"),
+            AssocItemKind::Fn(..) => (rustc_errors::error_code!(E0324), "method"),
+            AssocItemKind::TyAlias(..) => (rustc_errors::error_code!(E0325), "type"),
+            AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"),
+        };
+        self.report_error(
+            span,
+            ResolutionError::TraitImplMismatch {
+                name: ident.name,
+                kind,
+                code,
+                trait_path: path_names_to_string(path),
+                trait_item_span: binding.span,
+            },
+        );
     }
 
     fn resolve_params(&mut self, params: &'ast [Param]) {
@@ -2379,7 +2425,9 @@ fn resolve_expr(&mut self, expr: &'ast Expr, parent: Option<&'ast Expr>) {
             ExprKind::While(ref cond, ref block, label) => {
                 self.with_resolved_label(label, expr.id, |this| {
                     this.with_rib(ValueNS, NormalRibKind, |this| {
+                        let old = this.diagnostic_metadata.in_if_condition.replace(cond);
                         this.visit_expr(cond);
+                        this.diagnostic_metadata.in_if_condition = old;
                         this.visit_block(block);
                     })
                 });
index 02e57109bbd830cd56f86146fd3e8e533853f899..01fc1b7012e2630518e1f7049a68ec2062465b9f 100644 (file)
@@ -376,12 +376,9 @@ 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| {
-            let hir_id = tcx.hir().local_def_id_to_hir_id(id);
-            match tcx.hir().find(hir_id) {
-                Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item),
-                _ => None,
-            }
+        object_lifetime_defaults_map: |tcx, id| match tcx.hir().find_by_def_id(id) {
+            Some(Node::Item(item)) => compute_object_lifetime_defaults(tcx, item),
+            _ => None,
         },
         late_bound_vars_map: |tcx, id| resolve_lifetimes_for(tcx, id).late_bound_vars.get(&id),
         lifetime_scope_map: |tcx, id| {
@@ -514,14 +511,14 @@ fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx R
 
 /// Finds the `Item` that contains the given `LocalDefId`
 fn item_for(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> LocalDefId {
-    let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
-    match tcx.hir().find(hir_id) {
+    match tcx.hir().find_by_def_id(local_def_id) {
         Some(Node::Item(item)) => {
             return item.def_id;
         }
         _ => {}
     }
     let item = {
+        let hir_id = tcx.hir().local_def_id_to_hir_id(local_def_id);
         let mut parent_iter = tcx.hir().parent_iter(hir_id);
         loop {
             let node = parent_iter.next().map(|n| n.1);
@@ -1137,7 +1134,7 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
                 self.missing_named_lifetime_spots.push((&trait_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
-                    Some(tcx.hir().get_parent_did(trait_item.hir_id())),
+                    Some(tcx.hir().get_parent_item(trait_item.hir_id())),
                     trait_item.hir_id(),
                     &sig.decl,
                     &trait_item.generics,
@@ -1206,7 +1203,7 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
                 self.missing_named_lifetime_spots.push((&impl_item.generics).into());
                 let tcx = self.tcx;
                 self.visit_early_late(
-                    Some(tcx.hir().get_parent_did(impl_item.hir_id())),
+                    Some(tcx.hir().get_parent_item(impl_item.hir_id())),
                     impl_item.hir_id(),
                     &sig.decl,
                     &impl_item.generics,
@@ -1672,13 +1669,10 @@ fn check_if_label_shadows_lifetime(tcx: TyCtxt<'_>, mut scope: ScopeRef<'_>, lab
                     if let Some(def) =
                         lifetimes.get(&hir::ParamName::Plain(label.normalize_to_macros_2_0()))
                     {
-                        let hir_id =
-                            tcx.hir().local_def_id_to_hir_id(def.id().unwrap().expect_local());
-
                         signal_shadowing_problem(
                             tcx,
                             label.name,
-                            original_lifetime(tcx.hir().span(hir_id)),
+                            original_lifetime(tcx.def_span(def.id().unwrap().expect_local())),
                             shadower_label(label.span),
                         );
                         return;
@@ -1910,6 +1904,7 @@ fn suggest_eliding_single_use_lifetime(
         let remove_decl = self
             .tcx
             .parent(def_id)
+            .and_then(|parent_def_id| parent_def_id.as_local())
             .and_then(|parent_def_id| self.tcx.hir().get_generics(parent_def_id))
             .and_then(|generics| self.lifetime_deletion_span(name, generics));
 
@@ -1950,7 +1945,7 @@ fn suggest_eliding_single_use_lifetime(
         };
         if let Node::Lifetime(hir_lifetime) = self.tcx.hir().get(lifetime.hir_id) {
             if let Some(parent) =
-                self.tcx.hir().find(self.tcx.hir().get_parent_item(hir_lifetime.hir_id))
+                self.tcx.hir().find_by_def_id(self.tcx.hir().get_parent_item(hir_lifetime.hir_id))
             {
                 match parent {
                     Node::Item(item) => {
@@ -2032,19 +2027,20 @@ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
 
             match lifetimeuseset {
                 Some(LifetimeUseSet::One(lifetime)) => {
-                    let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-                    debug!("hir id first={:?}", hir_id);
-                    if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) {
-                        Node::Lifetime(hir_lifetime) => Some((
-                            hir_lifetime.hir_id,
-                            hir_lifetime.span,
-                            hir_lifetime.name.ident(),
-                        )),
-                        Node::GenericParam(param) => {
-                            Some((param.hir_id, param.span, param.name.ident()))
+                    debug!(?def_id);
+                    if let Some((id, span, name)) =
+                        match self.tcx.hir().get_by_def_id(def_id.expect_local()) {
+                            Node::Lifetime(hir_lifetime) => Some((
+                                hir_lifetime.hir_id,
+                                hir_lifetime.span,
+                                hir_lifetime.name.ident(),
+                            )),
+                            Node::GenericParam(param) => {
+                                Some((param.hir_id, param.span, param.name.ident()))
+                            }
+                            _ => None,
                         }
-                        _ => None,
-                    } {
+                    {
                         debug!("id = {:?} span = {:?} name = {:?}", id, span, name);
                         if name.name == kw::UnderscoreLifetime {
                             continue;
@@ -2052,12 +2048,10 @@ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
 
                         if let Some(parent_def_id) = self.tcx.parent(def_id) {
                             if let Some(def_id) = parent_def_id.as_local() {
-                                let parent_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
                                 // lifetimes in `derive` expansions don't count (Issue #53738)
                                 if self
                                     .tcx
-                                    .hir()
-                                    .attrs(parent_hir_id)
+                                    .get_attrs(def_id.to_def_id())
                                     .iter()
                                     .any(|attr| attr.has_name(sym::automatically_derived))
                                 {
@@ -2069,7 +2063,7 @@ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
                                 if let hir::Node::Item(hir::Item {
                                     kind: hir::ItemKind::OpaqueTy(ref opaque),
                                     ..
-                                }) = self.tcx.hir().get(parent_hir_id)
+                                }) = self.tcx.hir().get_by_def_id(def_id)
                                 {
                                     if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
                                         continue 'lifetimes;
@@ -2115,18 +2109,19 @@ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
                     debug!("not one use lifetime");
                 }
                 None => {
-                    let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-                    if let Some((id, span, name)) = match self.tcx.hir().get(hir_id) {
-                        Node::Lifetime(hir_lifetime) => Some((
-                            hir_lifetime.hir_id,
-                            hir_lifetime.span,
-                            hir_lifetime.name.ident(),
-                        )),
-                        Node::GenericParam(param) => {
-                            Some((param.hir_id, param.span, param.name.ident()))
+                    if let Some((id, span, name)) =
+                        match self.tcx.hir().get_by_def_id(def_id.expect_local()) {
+                            Node::Lifetime(hir_lifetime) => Some((
+                                hir_lifetime.hir_id,
+                                hir_lifetime.span,
+                                hir_lifetime.name.ident(),
+                            )),
+                            Node::GenericParam(param) => {
+                                Some((param.hir_id, param.span, param.name.ident()))
+                            }
+                            _ => None,
                         }
-                        _ => None,
-                    } {
+                    {
                         debug!("id ={:?} span = {:?} name = {:?}", id, span, name);
                         self.tcx.struct_span_lint_hir(
                             lint::builtin::UNUSED_LIFETIMES,
@@ -2137,7 +2132,7 @@ fn check_uses_for_lifetimes_defined_by_scope(&mut self) {
                                     .build(&format!("lifetime parameter `{}` never used", name));
                                 if let Some(parent_def_id) = self.tcx.parent(def_id) {
                                     if let Some(generics) =
-                                        self.tcx.hir().get_generics(parent_def_id)
+                                        self.tcx.hir().get_generics(parent_def_id.expect_local())
                                     {
                                         let unused_lt_span =
                                             self.lifetime_deletion_span(name, generics);
@@ -2761,7 +2756,7 @@ fn visit_fn_like_elision(
 
             Node::TraitItem(&hir::TraitItem { kind: hir::TraitItemKind::Fn(_, ref m), .. }) => {
                 if let hir::ItemKind::Trait(.., ref trait_items) =
-                    self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(parent)).kind
+                    self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
                 {
                     assoc_item_kind =
                         trait_items.iter().find(|ti| ti.id.hir_id() == parent).map(|ti| ti.kind);
@@ -2774,7 +2769,7 @@ fn visit_fn_like_elision(
 
             Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body), .. }) => {
                 if let hir::ItemKind::Impl(hir::Impl { ref self_ty, ref items, .. }) =
-                    self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(parent)).kind
+                    self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(parent)).kind
                 {
                     impl_self = Some(self_ty);
                     assoc_item_kind =
@@ -3339,13 +3334,10 @@ fn check_lifetime_param_for_shadowing(
 
                 Scope::Binder { ref lifetimes, s, .. } => {
                     if let Some(&def) = lifetimes.get(&param.name.normalize_to_macros_2_0()) {
-                        let hir_id =
-                            self.tcx.hir().local_def_id_to_hir_id(def.id().unwrap().expect_local());
-
                         signal_shadowing_problem(
                             self.tcx,
                             param.name.ident().name,
-                            original_lifetime(self.tcx.hir().span(hir_id)),
+                            original_lifetime(self.tcx.def_span(def.id().unwrap())),
                             shadower_lifetime(&param),
                         );
                         return;
index 26344080381daba1d0deea4f9811fb37eefc0b78..25137c6eda763e7c94767e827b66c536970442e0 100644 (file)
@@ -49,7 +49,8 @@
 use rustc_hir::TraitCandidate;
 use rustc_index::vec::IndexVec;
 use rustc_metadata::creader::{CStore, CrateLoader};
-use rustc_middle::hir::exports::ExportMap;
+use rustc_middle::metadata::ModChild;
+use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs};
@@ -68,7 +69,7 @@
 use std::cell::{Cell, RefCell};
 use std::collections::{BTreeMap, BTreeSet};
 use std::ops::ControlFlow;
-use std::{cmp, fmt, iter, ptr};
+use std::{cmp, fmt, iter, mem, ptr};
 use tracing::debug;
 
 use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_next_binding};
 use late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind::*};
 use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 
+use crate::access_levels::AccessLevelsVisitor;
+
 type Res = def::Res<NodeId>;
 
+mod access_levels;
 mod build_reduced_graph;
 mod check_unused;
 mod def_collector;
@@ -258,6 +262,14 @@ enum ResolutionError<'a> {
     SelfInGenericParamDefault,
     /// Error E0767: use of unreachable label
     UnreachableLabel { name: Symbol, definition_span: Span, suggestion: Option<LabelSuggestion> },
+    /// Error E0323, E0324, E0325: mismatch between trait item and impl item.
+    TraitImplMismatch {
+        name: Symbol,
+        kind: &'static str,
+        trait_path: String,
+        trait_item_span: Span,
+        code: rustc_errors::DiagnosticId,
+    },
 }
 
 enum VisResolutionError<'a> {
@@ -927,7 +939,7 @@ pub struct Resolver<'a> {
 
     /// `CrateNum` resolutions of `extern crate` items.
     extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
-    export_map: ExportMap,
+    reexport_map: FxHashMap<LocalDefId, Vec<ModChild>>,
     trait_map: NodeMap<Vec<TraitCandidate>>,
 
     /// A map from nodes to anonymous modules.
@@ -1052,6 +1064,8 @@ pub struct Resolver<'a> {
     /// they are declared in the static array generated by proc_macro_harness.
     proc_macros: Vec<NodeId>,
     confused_type_with_std_module: FxHashMap<Span, Span>,
+
+    access_levels: AccessLevels,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1333,7 +1347,7 @@ pub fn new(
             import_res_map: Default::default(),
             label_res_map: Default::default(),
             extern_crate_map: Default::default(),
-            export_map: FxHashMap::default(),
+            reexport_map: FxHashMap::default(),
             trait_map: NodeMap::default(),
             underscore_disambiguator: 0,
             empty_module,
@@ -1394,7 +1408,7 @@ pub fn new(
                 .chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat))
                 .collect(),
             lint_buffer: LintBuffer::default(),
-            next_node_id: NodeId::from_u32(1),
+            next_node_id: CRATE_NODE_ID,
             node_id_to_def_id,
             def_id_to_node_id,
             placeholder_field_indices: Default::default(),
@@ -1407,6 +1421,7 @@ pub fn new(
             trait_impls: Default::default(),
             proc_macros: Default::default(),
             confused_type_with_std_module: Default::default(),
+            access_levels: Default::default(),
         };
 
         let root_parent_scope = ParentScope::module(graph_root, &resolver);
@@ -1430,8 +1445,7 @@ fn new_module(
     pub fn next_node_id(&mut self) -> NodeId {
         let next =
             self.next_node_id.as_u32().checked_add(1).expect("input too large; ran out of NodeIds");
-        self.next_node_id = ast::NodeId::from_u32(next);
-        self.next_node_id
+        mem::replace(&mut self.next_node_id, ast::NodeId::from_u32(next))
     }
 
     pub fn lint_buffer(&mut self) -> &mut LintBuffer {
@@ -1447,18 +1461,20 @@ pub fn into_outputs(self) -> ResolverOutputs {
         let definitions = self.definitions;
         let visibilities = self.visibilities;
         let extern_crate_map = self.extern_crate_map;
-        let export_map = self.export_map;
+        let reexport_map = self.reexport_map;
         let maybe_unused_trait_imports = self.maybe_unused_trait_imports;
         let maybe_unused_extern_crates = self.maybe_unused_extern_crates;
         let glob_map = self.glob_map;
         let main_def = self.main_def;
         let confused_type_with_std_module = self.confused_type_with_std_module;
+        let access_levels = self.access_levels;
         ResolverOutputs {
             definitions,
             cstore: Box::new(self.crate_loader.into_cstore()),
             visibilities,
+            access_levels,
             extern_crate_map,
-            export_map,
+            reexport_map,
             glob_map,
             maybe_unused_trait_imports,
             maybe_unused_extern_crates,
@@ -1478,10 +1494,11 @@ pub fn clone_outputs(&self) -> ResolverOutputs {
         let proc_macros = self.proc_macros.iter().map(|id| self.local_def_id(*id)).collect();
         ResolverOutputs {
             definitions: self.definitions.clone(),
+            access_levels: self.access_levels.clone(),
             cstore: Box::new(self.cstore().clone()),
             visibilities: self.visibilities.clone(),
             extern_crate_map: self.extern_crate_map.clone(),
-            export_map: self.export_map.clone(),
+            reexport_map: self.reexport_map.clone(),
             glob_map: self.glob_map.clone(),
             maybe_unused_trait_imports: self.maybe_unused_trait_imports.clone(),
             maybe_unused_extern_crates: self.maybe_unused_extern_crates.clone(),
@@ -1533,6 +1550,9 @@ fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId {
     pub fn resolve_crate(&mut self, krate: &Crate) {
         self.session.time("resolve_crate", || {
             self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
+            self.session.time("resolve_access_levels", || {
+                AccessLevelsVisitor::compute_access_levels(self, krate)
+            });
             self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
             self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
             self.session.time("resolve_main", || self.resolve_main());
@@ -3421,7 +3441,7 @@ pub fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
 
                 let attr = self
                     .cstore()
-                    .item_attrs(def_id, self.session)
+                    .item_attrs_untracked(def_id, self.session)
                     .into_iter()
                     .find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
                 let mut ret = Vec::new();
index f1a5282b08871323aa2b0a18be0103481ae1fffd..23f5b17fa78893187e796d3fe5c5fa452041cb27 100644 (file)
@@ -1326,12 +1326,18 @@ fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
                 }
                 intravisit::walk_qpath(self, path, t.hir_id, t.span);
             }
-            hir::TyKind::Array(ref ty, ref anon_const) => {
+            hir::TyKind::Array(ref ty, ref length) => {
                 self.visit_ty(ty);
                 let map = self.tcx.hir();
-                self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
-                    v.visit_expr(&map.body(anon_const.body).value)
-                });
+                match length {
+                    // FIXME(generic_arg_infer): We probably want to
+                    // output the inferred type here? :shrug:
+                    hir::ArrayLen::Infer(..) => {}
+                    hir::ArrayLen::Body(anon_const) => self
+                        .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                            v.visit_expr(&map.body(anon_const.body).value)
+                        }),
+                }
             }
             hir::TyKind::OpaqueDef(item_id, _) => {
                 let item = self.tcx.hir().item(item_id);
@@ -1390,12 +1396,18 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
                     v.visit_expr(&body.value)
                 });
             }
-            hir::ExprKind::Repeat(ref expr, ref anon_const) => {
+            hir::ExprKind::Repeat(ref expr, ref length) => {
                 self.visit_expr(expr);
                 let map = self.tcx.hir();
-                self.nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
-                    v.visit_expr(&map.body(anon_const.body).value)
-                });
+                match length {
+                    // FIXME(generic_arg_infer): We probably want to
+                    // output the inferred type here? :shrug:
+                    hir::ArrayLen::Infer(..) => {}
+                    hir::ArrayLen::Body(anon_const) => self
+                        .nest_typeck_results(self.tcx.hir().local_def_id(anon_const.hir_id), |v| {
+                            v.visit_expr(&map.body(anon_const.body).value)
+                        }),
+                }
             }
             // In particular, we take this branch for call and path expressions,
             // where we'll index the idents involved just by continuing to walk.
index 7ec619e07ff9bb7cd5090589df83fee4f3f9ad8d..a83f02308145e57a704b599d001b1d24706d1fee 100644 (file)
@@ -710,13 +710,11 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool {
             }
             Res::Def(HirDefKind::AssocFn, decl_id) => {
                 let def_id = if decl_id.is_local() {
-                    let ti = self.tcx.associated_item(decl_id);
-
-                    self.tcx
-                        .associated_items(ti.container.id())
-                        .filter_by_name_unhygienic(ti.ident.name)
-                        .find(|item| item.defaultness.has_value())
-                        .map(|item| item.def_id)
+                    if self.tcx.associated_item(decl_id).defaultness.has_value() {
+                        Some(decl_id)
+                    } else {
+                        None
+                    }
                 } else {
                     None
                 };
index e43344ad6d9eff888d516d082d52d2cec971fe67..4971bb6d1aad7bff565fd43bf957cfae6b7620cd 100644 (file)
@@ -310,9 +310,9 @@ fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<
                 let nested = bounds_to_string(&bounds);
                 Ok(text_sig(nested))
             }
-            hir::TyKind::Array(ref ty, ref anon_const) => {
+            hir::TyKind::Array(ref ty, ref length) => {
                 let nested_ty = ty.make(offset + 1, id, scx)?;
-                let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " ");
+                let expr = id_to_string(&scx.tcx.hir(), length.hir_id()).replace('\n', " ");
                 let text = format!("[{}; {}]", nested_ty.text, expr);
                 Ok(replace_text(nested_ty, text))
             }
index ea2df80e641683b08017500a5659d4a78af331be..08b3c054200b72d9490f0e9173ee86bdb88b3ae8 100644 (file)
@@ -53,16 +53,24 @@ pub fn $fn_name(
 macro_rules! impl_read_unsigned_leb128 {
     ($fn_name:ident, $int_ty:ty) => {
         #[inline]
-        pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
-            let mut result = 0;
-            let mut shift = 0;
-            let mut position = 0;
+        pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty {
+            // The first iteration of this loop is unpeeled. This is a
+            // performance win because this code is hot and integer values less
+            // than 128 are very common, typically occurring 50-80% or more of
+            // the time, even for u64 and u128.
+            let byte = slice[*position];
+            *position += 1;
+            if (byte & 0x80) == 0 {
+                return byte as $int_ty;
+            }
+            let mut result = (byte & 0x7F) as $int_ty;
+            let mut shift = 7;
             loop {
-                let byte = slice[position];
-                position += 1;
+                let byte = slice[*position];
+                *position += 1;
                 if (byte & 0x80) == 0 {
                     result |= (byte as $int_ty) << shift;
-                    return (result, position);
+                    return result;
                 } else {
                     result |= ((byte & 0x7F) as $int_ty) << shift;
                 }
@@ -122,15 +130,14 @@ pub fn $fn_name(
 macro_rules! impl_read_signed_leb128 {
     ($fn_name:ident, $int_ty:ty) => {
         #[inline]
-        pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
+        pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty {
             let mut result = 0;
             let mut shift = 0;
-            let mut position = 0;
             let mut byte;
 
             loop {
-                byte = slice[position];
-                position += 1;
+                byte = slice[*position];
+                *position += 1;
                 result |= <$int_ty>::from(byte & 0x7F) << shift;
                 shift += 7;
 
@@ -144,7 +151,7 @@ pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) {
                 result |= (!0 << shift);
             }
 
-            (result, position)
+            result
         }
     };
 }
index cc1216418ae79306d54a5b46bb6b69a261afcdef..078237801be695142e5a6c8d8bb1fadcd5273b58 100644 (file)
@@ -92,7 +92,8 @@ fn emit_u32(&mut self, v: u32) -> EncodeResult {
 
     #[inline]
     fn emit_u16(&mut self, v: u16) -> EncodeResult {
-        write_leb128!(self, v, u16, write_u16_leb128)
+        self.data.extend_from_slice(&v.to_le_bytes());
+        Ok(())
     }
 
     #[inline]
@@ -123,7 +124,8 @@ fn emit_i32(&mut self, v: i32) -> EncodeResult {
 
     #[inline]
     fn emit_i16(&mut self, v: i16) -> EncodeResult {
-        write_leb128!(self, v, i16, write_i16_leb128)
+        self.data.extend_from_slice(&v.to_le_bytes());
+        Ok(())
     }
 
     #[inline]
@@ -446,7 +448,7 @@ fn emit_u32(&mut self, v: u32) -> FileEncodeResult {
 
     #[inline]
     fn emit_u16(&mut self, v: u16) -> FileEncodeResult {
-        file_encoder_write_leb128!(self, v, u16, write_u16_leb128)
+        self.write_all(&v.to_le_bytes())
     }
 
     #[inline]
@@ -476,13 +478,12 @@ fn emit_i32(&mut self, v: i32) -> FileEncodeResult {
 
     #[inline]
     fn emit_i16(&mut self, v: i16) -> FileEncodeResult {
-        file_encoder_write_leb128!(self, v, i16, write_i16_leb128)
+        self.write_all(&v.to_le_bytes())
     }
 
     #[inline]
     fn emit_i8(&mut self, v: i8) -> FileEncodeResult {
-        let as_u8: u8 = unsafe { std::mem::transmute(v) };
-        self.emit_u8(as_u8)
+        self.emit_u8(v as u8)
     }
 
     #[inline]
@@ -559,11 +560,7 @@ pub fn read_raw_bytes(&mut self, bytes: usize) -> &'a [u8] {
 }
 
 macro_rules! read_leb128 {
-    ($dec:expr, $fun:ident) => {{
-        let (value, bytes_read) = leb128::$fun(&$dec.data[$dec.position..]);
-        $dec.position += bytes_read;
-        Ok(value)
-    }};
+    ($dec:expr, $fun:ident) => {{ Ok(leb128::$fun($dec.data, &mut $dec.position)) }};
 }
 
 impl<'a> serialize::Decoder for Decoder<'a> {
@@ -591,7 +588,10 @@ fn read_u32(&mut self) -> Result<u32, Self::Error> {
 
     #[inline]
     fn read_u16(&mut self) -> Result<u16, Self::Error> {
-        read_leb128!(self, read_u16_leb128)
+        let bytes = [self.data[self.position], self.data[self.position + 1]];
+        let value = u16::from_le_bytes(bytes);
+        self.position += 2;
+        Ok(value)
     }
 
     #[inline]
@@ -623,7 +623,10 @@ fn read_i32(&mut self) -> Result<i32, Self::Error> {
 
     #[inline]
     fn read_i16(&mut self) -> Result<i16, Self::Error> {
-        read_leb128!(self, read_i16_leb128)
+        let bytes = [self.data[self.position], self.data[self.position + 1]];
+        let value = i16::from_le_bytes(bytes);
+        self.position += 2;
+        Ok(value)
     }
 
     #[inline]
index 3e2aab5125ab7b5fd98e5daf67f399639aa3414e..314c07db981daccfca32eda6f492c0962e57bf03 100644 (file)
@@ -30,9 +30,8 @@ fn $test_name() {
 
             let mut position = 0;
             for &expected in &values {
-                let (actual, bytes_read) = $read_fn_name(&stream[position..]);
+                let actual = $read_fn_name(&stream, &mut position);
                 assert_eq!(expected, actual);
-                position += bytes_read;
             }
             assert_eq!(stream.len(), position);
         }
@@ -77,9 +76,8 @@ fn $test_name() {
 
             let mut position = 0;
             for &expected in &values {
-                let (actual, bytes_read) = $read_fn_name(&stream[position..]);
+                let actual = $read_fn_name(&stream, &mut position);
                 assert_eq!(expected, actual);
-                position += bytes_read;
             }
             assert_eq!(stream.len(), position);
         }
index 607ee8da975ccb0457455e0d52921355a2dd58b8..62b351f5e0279a54eabbcdbe6386df03ebdf4585 100644 (file)
@@ -231,6 +231,37 @@ pub enum DebugInfo {
     Full,
 }
 
+/// Split debug-information is enabled by `-C split-debuginfo`, this enum is only used if split
+/// debug-information is enabled (in either `Packed` or `Unpacked` modes), and the platform
+/// uses DWARF for debug-information.
+///
+/// Some debug-information requires link-time relocation and some does not. LLVM can partition
+/// the debuginfo into sections depending on whether or not it requires link-time relocation. Split
+/// DWARF provides a mechanism which allows the linker to skip the sections which don't require
+/// link-time relocation - either by putting those sections in DWARF object files, or by keeping
+/// them in the object file in such a way that the linker will skip them.
+#[derive(Clone, Copy, Debug, PartialEq, Hash)]
+pub enum SplitDwarfKind {
+    /// Sections which do not require relocation are written into object file but ignored by the
+    /// linker.
+    Single,
+    /// Sections which do not require relocation are written into a DWARF object (`.dwo`) file
+    /// which is ignored by the linker.
+    Split,
+}
+
+impl FromStr for SplitDwarfKind {
+    type Err = ();
+
+    fn from_str(s: &str) -> Result<Self, ()> {
+        Ok(match s {
+            "single" => SplitDwarfKind::Single,
+            "split" => SplitDwarfKind::Split,
+            _ => return Err(()),
+        })
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
 #[derive(Encodable, Decodable)]
 pub enum OutputType {
@@ -378,7 +409,7 @@ pub fn len(&self) -> usize {
         self.0.len()
     }
 
-    // Returns `true` if any of the output types require codegen or linking.
+    /// Returns `true` if any of the output types require codegen or linking.
     pub fn should_codegen(&self) -> bool {
         self.0.keys().any(|k| match *k {
             OutputType::Bitcode
@@ -391,7 +422,7 @@ pub fn should_codegen(&self) -> bool {
         })
     }
 
-    // Returns `true` if any of the output types require linking.
+    /// Returns `true` if any of the output types require linking.
     pub fn should_link(&self) -> bool {
         self.0.keys().any(|k| match *k {
             OutputType::Bitcode
@@ -681,18 +712,23 @@ fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) ->
     pub fn split_dwarf_path(
         &self,
         split_debuginfo_kind: SplitDebuginfo,
+        split_dwarf_kind: SplitDwarfKind,
         cgu_name: Option<&str>,
     ) -> Option<PathBuf> {
         let obj_out = self.temp_path(OutputType::Object, cgu_name);
         let dwo_out = self.temp_path_dwo(cgu_name);
-        match split_debuginfo_kind {
-            SplitDebuginfo::Off => None,
+        match (split_debuginfo_kind, split_dwarf_kind) {
+            (SplitDebuginfo::Off, SplitDwarfKind::Single | SplitDwarfKind::Split) => None,
             // Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
             // (pointing at the path which is being determined here). Use the path to the current
             // object file.
-            SplitDebuginfo::Packed => Some(obj_out),
+            (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Single) => {
+                Some(obj_out)
+            }
             // Split mode emits the DWARF into a different file, use that path.
-            SplitDebuginfo::Unpacked => Some(dwo_out),
+            (SplitDebuginfo::Packed | SplitDebuginfo::Unpacked, SplitDwarfKind::Split) => {
+                Some(dwo_out)
+            }
         }
     }
 }
@@ -781,6 +817,10 @@ pub fn share_generics(&self) -> bool {
             },
         }
     }
+
+    pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
+        self.cg.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
+    }
 }
 
 impl DebuggingOptions {
@@ -794,10 +834,6 @@ pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags
             deduplicate_diagnostics: self.deduplicate_diagnostics,
         }
     }
-
-    pub fn get_symbol_mangling_version(&self) -> SymbolManglingVersion {
-        self.symbol_mangling_version.unwrap_or(SymbolManglingVersion::Legacy)
-    }
 }
 
 // The type of entry function, so users can have their own entry functions
@@ -821,6 +857,18 @@ pub enum CrateType {
 
 impl_stable_hash_via_hash!(CrateType);
 
+impl CrateType {
+    /// When generated, is this crate type an archive?
+    pub fn is_archive(&self) -> bool {
+        match *self {
+            CrateType::Rlib | CrateType::Staticlib => true,
+            CrateType::Executable | CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => {
+                false
+            }
+        }
+    }
+}
+
 #[derive(Clone, Hash, Debug, PartialEq, Eq)]
 pub enum Passes {
     Some(Vec<String>),
@@ -2116,6 +2164,34 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         );
     }
 
+    // Handle both `-Z symbol-mangling-version` and `-C symbol-mangling-version`; the latter takes
+    // precedence.
+    match (cg.symbol_mangling_version, debugging_opts.symbol_mangling_version) {
+        (Some(smv_c), Some(smv_z)) if smv_c != smv_z => {
+            early_error(
+                error_format,
+                "incompatible values passed for `-C symbol-mangling-version` \
+                and `-Z symbol-mangling-version`",
+            );
+        }
+        (Some(SymbolManglingVersion::V0), _) => {}
+        (Some(_), _) if !debugging_opts.unstable_options => {
+            early_error(
+                error_format,
+                "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
+            );
+        }
+        (None, None) => {}
+        (None, smv) => {
+            early_warn(
+                error_format,
+                "`-Z symbol-mangling-version` is deprecated; use `-C symbol-mangling-version`",
+            );
+            cg.symbol_mangling_version = smv;
+        }
+        _ => {}
+    }
+
     if debugging_opts.instrument_coverage.is_some()
         && debugging_opts.instrument_coverage != Some(InstrumentCoverage::Off)
     {
@@ -2127,19 +2203,17 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
             );
         }
 
-        // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent
+        // `-Z 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.
-        match debugging_opts.symbol_mangling_version {
-            None => {
-                debugging_opts.symbol_mangling_version = Some(SymbolManglingVersion::V0);
-            }
+        match cg.symbol_mangling_version {
+            None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
             Some(SymbolManglingVersion::Legacy) => {
                 early_warn(
                     error_format,
                     "-Z instrument-coverage requires symbol mangling version `v0`, \
-                    but `-Z symbol-mangling-version=legacy` was specified",
+                    but `-C symbol-mangling-version=legacy` was specified",
                 );
             }
             Some(SymbolManglingVersion::V0) => {}
index f59b9b304ca6f21361967ff12d6799258065aa84..0b9623d1c7d6f69c4e99cd5265fc27e618e9b666 100644 (file)
@@ -412,6 +412,8 @@ mod desc {
     pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
     pub const parse_split_debuginfo: &str =
         "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)";
+    pub const parse_split_dwarf_kind: &str =
+        "one of supported split dwarf modes (`split` or `single`)";
     pub const parse_gcc_ld: &str = "one of: no value, `lld`";
     pub const parse_stack_protector: &str =
         "one of (`none` (default), `basic`, `strong`, or `all`)";
@@ -941,6 +943,14 @@ mod parse {
         true
     }
 
+    crate fn parse_split_dwarf_kind(slot: &mut SplitDwarfKind, v: Option<&str>) -> bool {
+        match v.and_then(|s| SplitDwarfKind::from_str(s).ok()) {
+            Some(e) => *slot = e,
+            _ => return false,
+        }
+        true
+    }
+
     crate fn parse_gcc_ld(slot: &mut Option<LdImpl>, v: Option<&str>) -> bool {
         match v {
             None => *slot = None,
@@ -1083,6 +1093,9 @@ mod parse {
         "how to handle split-debuginfo, a platform-specific option"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
+    symbol_mangling_version: Option<SymbolManglingVersion> = (None,
+        parse_symbol_mangling_version, [TRACKED],
+        "which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
     target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
         "select target processor (`rustc --print target-cpus` for details)"),
     target_feature: String = (String::new(), parse_target_feature, [TRACKED],
@@ -1227,7 +1240,7 @@ mod parse {
     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 `-Z symbol-mangling-version=v0`. Optional values are:
+        implies `-C symbol-mangling-version=v0`. Optional values are:
         `=all` (implicit value)
         `=except-unused-generics`
         `=except-unused-functions`
@@ -1400,6 +1413,14 @@ mod parse {
         "control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
     strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
         "tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
+    split_dwarf_kind: SplitDwarfKind = (SplitDwarfKind::Split, parse_split_dwarf_kind, [UNTRACKED],
+        "split dwarf variant (only if -Csplit-debuginfo is enabled and on relevant platform)
+        (default: `split`)
+
+        `split`: sections which do not require relocation are written into a DWARF object (`.dwo`)
+                 file which is ignored by the linker
+        `single`: sections which do not require relocation are written into object file but ignored
+                  by the linker"),
     split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
         "provide minimal debug info in the object/executable to facilitate online \
          symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),
index d15befbf28730f17a7da2e09bf5367f15d3ff728..0bba918994c51d46f605e130aaa523d7434e74e7 100644 (file)
@@ -136,8 +136,8 @@ fn borrow(&self) -> &Fingerprint {
 /// collisions when loading crates and abort compilation in order to avoid
 /// further trouble.
 ///
-/// See the discussion in [`DefId`] for more information
-/// on the possibility of hash collisions in rustc,
+/// For more information on the possibility of hash collisions in rustc,
+/// see the discussion in [`DefId`].
 #[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
 #[derive(HashStable_Generic, Encodable, Decodable)]
 pub struct StableCrateId(pub(crate) u64);
@@ -221,10 +221,17 @@ impl<D: Decoder> Decodable<D> for DefIndex {
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy)]
 // On below-64 bit systems we can simply use the derived `Hash` impl
 #[cfg_attr(not(target_pointer_width = "64"), derive(Hash))]
-// Note that the order is essential here, see below why
+#[repr(C)]
+// We guarantee field order. Note that the order is essential here, see below why.
 pub struct DefId {
+    // cfg-ing the order of fields so that the `DefIndex` which is high entropy always ends up in
+    // the lower bits no matter the endianness. This allows the compiler to turn that `Hash` impl
+    // into a direct call to 'u64::hash(_)`.
+    #[cfg(not(all(target_pointer_width = "64", target_endian = "big")))]
     pub index: DefIndex,
     pub krate: CrateNum,
+    #[cfg(all(target_pointer_width = "64", target_endian = "big"))]
+    pub index: DefIndex,
 }
 
 // On 64-bit systems, we can hash the whole `DefId` as one `u64` instead of two `u32`s. This
@@ -316,17 +323,23 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 rustc_data_structures::define_id_collections!(DefIdMap, DefIdSet, DefId);
 
-/// A LocalDefId is equivalent to a DefId with `krate == LOCAL_CRATE`. Since
+/// A `LocalDefId` is equivalent to a `DefId` with `krate == LOCAL_CRATE`. Since
 /// we encode this information in the type, we can ensure at compile time that
-/// no DefIds from upstream crates get thrown into the mix. There are quite a
-/// few cases where we know that only DefIds from the local crate are expected
-/// and a DefId from a different crate would signify a bug somewhere. This
-/// is when LocalDefId comes in handy.
+/// no `DefId`s from upstream crates get thrown into the mix. There are quite a
+/// few cases where we know that only `DefId`s from the local crate are expected;
+/// a `DefId` from a different crate would signify a bug somewhere. This
+/// is when `LocalDefId` comes in handy.
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct LocalDefId {
     pub local_def_index: DefIndex,
 }
 
+// To ensure correctness of incremental compilation,
+// `LocalDefId` must not implement `Ord` or `PartialOrd`.
+// See https://github.com/rust-lang/rust/issues/90317.
+impl !Ord for LocalDefId {}
+impl !PartialOrd for LocalDefId {}
+
 pub const CRATE_DEF_ID: LocalDefId = LocalDefId { local_def_index: CRATE_DEF_INDEX };
 
 impl Idx for LocalDefId {
index 315b706fbc44ddb6583f0a412a6aea9f26385559..7b70c20d307f05cfdeffb843a754d7673bc4ea22 100644 (file)
@@ -32,6 +32,7 @@
 use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::stable_hasher::HashingControls;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_data_structures::unhash::UnhashMap;
@@ -88,6 +89,33 @@ pub struct LocalExpnId {
     }
 }
 
+/// Assert that the provided `HashStableContext` is configured with the 'default'
+/// `HashingControls`. We should always have bailed out before getting to here
+/// with a non-default mode. With this check in place, we can avoid the need
+/// to maintain separate versions of `ExpnData` hashes for each permutation
+/// of `HashingControls` settings.
+fn assert_default_hashing_controls<CTX: HashStableContext>(ctx: &CTX, msg: &str) {
+    match ctx.hashing_controls() {
+        // Ideally, we would also check that `node_id_hashing_mode` was always
+        // `NodeIdHashingMode::HashDefPath`. However, we currently end up hashing
+        // `Span`s in this mode, and there's not an easy way to change that.
+        // All of the span-related data that we hash is pretty self-contained
+        // (in particular, we don't hash any `HirId`s), so this shouldn't result
+        // in any caching problems.
+        // FIXME: Enforce that we don't end up transitively hashing any `HirId`s,
+        // or ensure that this method is always invoked with the same
+        // `NodeIdHashingMode`
+        //
+        // Note that we require that `hash_spans` be set according to the global
+        // `-Z incremental-ignore-spans` option. Normally, this option is disabled,
+        // which will cause us to require that this method always be called with `Span` hashing
+        // enabled.
+        HashingControls { hash_spans, node_id_hashing_mode: _ }
+            if hash_spans == !ctx.debug_opts_incremental_ignore_spans() => {}
+        other => panic!("Attempted hashing of {msg} with non-default HashingControls: {:?}", other),
+    }
+}
+
 /// A unique hash value associated to an expansion.
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
 pub struct ExpnHash(Fingerprint);
@@ -1444,6 +1472,7 @@ fn update_disambiguator(expn_data: &mut ExpnData, mut ctx: impl HashStableContex
         "Already set disambiguator for ExpnData: {:?}",
         expn_data
     );
+    assert_default_hashing_controls(&ctx, "ExpnData (disambiguator)");
     let mut expn_hash = expn_data.hash_expn(&mut ctx);
 
     let disambiguator = HygieneData::with(|data| {
@@ -1493,6 +1522,7 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
 
 impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
     fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+        assert_default_hashing_controls(ctx, "ExpnId");
         let hash = if *self == ExpnId::root() {
             // Avoid fetching TLS storage for a trivial often-used value.
             Fingerprint::ZERO
index 3bbf2a0e45666f8339d9889e466899fac892a67c..9602bc5d0b7d47e88545b509503d0caef0f1bae8 100644 (file)
@@ -42,6 +42,7 @@
 use hygiene::Transparency;
 pub use hygiene::{DesugaringKind, ExpnKind, MacroKind};
 pub use hygiene::{ExpnData, ExpnHash, ExpnId, LocalExpnId, SyntaxContext};
+use rustc_data_structures::stable_hasher::HashingControls;
 pub mod def_id;
 use def_id::{CrateNum, DefId, DefPathHash, LocalDefId, LOCAL_CRATE};
 pub mod lev_distance;
@@ -2057,11 +2058,15 @@ pub fn new(start: usize, end: usize) -> InnerSpan {
 pub trait HashStableContext {
     fn def_path_hash(&self, def_id: DefId) -> DefPathHash;
     fn hash_spans(&self) -> bool;
+    /// Accesses `sess.opts.debugging_opts.incremental_ignore_spans` since
+    /// we don't have easy access to a `Session`
+    fn debug_opts_incremental_ignore_spans(&self) -> bool;
     fn def_span(&self, def_id: LocalDefId) -> Span;
     fn span_data_to_lines_and_cols(
         &mut self,
         span: &SpanData,
     ) -> Option<(Lrc<SourceFile>, usize, BytePos, usize, BytePos)>;
+    fn hashing_controls(&self) -> HashingControls;
 }
 
 impl<CTX> HashStable<CTX> for Span
index 51a7a2644f69545d350481a927a1360b11926805..f99d5cfad0ab81a01f4ba65216b3d4100ca1e1c8 100644 (file)
         LinkedList,
         LintPass,
         Mutex,
+        N,
         None,
         Ok,
         Option,
         array,
         arrays,
         as_ptr,
+        as_ref,
         as_str,
         asm,
         asm_const,
         doc_spotlight,
         doctest,
         document_private_items,
+        dotdot: "..",
         dotdot_in_tuple_patterns,
         dotdoteq_in_patterns,
         dreg,
         enable,
         enclosing_scope,
         encode,
+        end,
         env,
         eq,
         ermsb_target_feature,
         literal,
         llvm_asm,
         load,
+        loaded_from_disk,
         local,
         local_inner_macros,
         log10f32,
index eebf618a5ded48f3749d16d33dc08da20898d426..c981b3ff54663a21f66dd28decbafda8e0bb74af 100644 (file)
@@ -107,35 +107,35 @@ fn get_symbol_hash<'tcx>(
         tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
 
         // Include the main item-type. Note that, in this case, the
-        // assertions about `definitely_needs_subst` may not hold, but this item-type
+        // assertions about `needs_subst` may not hold, but this item-type
         // ought to be the same for every reference anyway.
-        assert!(!item_type.has_erasable_regions(tcx));
+        assert!(!item_type.has_erasable_regions());
         hcx.while_hashing_spans(false, |hcx| {
             hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
                 item_type.hash_stable(hcx, &mut hasher);
-            });
-        });
 
-        // If this is a function, we hash the signature as well.
-        // This is not *strictly* needed, but it may help in some
-        // situations, see the `run-make/a-b-a-linker-guard` test.
-        if let ty::FnDef(..) = item_type.kind() {
-            item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher);
-        }
+                // If this is a function, we hash the signature as well.
+                // This is not *strictly* needed, but it may help in some
+                // situations, see the `run-make/a-b-a-linker-guard` test.
+                if let ty::FnDef(..) = item_type.kind() {
+                    item_type.fn_sig(tcx).hash_stable(hcx, &mut hasher);
+                }
 
-        // also include any type parameters (for generic items)
-        substs.hash_stable(&mut hcx, &mut hasher);
+                // also include any type parameters (for generic items)
+                substs.hash_stable(hcx, &mut hasher);
 
-        if let Some(instantiating_crate) = instantiating_crate {
-            tcx.def_path_hash(instantiating_crate.as_def_id())
-                .stable_crate_id()
-                .hash_stable(&mut hcx, &mut hasher);
-        }
+                if let Some(instantiating_crate) = instantiating_crate {
+                    tcx.def_path_hash(instantiating_crate.as_def_id())
+                        .stable_crate_id()
+                        .hash_stable(hcx, &mut hasher);
+                }
 
-        // We want to avoid accidental collision between different types of instances.
-        // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
-        // instances without this.
-        discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher);
+                // We want to avoid accidental collision between different types of instances.
+                // Especially, `VtableShim`s and `ReifyShim`s may overlap with their original
+                // instances without this.
+                discriminant(&instance.def).hash_stable(hcx, &mut hasher);
+            });
+        });
     });
 
     // 64 bits should be enough to avoid collisions.
index 65b5852bc39839caf06fa128dce5533222d383bd..c5e85b14421cf082dec61a34e4a74ca6de6ab0f9 100644 (file)
@@ -173,8 +173,7 @@ fn compute_symbol_name<'tcx>(
             let stable_crate_id = tcx.sess.local_stable_crate_id();
             return tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
         }
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-        matches!(tcx.hir().get(hir_id), Node::ForeignItem(_))
+        matches!(tcx.hir().get_by_def_id(def_id), Node::ForeignItem(_))
     } else {
         tcx.is_foreign_item(def_id)
     };
@@ -237,7 +236,7 @@ fn compute_symbol_name<'tcx>(
 
     // Pick the crate responsible for the symbol mangling version, which has to:
     // 1. be stable for each instance, whether it's being defined or imported
-    // 2. obey each crate's own `-Z symbol-mangling-version`, as much as possible
+    // 2. obey each crate's own `-C symbol-mangling-version`, as much as possible
     // We solve these as follows:
     // 1. because symbol names depend on both `def_id` and `instantiating_crate`,
     // both their `CrateNum`s are stable for any given instance, so we can pick
@@ -245,7 +244,7 @@ fn compute_symbol_name<'tcx>(
     // 2. we favor `instantiating_crate` where possible (i.e. when `Some`)
     let mangling_version_crate = instantiating_crate.unwrap_or(def_id.krate);
     let mangling_version = if mangling_version_crate == LOCAL_CRATE {
-        tcx.sess.opts.debugging_opts.get_symbol_mangling_version()
+        tcx.sess.opts.get_symbol_mangling_version()
     } else {
         tcx.symbol_mangling_version(mangling_version_crate)
     };
index c2519adcbe416c53f8f177b2666312868f318f7f..14e12bed59e1e77282c6832e73b4e79c088e991e 100644 (file)
@@ -317,9 +317,7 @@ fn print_impl_path(
 
         // Encode impl generic params if the substitutions contain parameters (implying
         // polymorphization is enabled) and this isn't an inherent impl.
-        if impl_trait_ref.is_some()
-            && substs.iter().any(|a| a.definitely_has_param_types_or_consts(self.tcx))
-        {
+        if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) {
             self = self.path_generic_args(
                 |this| {
                     this.path_append_ns(
index 2cb2661a5265e667fea44ad7309ef4c2f11e7014..a6c1b344d700719118ceddac83cd166506a6a66f 100644 (file)
@@ -17,12 +17,10 @@ pub fn target(target_cpu: String) -> Target {
             linker: Some("avr-gcc".to_owned()),
             executables: true,
             eh_frame_header: false,
-            pre_link_args: vec![(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu)])]
-                .into_iter()
-                .collect(),
-            late_link_args: vec![(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])]
+            pre_link_args: [(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu)])]
                 .into_iter()
                 .collect(),
+            late_link_args: [(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])].into_iter().collect(),
             max_atomic_width: Some(0),
             atomic_cas: false,
             ..TargetOptions::default()
index 43913183694e0c41d6ef80f1bf05683ab6c36ea8..2c149318730eeacf694c687c963508279b3c0de0 100644 (file)
@@ -479,7 +479,7 @@ pub enum SplitDebuginfo {
     ///
     /// * Windows - not supported
     /// * macOS - supported, scattered object files
-    /// * ELF - supported, scattered `*.dwo` files
+    /// * ELF - supported, scattered `*.dwo` or `*.o` files (see `SplitDwarfKind`)
     Unpacked,
 }
 
@@ -574,15 +574,15 @@ impl ToJson for StackProbeType {
     fn to_json(&self) -> Json {
         Json::Object(match self {
             StackProbeType::None => {
-                vec![(String::from("kind"), "none".to_json())].into_iter().collect()
+                [(String::from("kind"), "none".to_json())].into_iter().collect()
             }
             StackProbeType::Inline => {
-                vec![(String::from("kind"), "inline".to_json())].into_iter().collect()
+                [(String::from("kind"), "inline".to_json())].into_iter().collect()
             }
             StackProbeType::Call => {
-                vec![(String::from("kind"), "call".to_json())].into_iter().collect()
+                [(String::from("kind"), "call".to_json())].into_iter().collect()
             }
-            StackProbeType::InlineOrCall { min_llvm_version_for_inline } => vec![
+            StackProbeType::InlineOrCall { min_llvm_version_for_inline } => [
                 (String::from("kind"), "inline-or-call".to_json()),
                 (
                     String::from("min-llvm-version-for-inline"),
index 290426aa8278704b7b886fd299317e5c74a21eb6..d174e00df77a9c722e6837e5d5fbd14c2342e3cf 100644 (file)
@@ -444,7 +444,7 @@ fn orphan_check_trait_ref<'tcx>(
 ) -> Result<(), OrphanCheckErr<'tcx>> {
     debug!("orphan_check_trait_ref(trait_ref={:?}, in_crate={:?})", trait_ref, in_crate);
 
-    if trait_ref.needs_infer() && trait_ref.definitely_needs_subst(tcx) {
+    if trait_ref.needs_infer() && trait_ref.needs_subst() {
         bug!(
             "can't orphan check a trait ref with both params and inference variables {:?}",
             trait_ref
index 0ea3a18ca34fa2af5317beb4e552dc15594a4e0d..5a69c5d50ff762dc26dae8bf6e08720d23ac7393 100644 (file)
@@ -84,7 +84,7 @@ enum FailureKind {
                     Node::Leaf(leaf) => {
                         if leaf.has_infer_types_or_consts() {
                             failure_kind = FailureKind::MentionsInfer;
-                        } else if leaf.definitely_has_param_types_or_consts(tcx) {
+                        } else if leaf.has_param_types_or_consts() {
                             failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
                         }
 
@@ -93,7 +93,7 @@ enum FailureKind {
                     Node::Cast(_, _, ty) => {
                         if ty.has_infer_types_or_consts() {
                             failure_kind = FailureKind::MentionsInfer;
-                        } else if ty.definitely_has_param_types_or_consts(tcx) {
+                        } else if ty.has_param_types_or_consts() {
                             failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam);
                         }
 
@@ -149,7 +149,7 @@ enum FailureKind {
     // See #74595 for more details about this.
     let concrete = infcx.const_eval_resolve(param_env, uv.expand(), Some(span));
 
-    if concrete.is_ok() && uv.substs(infcx.tcx).definitely_has_param_types_or_consts(infcx.tcx) {
+    if concrete.is_ok() && uv.substs.has_param_types_or_consts() {
         match infcx.tcx.def_kind(uv.def.did) {
             DefKind::AnonConst | DefKind::InlineConst => {
                 let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
@@ -196,7 +196,7 @@ pub fn new(
     ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> {
         let inner = tcx.thir_abstract_const_opt_const_arg(uv.def)?;
         debug!("AbstractConst::new({:?}) = {:?}", uv, inner);
-        Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs(tcx) }))
+        Ok(inner.map(|inner| AbstractConst { inner, substs: uv.substs }))
     }
 
     pub fn from_const(
@@ -271,7 +271,6 @@ fn new(
         struct IsThirPolymorphic<'a, 'tcx> {
             is_poly: bool,
             thir: &'a thir::Thir<'tcx>,
-            tcx: TyCtxt<'tcx>,
         }
 
         use thir::visit;
@@ -281,25 +280,25 @@ fn thir(&self) -> &'a thir::Thir<'tcx> {
             }
 
             fn visit_expr(&mut self, expr: &thir::Expr<'tcx>) {
-                self.is_poly |= expr.ty.definitely_has_param_types_or_consts(self.tcx);
+                self.is_poly |= expr.ty.has_param_types_or_consts();
                 if !self.is_poly {
                     visit::walk_expr(self, expr)
                 }
             }
 
             fn visit_pat(&mut self, pat: &thir::Pat<'tcx>) {
-                self.is_poly |= pat.ty.definitely_has_param_types_or_consts(self.tcx);
+                self.is_poly |= pat.ty.has_param_types_or_consts();
                 if !self.is_poly {
                     visit::walk_pat(self, pat);
                 }
             }
 
             fn visit_const(&mut self, ct: &'tcx ty::Const<'tcx>) {
-                self.is_poly |= ct.definitely_has_param_types_or_consts(self.tcx);
+                self.is_poly |= ct.has_param_types_or_consts();
             }
         }
 
-        let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body, tcx };
+        let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body };
         visit::walk_expr(&mut is_poly_vis, &body[body_id]);
         debug!("AbstractConstBuilder: is_poly={}", is_poly_vis.is_poly);
         if !is_poly_vis.is_poly {
index a9ae0ec53c7e78283275b2e27902533cf217d44c..b4d297a03ef21f3b552d8a15b9164fe0d77395b3 100644 (file)
@@ -616,8 +616,6 @@ fn report_selection_error(
                             self.tcx.sess.source_map().guess_head_span(
                                 self.tcx.hir().span_if_local(closure_def_id).unwrap(),
                             );
-                        let hir_id =
-                            self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
                         let mut err = struct_span_err!(
                             self.tcx.sess,
                             closure_span,
@@ -640,6 +638,10 @@ fn report_selection_error(
                         // Additional context information explaining why the closure only implements
                         // a particular trait.
                         if let Some(typeck_results) = self.in_progress_typeck_results {
+                            let hir_id = self
+                                .tcx
+                                .hir()
+                                .local_def_id_to_hir_id(closure_def_id.expect_local());
                             let typeck_results = typeck_results.borrow();
                             match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
                                 (ty::ClosureKind::FnOnce, Some((span, place))) => {
@@ -2247,7 +2249,7 @@ pub fn recursive_type_with_infinite_size_error(
             spans
                 .iter()
                 .flat_map(|&span| {
-                    vec![
+                    [
                         (span.shrink_to_lo(), "Box<".to_string()),
                         (span.shrink_to_hi(), ">".to_string()),
                     ]
index 0f276718c16e774c217d17539aff9c8019db206f..b06977c3f302e035d7bf2ef819cb3b9cc89af087 100644 (file)
@@ -481,7 +481,7 @@ fn suggest_restricting_param_bound(
                 _ => {}
             }
 
-            hir_id = self.tcx.hir().get_parent_item(hir_id);
+            hir_id = self.tcx.hir().local_def_id_to_hir_id(self.tcx.hir().get_parent_item(hir_id));
         }
     }
 
@@ -1226,7 +1226,7 @@ fn suggest_impl_trait(
                     .returns
                     .iter()
                     .flat_map(|expr| {
-                        vec![
+                        [
                             (expr.span.shrink_to_lo(), "Box::new(".to_string()),
                             (expr.span.shrink_to_hi(), ")".to_string()),
                         ]
@@ -2301,7 +2301,7 @@ fn note_obligation_cause_code<T>(
                 {
                     let in_progress_typeck_results =
                         self.in_progress_typeck_results.map(|t| t.borrow());
-                    let parent_id = hir.local_def_id(hir.get_parent_item(arg_hir_id));
+                    let parent_id = hir.get_parent_item(arg_hir_id);
                     let typeck_results: &TypeckResults<'tcx> = match &in_progress_typeck_results {
                         Some(t) if t.hir_owner == parent_id => t,
                         _ => self.tcx.typeck(parent_id),
index 42e3f0db15e538204b701ff96e72ae2b95933aeb..346590a2de26ff9118a55f6280153246e66afe85 100644 (file)
@@ -538,7 +538,7 @@ fn progress_changed_obligations(
                         Err(NotConstEvaluatable::MentionsInfer) => {
                             pending_obligation.stalled_on.clear();
                             pending_obligation.stalled_on.extend(
-                                uv.substs(infcx.tcx)
+                                uv.substs
                                     .iter()
                                     .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
                             );
@@ -583,7 +583,7 @@ fn progress_changed_obligations(
                                 Err(ErrorHandled::TooGeneric) => {
                                     stalled_on.extend(
                                         unevaluated
-                                            .substs(tcx)
+                                            .substs
                                             .iter()
                                             .filter_map(TyOrConstInferVar::maybe_from_generic_arg),
                                     );
@@ -654,7 +654,7 @@ fn process_trait_obligation(
         stalled_on: &mut Vec<TyOrConstInferVar<'tcx>>,
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let infcx = self.selcx.infcx();
-        if obligation.predicate.is_known_global() {
+        if obligation.predicate.is_global() {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
             if infcx.predicate_must_hold_considering_regions(obligation) {
@@ -708,7 +708,7 @@ fn process_projection_obligation(
     ) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
         let tcx = self.selcx.tcx();
 
-        if obligation.predicate.is_global(tcx) {
+        if obligation.predicate.is_global() {
             // no type variables present, can use evaluation for better caching.
             // FIXME: consider caching errors too.
             if self.selcx.infcx().predicate_must_hold_considering_regions(obligation) {
@@ -756,15 +756,14 @@ fn substs_infer_vars<'a, 'tcx>(
     selcx: &mut SelectionContext<'a, 'tcx>,
     substs: ty::Binder<'tcx, SubstsRef<'tcx>>,
 ) -> impl Iterator<Item = TyOrConstInferVar<'tcx>> {
-    let tcx = selcx.tcx();
     selcx
         .infcx()
         .resolve_vars_if_possible(substs)
         .skip_binder() // ok because this check doesn't care about regions
         .iter()
         .filter(|arg| arg.has_infer_types_or_consts())
-        .flat_map(move |arg| {
-            let mut walker = arg.walk(tcx);
+        .flat_map(|arg| {
+            let mut walker = arg.walk();
             while let Some(c) = walker.next() {
                 if !c.has_infer_types_or_consts() {
                     walker.visited.remove(&c);
index a8f26982d2e42096f5eb99adff5a5bada34cd0ae..23f534858b82a865436661d444580391cdf59fd0 100644 (file)
@@ -465,7 +465,7 @@ fn subst_and_check_impossible_predicates<'tcx>(
     debug!("subst_and_check_impossible_predicates(key={:?})", key);
 
     let mut predicates = tcx.predicates_of(key.0).instantiate(tcx, key.1).predicates;
-    predicates.retain(|predicate| !predicate.definitely_needs_subst(tcx));
+    predicates.retain(|predicate| !predicate.needs_subst());
     let result = impossible_predicates(tcx, predicates);
 
     debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result);
index 4e84849bc1e235572e035a64ca201afa9eb42bf6..185d64eab707ac4c99222ded595518d8dff9309a 100644 (file)
@@ -274,7 +274,7 @@ fn predicate_references_self<'tcx>(
     (predicate, sp): (ty::Predicate<'tcx>, Span),
 ) -> Option<Span> {
     let self_ty = tcx.types.self_param;
-    let has_self_ty = |arg: &GenericArg<'tcx>| arg.walk(tcx).any(|arg| arg == self_ty.into());
+    let has_self_ty = |arg: &GenericArg<'_>| arg.walk().any(|arg| arg == self_ty.into());
     match predicate.kind().skip_binder() {
         ty::PredicateKind::Trait(ref data) => {
             // In the case of a trait predicate, we can skip the "self" type.
@@ -768,9 +768,6 @@ struct IllegalSelfTypeVisitor<'tcx> {
 
     impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> {
         type BreakTy = ();
-        fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-            Some(self.tcx)
-        }
 
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             match t.kind() {
index 23f615a96185df70969a5391b9bd50fedd81f4fb..577b96f3a400ba5e331f7803f4c9290de27a80db 100644 (file)
@@ -1225,6 +1225,10 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     );
 }
 
+#[tracing::instrument(
+    level = "debug",
+    skip(selcx, candidate_set, ctor, env_predicates, potentially_unnormalized_candidates)
+)]
 fn assemble_candidates_from_predicates<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
@@ -1233,8 +1237,6 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
     env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
     potentially_unnormalized_candidates: bool,
 ) {
-    debug!(?obligation, "assemble_candidates_from_predicates");
-
     let infcx = selcx.infcx();
     for predicate in env_predicates {
         debug!(?predicate);
@@ -1270,13 +1272,12 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>(
     }
 }
 
+#[tracing::instrument(level = "debug", skip(selcx, obligation, candidate_set))]
 fn assemble_candidates_from_impls<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
     candidate_set: &mut ProjectionTyCandidateSet<'tcx>,
 ) {
-    debug!("assemble_candidates_from_impls");
-
     // If we are resolving `<T as TraitRef<...>>::Item == Type`,
     // start out by selecting the predicate `T as TraitRef<...>`:
     let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));
@@ -1400,8 +1401,17 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                 // Any type with multiple potential metadata types is therefore not eligible.
                 let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
 
-                // FIXME: should this normalize?
-                let tail = selcx.tcx().struct_tail_without_normalization(self_ty);
+                let tail = selcx.tcx().struct_tail_with_normalize(self_ty, |ty| {
+                    normalize_with_depth(
+                        selcx,
+                        obligation.param_env,
+                        obligation.cause.clone(),
+                        obligation.recursion_depth + 1,
+                        ty,
+                    )
+                    .value
+                });
+
                 match tail.kind() {
                     ty::Bool
                     | ty::Char
@@ -1435,7 +1445,12 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
                     | ty::Bound(..)
                     | ty::Placeholder(..)
                     | ty::Infer(..)
-                    | ty::Error(_) => false,
+                    | ty::Error(_) => {
+                        if tail.has_infer_types() {
+                            candidate_set.mark_ambiguous();
+                        }
+                        false
+                    },
                 }
             }
             super::ImplSource::Param(..) => {
@@ -1640,18 +1655,30 @@ fn confirm_pointee_candidate<'cx, 'tcx>(
     _: ImplSourcePointeeData,
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
-
     let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty());
-    let substs = tcx.mk_substs([self_ty.into()].iter());
 
+    let mut obligations = vec![];
+    let metadata_ty = self_ty.ptr_metadata_ty(tcx, |ty| {
+        normalize_with_depth_to(
+            selcx,
+            obligation.param_env,
+            obligation.cause.clone(),
+            obligation.recursion_depth + 1,
+            ty,
+            &mut obligations,
+        )
+    });
+
+    let substs = tcx.mk_substs([self_ty.into()].iter());
     let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
 
     let predicate = ty::ProjectionPredicate {
         projection_ty: ty::ProjectionTy { substs, item_def_id: metadata_def_id },
-        ty: self_ty.ptr_metadata_ty(tcx),
+        ty: metadata_ty,
     };
 
     confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
+        .with_addl_obligations(obligations)
 }
 
 fn confirm_fn_pointer_candidate<'cx, 'tcx>(
@@ -1883,7 +1910,6 @@ fn assoc_ty_def(
     assoc_ty_def_id: DefId,
 ) -> Result<specialization_graph::LeafDef, ErrorReported> {
     let tcx = selcx.tcx();
-    let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident;
     let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id;
     let trait_def = tcx.trait_def(trait_def_id);
 
@@ -1893,21 +1919,18 @@ fn assoc_ty_def(
     // for the associated item at the given impl.
     // If there is no such item in that impl, this function will fail with a
     // cycle error if the specialization graph is currently being built.
-    let impl_node = specialization_graph::Node::Impl(impl_def_id);
-    for item in impl_node.items(tcx) {
-        if matches!(item.kind, ty::AssocKind::Type)
-            && tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id)
-        {
-            return Ok(specialization_graph::LeafDef {
-                item: *item,
-                defining_node: impl_node,
-                finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
-            });
-        }
+    if let Some(&impl_item_id) = tcx.impl_item_implementor_ids(impl_def_id).get(&assoc_ty_def_id) {
+        let item = tcx.associated_item(impl_item_id);
+        let impl_node = specialization_graph::Node::Impl(impl_def_id);
+        return Ok(specialization_graph::LeafDef {
+            item: *item,
+            defining_node: impl_node,
+            finalizing_node: if item.defaultness.is_default() { None } else { Some(impl_node) },
+        });
     }
 
     let ancestors = trait_def.ancestors(tcx, impl_def_id)?;
-    if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_name, ty::AssocKind::Type) {
+    if let Some(assoc_item) = ancestors.leaf_def(tcx, assoc_ty_def_id) {
         Ok(assoc_item)
     } else {
         // This is saying that neither the trait nor
@@ -1916,7 +1939,11 @@ fn assoc_ty_def(
         // could only arise through a compiler bug --
         // if the user wrote a bad item name, it
         // should have failed in astconv.
-        bug!("No associated type `{}` for {}", assoc_ty_name, tcx.def_path_str(impl_def_id))
+        bug!(
+            "No associated type `{}` for {}",
+            tcx.item_name(assoc_ty_def_id),
+            tcx.def_path_str(impl_def_id)
+        )
     }
 }
 
index 26bacf787e2ebaded063e0854d2b9d55c5163436..81ee22c1de4d93dae3f52dcd22f6c00926f1bc9c 100644 (file)
@@ -77,11 +77,8 @@ fn normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
         // The rest of the code is already set up to be lazy about replacing bound vars,
         // and only when we actually have to normalize.
         if value.has_escaping_bound_vars() {
-            let mut max_visitor = MaxEscapingBoundVarVisitor {
-                tcx: self.infcx.tcx,
-                outer_index: ty::INNERMOST,
-                escaping: 0,
-            };
+            let mut max_visitor =
+                MaxEscapingBoundVarVisitor { outer_index: ty::INNERMOST, escaping: 0 };
             value.visit_with(&mut max_visitor);
             if max_visitor.escaping > 0 {
                 normalizer.universes.extend((0..max_visitor.escaping).map(|_| None));
@@ -104,18 +101,13 @@ fn normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
 }
 
 /// Visitor to find the maximum escaping bound var
-struct MaxEscapingBoundVarVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct MaxEscapingBoundVarVisitor {
     // The index which would count as escaping
     outer_index: ty::DebruijnIndex,
     escaping: usize,
 }
 
-impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor<'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.tcx)
-    }
-
+impl<'tcx> TypeVisitor<'tcx> for MaxEscapingBoundVarVisitor {
     fn visit_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: &ty::Binder<'tcx, T>,
index 12ca3faeb379785e34b8f3b1c3e55ab6b3726743..d662f61e2cf4dbbc1532fef09b656d71d7b546d1 100644 (file)
@@ -4,7 +4,9 @@
 use crate::infer::{InferCtxt, InferOk};
 use crate::traits::query::Fallible;
 use crate::traits::ObligationCause;
-use rustc_infer::infer::canonical::Canonical;
+use rustc_infer::infer::canonical::{Canonical, Certainty};
+use rustc_infer::traits::query::NoSolution;
+use rustc_infer::traits::PredicateObligations;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
 use std::fmt;
@@ -17,7 +19,6 @@
 pub mod normalize;
 pub mod outlives;
 pub mod prove_predicate;
-use self::prove_predicate::ProvePredicate;
 pub mod subtype;
 
 pub use rustc_middle::traits::query::type_op::*;
@@ -80,9 +81,14 @@ fn fully_perform_into(
         query_key: ParamEnvAnd<'tcx, Self>,
         infcx: &InferCtxt<'_, 'tcx>,
         output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
-    ) -> Fallible<(Self::QueryResponse, Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>)> {
+    ) -> Fallible<(
+        Self::QueryResponse,
+        Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
+        PredicateObligations<'tcx>,
+        Certainty,
+    )> {
         if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
-            return Ok((result, None));
+            return Ok((result, None, vec![], Certainty::Proven));
         }
 
         // FIXME(#33684) -- We need to use
@@ -104,20 +110,7 @@ fn fully_perform_into(
                 output_query_region_constraints,
             )?;
 
-        // Typically, instantiating NLL query results does not
-        // create obligations. However, in some cases there
-        // are unresolved type variables, and unify them *can*
-        // create obligations. In that case, we have to go
-        // fulfill them. We do this via a (recursive) query.
-        for obligation in obligations {
-            let ((), _) = ProvePredicate::fully_perform_into(
-                obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
-                infcx,
-                output_query_region_constraints,
-            )?;
-        }
-
-        Ok((value, Some(canonical_self)))
+        Ok((value, Some(canonical_self), obligations, canonical_result.value.certainty))
     }
 }
 
@@ -129,9 +122,39 @@ impl<'tcx, Q> TypeOp<'tcx> for ParamEnvAnd<'tcx, Q>
 
     fn fully_perform(self, infcx: &InferCtxt<'_, 'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
         let mut region_constraints = QueryRegionConstraints::default();
-        let (output, canonicalized_query) =
+        let (output, canonicalized_query, mut obligations, _) =
             Q::fully_perform_into(self, infcx, &mut region_constraints)?;
 
+        // Typically, instantiating NLL query results does not
+        // create obligations. However, in some cases there
+        // are unresolved type variables, and unify them *can*
+        // create obligations. In that case, we have to go
+        // fulfill them. We do this via a (recursive) query.
+        while !obligations.is_empty() {
+            trace!("{:#?}", obligations);
+            let mut progress = false;
+            for obligation in std::mem::take(&mut obligations) {
+                let obligation = infcx.resolve_vars_if_possible(obligation);
+                match ProvePredicate::fully_perform_into(
+                    obligation.param_env.and(ProvePredicate::new(obligation.predicate)),
+                    infcx,
+                    &mut region_constraints,
+                ) {
+                    Ok(((), _, new, certainty)) => {
+                        obligations.extend(new);
+                        progress = true;
+                        if let Certainty::Ambiguous = certainty {
+                            obligations.push(obligation);
+                        }
+                    }
+                    Err(_) => obligations.push(obligation),
+                }
+            }
+            if !progress {
+                return Err(NoSolution);
+            }
+        }
+
         // Promote the final query-region-constraints into a
         // (optional) ref-counted vector:
         let region_constraints =
index 017f47d4357fb9aa79f5a4064aca2ae50bdb797d..b573c4b43906c58ed3e19dd7ceca3ad9a6fcdf51 100644 (file)
@@ -173,6 +173,9 @@ fn candidate_from_obligation_no_cache<'o>(
 
         let needs_infer = stack.obligation.predicate.has_infer_types_or_consts();
 
+        let sized_predicate = self.tcx().lang_items().sized_trait()
+            == Some(stack.obligation.predicate.skip_binder().def_id());
+
         // If there are STILL multiple candidates, we can further
         // reduce the list by dropping duplicates -- including
         // resolving specializations.
@@ -181,6 +184,7 @@ fn candidate_from_obligation_no_cache<'o>(
             while i < candidates.len() {
                 let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| {
                     self.candidate_should_be_dropped_in_favor_of(
+                        sized_predicate,
                         &candidates[i],
                         &candidates[j],
                         needs_infer,
@@ -338,13 +342,12 @@ pub(super) fn assemble_candidates<'o>(
         Ok(candidates)
     }
 
+    #[tracing::instrument(level = "debug", skip(self, candidates))]
     fn assemble_candidates_from_projected_tys(
         &mut self,
         obligation: &TraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) {
-        debug!(?obligation, "assemble_candidates_from_projected_tys");
-
         // Before we go into the whole placeholder thing, just
         // quickly check if the self-type is a projection at all.
         match obligation.predicate.skip_binder().trait_ref.self_ty().kind() {
@@ -369,12 +372,13 @@ fn assemble_candidates_from_projected_tys(
     /// supplied to find out whether it is listed among them.
     ///
     /// Never affects the inference environment.
+    #[tracing::instrument(level = "debug", skip(self, stack, candidates))]
     fn assemble_candidates_from_caller_bounds<'o>(
         &mut self,
         stack: &TraitObligationStack<'o, 'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
     ) -> Result<(), SelectionError<'tcx>> {
-        debug!(?stack.obligation, "assemble_candidates_from_caller_bounds");
+        debug!(?stack.obligation);
 
         let all_bounds = stack
             .obligation
@@ -876,6 +880,7 @@ fn assemble_candidates_for_unsizing(
         };
     }
 
+    #[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
     fn assemble_candidates_for_trait_alias(
         &mut self,
         obligation: &TraitObligation<'tcx>,
@@ -883,7 +888,7 @@ fn assemble_candidates_for_trait_alias(
     ) {
         // Okay to skip binder here because the tests we do below do not involve bound regions.
         let self_ty = obligation.self_ty().skip_binder();
-        debug!(?self_ty, "assemble_candidates_for_trait_alias");
+        debug!(?self_ty);
 
         let def_id = obligation.predicate.def_id();
 
@@ -894,6 +899,7 @@ fn assemble_candidates_for_trait_alias(
 
     /// Assembles the trait which are built-in to the language itself:
     /// `Copy`, `Clone` and `Sized`.
+    #[tracing::instrument(level = "debug", skip(self, candidates))]
     fn assemble_builtin_bound_candidates(
         &mut self,
         conditions: BuiltinImplConditions<'tcx>,
@@ -901,14 +907,12 @@ fn assemble_builtin_bound_candidates(
     ) {
         match conditions {
             BuiltinImplConditions::Where(nested) => {
-                debug!(?nested, "builtin_bound");
                 candidates
                     .vec
                     .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() });
             }
             BuiltinImplConditions::None => {}
             BuiltinImplConditions::Ambiguous => {
-                debug!("assemble_builtin_bound_candidates: ambiguous builtin");
                 candidates.ambiguous = true;
             }
         }
index b7fc578ea3bd371455db666e236c8acc072cdb75..36af78b66edfa47bd8d5790a6ece1aac188d97c9 100644 (file)
@@ -997,7 +997,7 @@ fn confirm_builtin_unsize_candidate(
                 let tail_field_ty = tcx.type_of(tail_field.did);
 
                 let mut unsizing_params = GrowableBitSet::new_empty();
-                for arg in tail_field_ty.walk(tcx) {
+                for arg in tail_field_ty.walk() {
                     if let Some(i) = maybe_unsizing_param_idx(arg) {
                         unsizing_params.insert(i);
                     }
@@ -1006,7 +1006,7 @@ fn confirm_builtin_unsize_candidate(
                 // Ensure none of the other fields mention the parameters used
                 // in unsizing.
                 for field in prefix_fields {
-                    for arg in tcx.type_of(field.did).walk(tcx) {
+                    for arg in tcx.type_of(field.did).walk() {
                         if let Some(i) = maybe_unsizing_param_idx(arg) {
                             unsizing_params.remove(i);
                         }
index fa88c8ee37015f6db0e08f86c37141d16246f0b4..1414c742635c401855b0f8de3f54b487b31542c1 100644 (file)
@@ -201,6 +201,7 @@ struct EvaluatedCandidate<'tcx> {
 }
 
 /// When does the builtin impl for `T: Trait` apply?
+#[derive(Debug)]
 enum BuiltinImplConditions<'tcx> {
     /// The impl is conditional on `T1, T2, ...: Trait`.
     Where(ty::Binder<'tcx, Vec<Ty<'tcx>>>),
@@ -344,7 +345,7 @@ pub fn select(
             }
             Err(e) => Err(e),
             Ok(candidate) => {
-                debug!(?candidate);
+                debug!(?candidate, "confirmed");
                 Ok(Some(candidate))
             }
         }
@@ -526,7 +527,7 @@ fn evaluate_predicate_recursively<'o>(
                     // contain the "'static" lifetime (any other lifetime
                     // would either be late-bound or local), so it is guaranteed
                     // to outlive any other lifetime
-                    if pred.0.is_global(self.infcx.tcx) && !pred.0.has_late_bound_regions() {
+                    if pred.0.is_global() && !pred.0.has_late_bound_regions() {
                         Ok(EvaluatedToOk)
                     } else {
                         Ok(EvaluatedToOkModuloRegions)
@@ -711,12 +712,8 @@ fn evaluate_trait_predicate_recursively<'o>(
         mut obligation: TraitObligation<'tcx>,
     ) -> Result<EvaluationResult, OverflowError> {
         if !self.intercrate
-            && obligation.is_global(self.tcx())
-            && obligation
-                .param_env
-                .caller_bounds()
-                .iter()
-                .all(|bound| bound.definitely_needs_subst(self.tcx()))
+            && obligation.is_global()
+            && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst())
         {
             // If a param env has no global bounds, global obligations do not
             // depend on its particular value in order to work, so we can clear
@@ -1523,6 +1520,7 @@ pub(super) fn match_projection_projections(
     /// See the comment for "SelectionCandidate" for more details.
     fn candidate_should_be_dropped_in_favor_of(
         &mut self,
+        sized_predicate: bool,
         victim: &EvaluatedCandidate<'tcx>,
         other: &EvaluatedCandidate<'tcx>,
         needs_infer: bool,
@@ -1535,7 +1533,7 @@ fn candidate_should_be_dropped_in_favor_of(
         // the param_env so that it can be given the lowest priority. See
         // #50825 for the motivation for this.
         let is_global = |cand: &ty::PolyTraitPredicate<'tcx>| {
-            cand.is_global(self.infcx.tcx) && !cand.has_late_bound_regions()
+            cand.is_global() && !cand.has_late_bound_regions()
         };
 
         // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
@@ -1594,6 +1592,16 @@ fn candidate_should_be_dropped_in_favor_of(
             // Drop otherwise equivalent non-const fn pointer candidates
             (FnPointerCandidate { .. }, FnPointerCandidate { is_const: false }) => true,
 
+            // If obligation is a sized predicate or the where-clause bound is
+            // global, prefer the projection or object candidate. See issue
+            // #50825 and #89352.
+            (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
+                sized_predicate || is_global(cand)
+            }
+            (ParamCandidate(ref cand), ObjectCandidate(_) | ProjectionCandidate(_)) => {
+                !(sized_predicate || is_global(cand))
+            }
+
             // Global bounds from the where clause should be ignored
             // here (see issue #50825). Otherwise, we have a where
             // clause so don't go around looking for impls.
@@ -1609,15 +1617,8 @@ fn candidate_should_be_dropped_in_favor_of(
                 | BuiltinUnsizeCandidate
                 | TraitUpcastingUnsizeCandidate(_)
                 | BuiltinCandidate { .. }
-                | TraitAliasCandidate(..)
-                | ObjectCandidate(_)
-                | ProjectionCandidate(_),
+                | TraitAliasCandidate(..),
             ) => !is_global(cand),
-            (ObjectCandidate(_) | ProjectionCandidate(_), ParamCandidate(ref cand)) => {
-                // Prefer these to a global where-clause bound
-                // (see issue #50825).
-                is_global(cand)
-            }
             (
                 ImplCandidate(_)
                 | ClosureCandidate
@@ -1953,7 +1954,7 @@ fn constituent_types_for_ty(
             ty::Generator(_, ref substs, _) => {
                 let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty());
                 let witness = substs.as_generator().witness();
-                t.rebind(vec![ty].into_iter().chain(iter::once(witness)).collect())
+                t.rebind([ty].into_iter().chain(iter::once(witness)).collect())
             }
 
             ty::GeneratorWitness(types) => {
index 55feb3c1de17d356ec0d6ccb917d58cf4d805ddb..2ed7a8f9cf9ea2d2f4366289f3f6f6a5ee3ab43d 100644 (file)
@@ -48,7 +48,6 @@ pub enum NonStructuralMatchTy<'tcx> {
 /// that arose when the requirement was not enforced completely, see
 /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
 pub fn search_for_structural_match_violation<'tcx>(
-    _id: hir::HirId,
     span: Span,
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
@@ -131,9 +130,6 @@ fn type_marked_structural(&self, adt_ty: Ty<'tcx>) -> bool {
 
 impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> {
     type BreakTy = NonStructuralMatchTy<'tcx>;
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.tcx())
-    }
 
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         debug!("Search visiting ty: {:?}", ty);
index 4bd73ef68aa7a58fa707562739a6bec2068df0b0..f6e98f427108f7f380dd0579040acaa986fb2677 100644 (file)
@@ -132,11 +132,10 @@ pub fn predicate_obligations<'a, 'tcx>(
             wf.compute(b.into());
         }
         ty::PredicateKind::ConstEvaluatable(uv) => {
-            let substs = uv.substs(wf.tcx());
-            let obligations = wf.nominal_obligations(uv.def.did, substs);
+            let obligations = wf.nominal_obligations(uv.def.did, uv.substs);
             wf.out.extend(obligations);
 
-            for arg in substs.iter() {
+            for arg in uv.substs.iter() {
                 wf.compute(arg);
             }
         }
@@ -197,14 +196,13 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
     item: Option<&hir::Item<'tcx>>,
     cause: &mut traits::ObligationCause<'tcx>,
     pred: &ty::Predicate<'tcx>,
-    mut trait_assoc_items: impl Iterator<Item = &'tcx ty::AssocItem>,
 ) {
     debug!(
         "extended_cause_with_original_assoc_item_obligation {:?} {:?} {:?} {:?}",
         trait_ref, item, cause, pred
     );
-    let items = match item {
-        Some(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) => impl_.items,
+    let (items, impl_def_id) = match item {
+        Some(hir::Item { kind: hir::ItemKind::Impl(impl_), def_id, .. }) => (impl_.items, *def_id),
         _ => return,
     };
     let fix_span =
@@ -222,11 +220,16 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
             // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and
             // `traits-assoc-type-in-supertrait-bad.rs`.
             if let ty::Projection(projection_ty) = proj.ty.kind() {
-                let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id);
-                if let Some(impl_item_span) =
-                    items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span)
+                if let Some(&impl_item_id) =
+                    tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
                 {
-                    cause.span = impl_item_span;
+                    if let Some(impl_item_span) = items
+                        .iter()
+                        .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+                        .map(fix_span)
+                    {
+                        cause.span = impl_item_span;
+                    }
                 }
             }
         }
@@ -235,13 +238,16 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
             // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`.
             debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred);
             if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = *pred.self_ty().kind() {
-                if let Some(impl_item_span) = trait_assoc_items
-                    .find(|i| i.def_id == item_def_id)
-                    .and_then(|trait_assoc_item| {
-                        items.iter().find(|i| i.ident == trait_assoc_item.ident).map(fix_span)
-                    })
+                if let Some(&impl_item_id) =
+                    tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id)
                 {
-                    cause.span = impl_item_span;
+                    if let Some(impl_item_span) = items
+                        .iter()
+                        .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+                        .map(fix_span)
+                    {
+                        cause.span = impl_item_span;
+                    }
                 }
             }
         }
@@ -312,7 +318,6 @@ fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elabo
                 item,
                 &mut cause,
                 &obligation.predicate,
-                tcx.associated_items(trait_ref.def_id).in_definition_order(),
             );
             traits::Obligation::with_depth(cause, depth, param_env, obligation.predicate)
         };
@@ -423,7 +428,7 @@ fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<
 
     /// Pushes all the predicates needed to validate that `ty` is WF into `out`.
     fn compute(&mut self, arg: GenericArg<'tcx>) {
-        let mut walker = arg.walk(self.tcx());
+        let mut walker = arg.walk();
         let param_env = self.param_env;
         let depth = self.recursion_depth;
         while let Some(arg) = walker.next() {
@@ -437,16 +442,12 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                 GenericArgKind::Const(constant) => {
                     match constant.val {
                         ty::ConstKind::Unevaluated(uv) => {
-                            assert!(uv.promoted.is_none());
-                            let substs = uv.substs(self.tcx());
-
-                            let obligations = self.nominal_obligations(uv.def.did, substs);
+                            let obligations = self.nominal_obligations(uv.def.did, uv.substs);
                             self.out.extend(obligations);
 
-                            let predicate = ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
-                                ty::Unevaluated::new(uv.def, substs),
-                            ))
-                            .to_predicate(self.tcx());
+                            let predicate =
+                                ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink()))
+                                    .to_predicate(self.tcx());
                             let cause = self.cause(traits::MiscObligation);
                             self.out.push(traits::Obligation::with_depth(
                                 cause,
index c38680651af7f276c605de1c0cffb5da3aaa2aca..3f51442277f5940f16c493959088ab8ec224587f 100644 (file)
@@ -436,23 +436,13 @@ fn associated_ty_value(
     ) -> Arc<chalk_solve::rust_ir::AssociatedTyValue<RustInterner<'tcx>>> {
         let def_id = associated_ty_id.0;
         let assoc_item = self.interner.tcx.associated_item(def_id);
-        let (impl_id, trait_id) = match assoc_item.container {
-            AssocItemContainer::TraitContainer(def_id) => (def_id, def_id),
-            AssocItemContainer::ImplContainer(def_id) => {
-                (def_id, self.interner.tcx.impl_trait_ref(def_id).unwrap().def_id)
-            }
-        };
+        let impl_id = assoc_item.container.id();
         match assoc_item.kind {
             AssocKind::Type => {}
             _ => unimplemented!("Not possible??"),
         }
 
-        let trait_item = self
-            .interner
-            .tcx
-            .associated_items(trait_id)
-            .find_by_name_and_kind(self.interner.tcx, assoc_item.ident, assoc_item.kind, trait_id)
-            .unwrap();
+        let trait_item_id = assoc_item.trait_item_def_id.expect("assoc_ty with no trait version");
         let bound_vars = bound_vars_for_item(self.interner.tcx, def_id);
         let binders = binders_for(self.interner, bound_vars);
         let ty = self
@@ -464,7 +454,7 @@ fn associated_ty_value(
 
         Arc::new(chalk_solve::rust_ir::AssociatedTyValue {
             impl_id: chalk_ir::ImplId(impl_id),
-            associated_ty_id: chalk_ir::AssocTypeId(trait_item.def_id),
+            associated_ty_id: chalk_ir::AssocTypeId(trait_item_id),
             value: chalk_ir::Binders::new(
                 binders,
                 chalk_solve::rust_ir::AssociatedTyValueBound { ty },
index cc07bfc50081646ddad396cc7c70de0c53c7467b..36c536c0ba3b2af0273852b537d7e45f31fd1134 100644 (file)
@@ -806,7 +806,7 @@ fn lower_into(
     tcx: TyCtxt<'tcx>,
     ty: Binder<'tcx, T>,
 ) -> (T, chalk_ir::VariableKinds<RustInterner<'tcx>>, BTreeMap<DefId, u32>) {
-    let mut bound_vars_collector = BoundVarsCollector::new(tcx);
+    let mut bound_vars_collector = BoundVarsCollector::new();
     ty.as_ref().skip_binder().visit_with(&mut bound_vars_collector);
     let mut parameters = bound_vars_collector.parameters;
     let named_parameters: BTreeMap<DefId, u32> = bound_vars_collector
@@ -836,16 +836,14 @@ fn lower_into(
 }
 
 crate struct BoundVarsCollector<'tcx> {
-    tcx: TyCtxt<'tcx>,
     binder_index: ty::DebruijnIndex,
     crate parameters: BTreeMap<u32, chalk_ir::VariableKind<RustInterner<'tcx>>>,
     crate named_parameters: Vec<DefId>,
 }
 
 impl<'tcx> BoundVarsCollector<'tcx> {
-    crate fn new(tcx: TyCtxt<'tcx>) -> Self {
+    crate fn new() -> Self {
         BoundVarsCollector {
-            tcx,
             binder_index: ty::INNERMOST,
             parameters: BTreeMap::new(),
             named_parameters: vec![],
@@ -854,10 +852,6 @@ impl<'tcx> BoundVarsCollector<'tcx> {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.tcx)
-    }
-
     fn visit_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: &Binder<'tcx, T>,
@@ -1076,11 +1070,6 @@ impl PlaceholdersCollector {
 }
 
 impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector {
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        // Anon const substs do not contain placeholders by default.
-        None
-    }
-
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match t.kind() {
             ty::Placeholder(p) if p.universe == self.universe_index => {
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
new file mode 100644 (file)
index 0000000..781a639
--- /dev/null
@@ -0,0 +1,136 @@
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::ty::{self, TyCtxt};
+
+pub fn provide(providers: &mut ty::query::Providers) {
+    *providers = ty::query::Providers {
+        associated_item,
+        associated_item_def_ids,
+        associated_items,
+        impl_item_implementor_ids,
+        trait_of_item,
+        ..*providers
+    };
+}
+
+fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
+    let item = tcx.hir().expect_item(def_id.expect_local());
+    match item.kind {
+        hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
+            trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
+        ),
+        hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
+            impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
+        ),
+        hir::ItemKind::TraitAlias(..) => &[],
+        _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
+    }
+}
+
+fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
+    let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
+    ty::AssocItems::new(items)
+}
+
+fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> FxHashMap<DefId, DefId> {
+    tcx.associated_items(impl_id)
+        .in_definition_order()
+        .filter_map(|item| item.trait_item_def_id.map(|trait_item| (trait_item, item.def_id)))
+        .collect()
+}
+
+/// If the given `DefId` describes an item belonging to a trait,
+/// returns the `DefId` of the trait that the trait item belongs to;
+/// otherwise, returns `None`.
+fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
+    tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
+        ty::TraitContainer(def_id) => Some(def_id),
+        ty::ImplContainer(_) => None,
+    })
+}
+
+fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
+    let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+    let parent_def_id = tcx.hir().get_parent_item(id);
+    let parent_item = tcx.hir().expect_item(parent_def_id);
+    match parent_item.kind {
+        hir::ItemKind::Impl(ref impl_) => {
+            if let Some(impl_item_ref) =
+                impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+            {
+                let assoc_item =
+                    associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
+                debug_assert_eq!(assoc_item.def_id, def_id);
+                return assoc_item;
+            }
+        }
+
+        hir::ItemKind::Trait(.., ref trait_item_refs) => {
+            if let Some(trait_item_ref) =
+                trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+            {
+                let assoc_item =
+                    associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
+                debug_assert_eq!(assoc_item.def_id, def_id);
+                return assoc_item;
+            }
+        }
+
+        _ => {}
+    }
+
+    span_bug!(
+        parent_item.span,
+        "unexpected parent of trait or impl item or item not found: {:?}",
+        parent_item.kind
+    )
+}
+
+fn associated_item_from_trait_item_ref(
+    tcx: TyCtxt<'_>,
+    parent_def_id: LocalDefId,
+    trait_item_ref: &hir::TraitItemRef,
+) -> ty::AssocItem {
+    let def_id = trait_item_ref.id.def_id;
+    let (kind, has_self) = match trait_item_ref.kind {
+        hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+        hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
+        hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+    };
+
+    ty::AssocItem {
+        ident: trait_item_ref.ident,
+        kind,
+        vis: tcx.visibility(def_id),
+        defaultness: trait_item_ref.defaultness,
+        def_id: def_id.to_def_id(),
+        trait_item_def_id: Some(def_id.to_def_id()),
+        container: ty::TraitContainer(parent_def_id.to_def_id()),
+        fn_has_self_parameter: has_self,
+    }
+}
+
+fn associated_item_from_impl_item_ref(
+    tcx: TyCtxt<'_>,
+    parent_def_id: LocalDefId,
+    impl_item_ref: &hir::ImplItemRef,
+) -> ty::AssocItem {
+    let def_id = impl_item_ref.id.def_id;
+    let (kind, has_self) = match impl_item_ref.kind {
+        hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
+        hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
+        hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+    };
+
+    ty::AssocItem {
+        ident: impl_item_ref.ident,
+        kind,
+        vis: tcx.visibility(def_id),
+        defaultness: impl_item_ref.defaultness,
+        def_id: def_id.to_def_id(),
+        trait_item_def_id: impl_item_ref.trait_item_def_id,
+        container: ty::ImplContainer(parent_def_id.to_def_id()),
+        fn_has_self_parameter: has_self,
+    }
+}
index 13ffb2a5adc860b39d3173db80afaace4b76f713..e7cc0f69e9f952804cb7870e8677a03678e3a384 100644 (file)
@@ -54,10 +54,6 @@ fn into_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx ty::List<ty::BoundVariableKind> {
 impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> {
     type BreakTy = ();
 
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        // Anon const substs do not contain bound vars by default.
-        None
-    }
     fn visit_binder<T: TypeFoldable<'tcx>>(
         &mut self,
         t: &Binder<'tcx, T>,
@@ -152,8 +148,7 @@ fn inner_resolve_instance<'tcx>(
 
     let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) {
         debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
-        let item = tcx.associated_item(def.did);
-        resolve_associated_item(tcx, &item, param_env, trait_def_id, substs)
+        resolve_associated_item(tcx, def.did, param_env, trait_def_id, substs)
     } else {
         let ty = tcx.type_of(def.def_id_for_type_of());
         let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
@@ -204,19 +199,12 @@ fn inner_resolve_instance<'tcx>(
 
 fn resolve_associated_item<'tcx>(
     tcx: TyCtxt<'tcx>,
-    trait_item: &ty::AssocItem,
+    trait_item_id: DefId,
     param_env: ty::ParamEnv<'tcx>,
     trait_id: DefId,
     rcvr_substs: SubstsRef<'tcx>,
 ) -> Result<Option<Instance<'tcx>>, ErrorReported> {
-    let def_id = trait_item.def_id;
-    debug!(
-        "resolve_associated_item(trait_item={:?}, \
-            param_env={:?}, \
-            trait_id={:?}, \
-            rcvr_substs={:?})",
-        def_id, param_env, trait_id, rcvr_substs
-    );
+    debug!(?trait_item_id, ?param_env, ?trait_id, ?rcvr_substs, "resolve_associated_item");
 
     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
 
@@ -232,7 +220,7 @@ fn resolve_associated_item<'tcx>(
         traits::ImplSource::UserDefined(impl_data) => {
             debug!(
                 "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",
-                param_env, trait_item, rcvr_substs, impl_data
+                param_env, trait_item_id, rcvr_substs, impl_data
             );
             assert!(!rcvr_substs.needs_infer());
             assert!(!trait_ref.needs_infer());
@@ -241,9 +229,9 @@ fn resolve_associated_item<'tcx>(
             let trait_def = tcx.trait_def(trait_def_id);
             let leaf_def = trait_def
                 .ancestors(tcx, impl_data.impl_def_id)?
-                .leaf_def(tcx, trait_item.ident, trait_item.kind)
+                .leaf_def(tcx, trait_item_id)
                 .unwrap_or_else(|| {
-                    bug!("{:?} not found in {:?}", trait_item, impl_data.impl_def_id);
+                    bug!("{:?} not found in {:?}", trait_item_id, impl_data.impl_def_id);
                 });
 
             let substs = tcx.infer_ctxt().enter(|infcx| {
@@ -297,22 +285,22 @@ fn resolve_associated_item<'tcx>(
             // performs (i.e. that the definition's type in the `impl` matches
             // the declaration in the `trait`), so that we can cheaply check
             // here if it failed, instead of approximating it.
-            if trait_item.kind == ty::AssocKind::Const
-                && trait_item.def_id != leaf_def.item.def_id
+            if leaf_def.item.kind == ty::AssocKind::Const
+                && trait_item_id != leaf_def.item.def_id
                 && leaf_def.item.def_id.is_local()
             {
                 let normalized_type_of = |def_id, substs| {
                     tcx.subst_and_normalize_erasing_regions(substs, param_env, tcx.type_of(def_id))
                 };
 
-                let original_ty = normalized_type_of(trait_item.def_id, rcvr_substs);
+                let original_ty = normalized_type_of(trait_item_id, rcvr_substs);
                 let resolved_ty = normalized_type_of(leaf_def.item.def_id, substs);
 
                 if original_ty != resolved_ty {
                     let msg = format!(
                         "Instance::resolve: inconsistent associated `const` type: \
                          was `{}: {}` but resolved to `{}: {}`",
-                        tcx.def_path_str_with_substs(trait_item.def_id, rcvr_substs),
+                        tcx.def_path_str_with_substs(trait_item_id, rcvr_substs),
                         original_ty,
                         tcx.def_path_str_with_substs(leaf_def.item.def_id, substs),
                         resolved_ty,
@@ -343,19 +331,22 @@ fn resolve_associated_item<'tcx>(
         }
         traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
             ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
-                def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty),
+                def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
                 substs: rcvr_substs,
             }),
             _ => None,
         },
         traits::ImplSource::Object(ref data) => {
-            let index = traits::get_vtable_index_of_object_method(tcx, data, def_id);
-            Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs })
+            let index = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id);
+            Some(Instance {
+                def: ty::InstanceDef::Virtual(trait_item_id, index),
+                substs: rcvr_substs,
+            })
         }
         traits::ImplSource::Builtin(..) => {
             if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() {
                 // FIXME(eddyb) use lang items for methods instead of names.
-                let name = tcx.item_name(def_id);
+                let name = tcx.item_name(trait_item_id);
                 if name == sym::clone {
                     let self_ty = trait_ref.self_ty();
 
@@ -367,7 +358,7 @@ fn resolve_associated_item<'tcx>(
                     };
 
                     Some(Instance {
-                        def: ty::InstanceDef::CloneShim(def_id, self_ty),
+                        def: ty::InstanceDef::CloneShim(trait_item_id, self_ty),
                         substs: rcvr_substs,
                     })
                 } else {
@@ -375,7 +366,7 @@ fn resolve_associated_item<'tcx>(
 
                     // Use the default `fn clone_from` from `trait Clone`.
                     let substs = tcx.erase_regions(rcvr_substs);
-                    Some(ty::Instance::new(def_id, substs))
+                    Some(ty::Instance::new(trait_item_id, substs))
                 }
             } else {
                 None
index 60f8e196bcba1c8c4227b3efd28765e0521f5972..55e199907617cb72af846b85a8c6c357cb6492f6 100644 (file)
@@ -16,6 +16,7 @@
 
 use rustc_middle::ty::query::Providers;
 
+mod assoc;
 mod common_traits;
 pub mod instance;
 mod needs_drop;
@@ -23,6 +24,7 @@
 mod ty;
 
 pub fn provide(providers: &mut Providers) {
+    assoc::provide(providers);
     common_traits::provide(providers);
     needs_drop::provide(providers);
     ty::provide(providers);
index d3eb9fd95571400724496faf317b625e1dfa127f..fb7fdacf5e6874925f5efc1e07033298146f206d 100644 (file)
@@ -99,12 +99,7 @@ fn are_inner_types_recursive<'tcx>(
             // Find non representable fields with their spans
             fold_repr(def.all_fields().map(|field| {
                 let ty = field.ty(tcx, substs);
-                let span = match field
-                    .did
-                    .as_local()
-                    .map(|id| tcx.hir().local_def_id_to_hir_id(id))
-                    .and_then(|id| tcx.hir().find(id))
-                {
+                let span = match field.did.as_local().and_then(|id| tcx.hir().find_by_def_id(id)) {
                     Some(hir::Node::Field(field)) => field.ty.span,
                     _ => sp,
                 };
index 6c2657bd64bdbe47de19dafaa50545a05425063a..fef83190468196c32ee0257fb33c36aadd889724 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt};
 use rustc_span::{sym, Span};
@@ -71,90 +71,6 @@ fn sized_constraint_for_ty<'tcx>(
     result
 }
 
-fn associated_item_from_trait_item_ref(
-    tcx: TyCtxt<'_>,
-    parent_def_id: LocalDefId,
-    trait_item_ref: &hir::TraitItemRef,
-) -> ty::AssocItem {
-    let def_id = trait_item_ref.id.def_id;
-    let (kind, has_self) = match trait_item_ref.kind {
-        hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
-        hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
-        hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
-    };
-
-    ty::AssocItem {
-        ident: trait_item_ref.ident,
-        kind,
-        vis: tcx.visibility(def_id),
-        defaultness: trait_item_ref.defaultness,
-        def_id: def_id.to_def_id(),
-        container: ty::TraitContainer(parent_def_id.to_def_id()),
-        fn_has_self_parameter: has_self,
-    }
-}
-
-fn associated_item_from_impl_item_ref(
-    tcx: TyCtxt<'_>,
-    parent_def_id: LocalDefId,
-    impl_item_ref: &hir::ImplItemRef,
-) -> ty::AssocItem {
-    let def_id = impl_item_ref.id.def_id;
-    let (kind, has_self) = match impl_item_ref.kind {
-        hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
-        hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
-        hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
-    };
-
-    ty::AssocItem {
-        ident: impl_item_ref.ident,
-        kind,
-        vis: tcx.visibility(def_id),
-        defaultness: impl_item_ref.defaultness,
-        def_id: def_id.to_def_id(),
-        container: ty::ImplContainer(parent_def_id.to_def_id()),
-        fn_has_self_parameter: has_self,
-    }
-}
-
-fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
-    let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-    let parent_id = tcx.hir().get_parent_item(id);
-    let parent_def_id = tcx.hir().local_def_id(parent_id);
-    let parent_item = tcx.hir().expect_item(parent_def_id);
-    match parent_item.kind {
-        hir::ItemKind::Impl(ref impl_) => {
-            if let Some(impl_item_ref) =
-                impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
-            {
-                let assoc_item =
-                    associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
-                debug_assert_eq!(assoc_item.def_id, def_id);
-                return assoc_item;
-            }
-        }
-
-        hir::ItemKind::Trait(.., ref trait_item_refs) => {
-            if let Some(trait_item_ref) =
-                trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
-            {
-                let assoc_item =
-                    associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
-                debug_assert_eq!(assoc_item.def_id, def_id);
-                return assoc_item;
-            }
-        }
-
-        _ => {}
-    }
-
-    span_bug!(
-        parent_item.span,
-        "unexpected parent of trait or impl item or item not found: {:?}",
-        parent_item.kind
-    )
-}
-
 fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
     let item = tcx.hir().expect_item(def_id.expect_local());
     if let hir::ItemKind::Impl(impl_) = &item.kind {
@@ -197,25 +113,6 @@ fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstrain
     ty::AdtSizedConstraint(result)
 }
 
-fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
-    let item = tcx.hir().expect_item(def_id.expect_local());
-    match item.kind {
-        hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
-            trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
-        ),
-        hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
-            impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
-        ),
-        hir::ItemKind::TraitAlias(..) => &[],
-        _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
-    }
-}
-
-fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
-    let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
-    ty::AssocItems::new(items)
-}
-
 fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
     tcx.hir()
         .get_if_local(def_id)
@@ -231,16 +128,6 @@ fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
         .map(|ident| ident.span)
 }
 
-/// If the given `DefId` describes an item belonging to a trait,
-/// returns the `DefId` of the trait that the trait item belongs to;
-/// otherwise, returns `None`.
-fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
-    tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
-        ty::TraitContainer(def_id) => Some(def_id),
-        ty::ImplContainer(_) => None,
-    })
-}
-
 /// See `ParamEnv` struct definition for details.
 #[instrument(level = "debug", skip(tcx))]
 fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
@@ -270,16 +157,6 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
         predicates.extend(environment);
     }
 
-    // It's important that we include the default substs in unevaluated
-    // constants, since `Unevaluated` instances in predicates whose substs are None
-    // can lead to "duplicate" caller bounds candidates during trait selection,
-    // duplicate in the sense that both have their default substs, but the
-    // candidate that resulted from a superpredicate still uses `None` in its
-    // `substs_` field of `Unevaluated` to indicate that it has its default substs,
-    // whereas the other candidate has `substs_: Some(default_substs)`, see
-    // issue #89334
-    predicates = tcx.expose_default_const_substs(predicates);
-
     let local_did = def_id.as_local();
     let hir_id = local_did.map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id));
 
@@ -392,8 +269,7 @@ fn well_formed_types_in_env<'tcx>(
     if !def_id.is_local() {
         return ty::List::empty();
     }
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-    let node = tcx.hir().get(hir_id);
+    let node = tcx.hir().get_by_def_id(def_id.expect_local());
 
     enum NodeKind {
         TraitImpl,
@@ -447,7 +323,7 @@ enum NodeKind {
         // constituents are well-formed.
         NodeKind::InherentImpl => {
             let self_ty = tcx.type_of(def_id);
-            inputs.extend(self_ty.walk(tcx));
+            inputs.extend(self_ty.walk());
         }
 
         // In an fn, we assume that the arguments and all their constituents are
@@ -456,7 +332,7 @@ enum NodeKind {
             let fn_sig = tcx.fn_sig(def_id);
             let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig);
 
-            inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk(tcx)));
+            inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
         }
 
         NodeKind::Other => (),
@@ -549,9 +425,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> {
 
 /// Check if a function is async.
 fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-
-    let node = tcx.hir().get(hir_id);
+    let node = tcx.hir().get_by_def_id(def_id.expect_local());
 
     let fn_kind = node.fn_kind().unwrap_or_else(|| {
         bug!("asyncness: expected fn-like node but got `{:?}`", def_id);
@@ -620,14 +494,10 @@ pub fn conservative_is_privately_uninhabited_raw<'tcx>(
 pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
         asyncness,
-        associated_item,
-        associated_item_def_ids,
-        associated_items,
         adt_sized_constraint,
         def_ident_span,
         param_env,
         param_env_reveal_all_normalized,
-        trait_of_item,
         instance_def_size_estimate,
         issue33140_self_ty,
         impl_defaultness,
index f11c93e933996e328109c295ded2e9cdfb13e4f4..ec6fb622d32aa40c9f7d097115ed143fd1b609e3 100644 (file)
@@ -19,116 +19,94 @@ pub struct TypeFlags: u32 {
         // Does this have parameters? Used to determine whether substitution is
         // required.
         /// Does this have `Param`?
-        const HAS_KNOWN_TY_PARAM                = 1 << 0;
+        const HAS_TY_PARAM                = 1 << 0;
         /// Does this have `ReEarlyBound`?
-        const HAS_KNOWN_RE_PARAM                = 1 << 1;
+        const HAS_RE_PARAM                = 1 << 1;
         /// Does this have `ConstKind::Param`?
-        const HAS_KNOWN_CT_PARAM                = 1 << 2;
+        const HAS_CT_PARAM                = 1 << 2;
 
-        const KNOWN_NEEDS_SUBST                 = TypeFlags::HAS_KNOWN_TY_PARAM.bits
-                                                | TypeFlags::HAS_KNOWN_RE_PARAM.bits
-                                                | TypeFlags::HAS_KNOWN_CT_PARAM.bits;
+        const NEEDS_SUBST                 = TypeFlags::HAS_TY_PARAM.bits
+                                          | TypeFlags::HAS_RE_PARAM.bits
+                                          | TypeFlags::HAS_CT_PARAM.bits;
 
         /// Does this have `Infer`?
-        const HAS_TY_INFER                      = 1 << 3;
+        const HAS_TY_INFER                = 1 << 3;
         /// Does this have `ReVar`?
-        const HAS_RE_INFER                      = 1 << 4;
+        const HAS_RE_INFER                = 1 << 4;
         /// Does this have `ConstKind::Infer`?
-        const HAS_CT_INFER                      = 1 << 5;
+        const HAS_CT_INFER                = 1 << 5;
 
         /// Does this have inference variables? Used to determine whether
         /// inference is required.
-        const NEEDS_INFER                       = TypeFlags::HAS_TY_INFER.bits
-                                                | TypeFlags::HAS_RE_INFER.bits
-                                                | TypeFlags::HAS_CT_INFER.bits;
+        const NEEDS_INFER                 = TypeFlags::HAS_TY_INFER.bits
+                                          | TypeFlags::HAS_RE_INFER.bits
+                                          | TypeFlags::HAS_CT_INFER.bits;
 
         /// Does this have `Placeholder`?
-        const HAS_TY_PLACEHOLDER                = 1 << 6;
+        const HAS_TY_PLACEHOLDER          = 1 << 6;
         /// Does this have `RePlaceholder`?
-        const HAS_RE_PLACEHOLDER                = 1 << 7;
+        const HAS_RE_PLACEHOLDER          = 1 << 7;
         /// Does this have `ConstKind::Placeholder`?
-        const HAS_CT_PLACEHOLDER                = 1 << 8;
+        const HAS_CT_PLACEHOLDER          = 1 << 8;
 
         /// `true` if there are "names" of regions and so forth
         /// that are local to a particular fn/inferctxt
-        const HAS_KNOWN_FREE_LOCAL_REGIONS      = 1 << 9;
+        const HAS_FREE_LOCAL_REGIONS      = 1 << 9;
 
         /// `true` if there are "names" of types and regions and so forth
         /// that are local to a particular fn
-        const HAS_KNOWN_FREE_LOCAL_NAMES        = TypeFlags::HAS_KNOWN_TY_PARAM.bits
-                                                | TypeFlags::HAS_KNOWN_CT_PARAM.bits
-                                                | TypeFlags::HAS_TY_INFER.bits
-                                                | TypeFlags::HAS_CT_INFER.bits
-                                                | TypeFlags::HAS_TY_PLACEHOLDER.bits
-                                                | TypeFlags::HAS_CT_PLACEHOLDER.bits
-                                                // We consider 'freshened' types and constants
-                                                // to depend on a particular fn.
-                                                // The freshening process throws away information,
-                                                // which can make things unsuitable for use in a global
-                                                // cache. Note that there is no 'fresh lifetime' flag -
-                                                // freshening replaces all lifetimes with `ReErased`,
-                                                // which is different from how types/const are freshened.
-                                                | TypeFlags::HAS_TY_FRESH.bits
-                                                | TypeFlags::HAS_CT_FRESH.bits
-                                                | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS.bits;
-
-        const HAS_POTENTIAL_FREE_LOCAL_NAMES    = TypeFlags::HAS_KNOWN_FREE_LOCAL_NAMES.bits
-                                                | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits;
+        const HAS_FREE_LOCAL_NAMES        = TypeFlags::HAS_TY_PARAM.bits
+                                          | TypeFlags::HAS_CT_PARAM.bits
+                                          | TypeFlags::HAS_TY_INFER.bits
+                                          | TypeFlags::HAS_CT_INFER.bits
+                                          | TypeFlags::HAS_TY_PLACEHOLDER.bits
+                                          | TypeFlags::HAS_CT_PLACEHOLDER.bits
+                                          // We consider 'freshened' types and constants
+                                          // to depend on a particular fn.
+                                          // The freshening process throws away information,
+                                          // which can make things unsuitable for use in a global
+                                          // cache. Note that there is no 'fresh lifetime' flag -
+                                          // freshening replaces all lifetimes with `ReErased`,
+                                          // which is different from how types/const are freshened.
+                                          | TypeFlags::HAS_TY_FRESH.bits
+                                          | TypeFlags::HAS_CT_FRESH.bits
+                                          | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits;
 
         /// Does this have `Projection`?
-        const HAS_TY_PROJECTION                 = 1 << 10;
+        const HAS_TY_PROJECTION           = 1 << 10;
         /// Does this have `Opaque`?
-        const HAS_TY_OPAQUE                     = 1 << 11;
+        const HAS_TY_OPAQUE               = 1 << 11;
         /// Does this have `ConstKind::Unevaluated`?
-        const HAS_CT_PROJECTION                 = 1 << 12;
+        const HAS_CT_PROJECTION           = 1 << 12;
 
         /// Could this type be normalized further?
-        const HAS_PROJECTION                    = TypeFlags::HAS_TY_PROJECTION.bits
-                                                | TypeFlags::HAS_TY_OPAQUE.bits
-                                                | TypeFlags::HAS_CT_PROJECTION.bits;
+        const HAS_PROJECTION              = TypeFlags::HAS_TY_PROJECTION.bits
+                                          | TypeFlags::HAS_TY_OPAQUE.bits
+                                          | TypeFlags::HAS_CT_PROJECTION.bits;
 
         /// Is an error type/const reachable?
-        const HAS_ERROR                         = 1 << 13;
+        const HAS_ERROR                   = 1 << 13;
 
         /// Does this have any region that "appears free" in the type?
         /// Basically anything but `ReLateBound` and `ReErased`.
-        const HAS_KNOWN_FREE_REGIONS            = 1 << 14;
-
-        const HAS_POTENTIAL_FREE_REGIONS        = TypeFlags::HAS_KNOWN_FREE_REGIONS.bits
-                                                | TypeFlags::HAS_UNKNOWN_DEFAULT_CONST_SUBSTS.bits;
+        const HAS_FREE_REGIONS            = 1 << 14;
 
         /// Does this have any `ReLateBound` regions? Used to check
         /// if a global bound is safe to evaluate.
-        const HAS_RE_LATE_BOUND                 = 1 << 15;
+        const HAS_RE_LATE_BOUND           = 1 << 15;
 
         /// Does this have any `ReErased` regions?
-        const HAS_RE_ERASED                     = 1 << 16;
+        const HAS_RE_ERASED               = 1 << 16;
 
         /// Does this value have parameters/placeholders/inference variables which could be
         /// replaced later, in a way that would change the results of `impl` specialization?
-        ///
-        /// Note that this flag being set is not a guarantee, as it is also
-        /// set if there are any anon consts with unknown default substs.
-        const STILL_FURTHER_SPECIALIZABLE       = 1 << 17;
+        const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
 
         /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
-        const HAS_TY_FRESH                      = 1 << 18;
+        const HAS_TY_FRESH                = 1 << 18;
 
         /// Does this value have `InferConst::Fresh`?
-        const HAS_CT_FRESH                      = 1 << 19;
-
-        /// Does this value have unknown default anon const substs.
-        ///
-        /// For more details refer to...
-        /// FIXME(@lcnr): ask me for now, still have to write all of this.
-        const HAS_UNKNOWN_DEFAULT_CONST_SUBSTS  = 1 << 20;
-        /// Flags which can be influenced by default anon const substs.
-        const MAY_NEED_DEFAULT_CONST_SUBSTS     = TypeFlags::HAS_KNOWN_RE_PARAM.bits
-                                                | TypeFlags::HAS_KNOWN_TY_PARAM.bits
-                                                | TypeFlags::HAS_KNOWN_CT_PARAM.bits
-                                                | TypeFlags::HAS_KNOWN_FREE_LOCAL_REGIONS.bits
-                                                | TypeFlags::HAS_KNOWN_FREE_REGIONS.bits;
-
+        const HAS_CT_FRESH                = 1 << 19;
     }
 }
 
index ea54b85b2f20c889162316f7d570f11cffc572ff..1f99a9b0536d0e967a54d17ddcef6d170d387162 100644 (file)
@@ -93,62 +93,96 @@ pub(crate) fn complain_about_internal_fn_trait(
         span: Span,
         trait_def_id: DefId,
         trait_segment: &'_ hir::PathSegment<'_>,
+        is_impl: bool,
     ) {
+        if self.tcx().features().unboxed_closures {
+            return;
+        }
+
         let trait_def = self.tcx().trait_def(trait_def_id);
+        if !trait_def.paren_sugar {
+            if trait_segment.args().parenthesized {
+                // For now, require that parenthetical notation be used only with `Fn()` etc.
+                let mut err = feature_err(
+                    &self.tcx().sess.parse_sess,
+                    sym::unboxed_closures,
+                    span,
+                    "parenthetical notation is only stable when used with `Fn`-family traits",
+                );
+                err.emit();
+            }
 
-        if !self.tcx().features().unboxed_closures
-            && trait_segment.args().parenthesized != trait_def.paren_sugar
-        {
-            let sess = &self.tcx().sess.parse_sess;
+            return;
+        }
+
+        let sess = self.tcx().sess;
+
+        if !trait_segment.args().parenthesized {
             // For now, require that parenthetical notation be used only with `Fn()` etc.
-            let (msg, sugg) = if trait_def.paren_sugar {
-                (
-                    "the precise format of `Fn`-family traits' type parameters is subject to \
-                     change",
-                    Some(format!(
-                        "{}{} -> {}",
-                        trait_segment.ident,
-                        trait_segment
-                            .args
-                            .as_ref()
-                            .and_then(|args| args.args.get(0))
-                            .and_then(|arg| match arg {
-                                hir::GenericArg::Type(ty) => match ty.kind {
-                                    hir::TyKind::Tup(t) => t
-                                        .iter()
-                                        .map(|e| sess.source_map().span_to_snippet(e.span))
-                                        .collect::<Result<Vec<_>, _>>()
-                                        .map(|a| a.join(", ")),
-                                    _ => sess.source_map().span_to_snippet(ty.span),
-                                }
-                                .map(|s| format!("({})", s))
-                                .ok(),
-                                _ => None,
-                            })
-                            .unwrap_or_else(|| "()".to_string()),
-                        trait_segment
-                            .args()
-                            .bindings
-                            .iter()
-                            .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
-                                (true, hir::TypeBindingKind::Equality { ty }) => {
-                                    sess.source_map().span_to_snippet(ty.span).ok()
-                                }
-                                _ => None,
-                            })
-                            .unwrap_or_else(|| "()".to_string()),
-                    )),
-                )
-            } else {
-                ("parenthetical notation is only stable when used with `Fn`-family traits", None)
-            };
-            let mut err = feature_err(sess, sym::unboxed_closures, span, msg);
-            if let Some(sugg) = sugg {
-                let msg = "use parenthetical notation instead";
-                err.span_suggestion(span, msg, sugg, Applicability::MaybeIncorrect);
+            let mut err = feature_err(
+                &sess.parse_sess,
+                sym::unboxed_closures,
+                span,
+                "the precise format of `Fn`-family traits' type parameters is subject to change",
+            );
+            // Do not suggest the other syntax if we are in trait impl:
+            // the desugaring would contain an associated type constrait.
+            if !is_impl {
+                let args = trait_segment
+                    .args
+                    .as_ref()
+                    .and_then(|args| args.args.get(0))
+                    .and_then(|arg| match arg {
+                        hir::GenericArg::Type(ty) => match ty.kind {
+                            hir::TyKind::Tup(t) => t
+                                .iter()
+                                .map(|e| sess.source_map().span_to_snippet(e.span))
+                                .collect::<Result<Vec<_>, _>>()
+                                .map(|a| a.join(", ")),
+                            _ => sess.source_map().span_to_snippet(ty.span),
+                        }
+                        .map(|s| format!("({})", s))
+                        .ok(),
+                        _ => None,
+                    })
+                    .unwrap_or_else(|| "()".to_string());
+                let ret = trait_segment
+                    .args()
+                    .bindings
+                    .iter()
+                    .find_map(|b| match (b.ident.name == sym::Output, &b.kind) {
+                        (true, hir::TypeBindingKind::Equality { ty }) => {
+                            sess.source_map().span_to_snippet(ty.span).ok()
+                        }
+                        _ => None,
+                    })
+                    .unwrap_or_else(|| "()".to_string());
+                err.span_suggestion(
+                    span,
+                    "use parenthetical notation instead",
+                    format!("{}{} -> {}", trait_segment.ident, args, ret),
+                    Applicability::MaybeIncorrect,
+                );
             }
             err.emit();
         }
+
+        if is_impl {
+            let trait_name = self.tcx().def_path_str(trait_def_id);
+            struct_span_err!(
+                self.tcx().sess,
+                span,
+                E0183,
+                "manual implementations of `{}` are experimental",
+                trait_name,
+            )
+            .span_label(
+                span,
+                format!("manual implementations of `{}` are experimental", trait_name),
+            )
+            .help("add `#![feature(unboxed_closures)]` to the crate attributes to enable")
+            .emit();
+        }
     }
 
     pub(crate) fn complain_about_assoc_type_not_found<I>(
index caa5c71e21cd940525ff88bae9411e9a08b724be..956696546da8ef9a9298bab17427d54f17c522ca 100644 (file)
@@ -104,7 +104,7 @@ fn generic_arg_mismatch_err(
                 GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
                 GenericParamDefKind::Const { .. },
             ) if tcx.type_of(param.def_id) == tcx.types.usize => {
-                let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id));
+                let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id()));
                 if let Ok(snippet) = snippet {
                     err.span_suggestion(
                         arg.span(),
index 8db706c3709c1451767dd68a37bc67a53b9318e9..2ada1c0ddf4fa19c9fc6275577d72337ece2e415 100644 (file)
@@ -288,7 +288,7 @@ pub fn ast_path_substs_for_ty(
     /// Given the type/lifetime/const arguments provided to some path (along with
     /// an implicit `Self`, if this is a trait reference), returns the complete
     /// set of substitutions. This may involve applying defaulted type parameters.
-    /// Also returns back constraints on associated types.
+    /// Constraints on associated typess are created from `create_assoc_bindings_for_generic_args`.
     ///
     /// Example:
     ///
@@ -302,7 +302,7 @@ pub fn ast_path_substs_for_ty(
     ///    which will have been resolved to a `def_id`
     /// 3. The `generic_args` contains info on the `<...>` contents. The `usize` type
     ///    parameters are returned in the `SubstsRef`, the associated type bindings like
-    ///    `Output = u32` are returned in the `Vec<ConvertedBinding...>` result.
+    ///    `Output = u32` are returned from `create_assoc_bindings_for_generic_args`.
     ///
     /// Note that the type listing given here is *exactly* what the user provided.
     ///
@@ -388,7 +388,7 @@ fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool {
                     if self.is_object && has_default {
                         let default_ty = tcx.at(self.span).type_of(param.def_id);
                         let self_param = tcx.types.self_param;
-                        if default_ty.walk(tcx).any(|arg| arg == self_param.into()) {
+                        if default_ty.walk().any(|arg| arg == self_param.into()) {
                             // There is no suitable inference default for a type parameter
                             // that references self, in an object type.
                             return true;
@@ -669,6 +669,7 @@ pub fn instantiate_mono_trait_ref(
             trait_ref.trait_def_id().unwrap_or_else(|| FatalError.raise()),
             self_ty,
             trait_ref.path.segments.last().unwrap(),
+            true,
         )
     }
 
@@ -765,7 +766,7 @@ pub(crate) fn instantiate_poly_trait_ref(
         let infer_args = trait_segment.infer_args;
 
         self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1);
-        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
+        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, false);
 
         self.instantiate_poly_trait_ref_inner(
             hir_id,
@@ -822,9 +823,15 @@ fn ast_path_to_mono_trait_ref(
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         trait_segment: &hir::PathSegment<'_>,
+        is_impl: bool,
     ) -> ty::TraitRef<'tcx> {
-        let (substs, _) =
-            self.create_substs_for_ast_trait_ref(span, trait_def_id, self_ty, trait_segment);
+        let (substs, _) = self.create_substs_for_ast_trait_ref(
+            span,
+            trait_def_id,
+            self_ty,
+            trait_segment,
+            is_impl,
+        );
         let assoc_bindings = self.create_assoc_bindings_for_generic_args(trait_segment.args());
         if let Some(b) = assoc_bindings.first() {
             Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
@@ -839,8 +846,9 @@ fn create_substs_for_ast_trait_ref<'a>(
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         trait_segment: &'a hir::PathSegment<'a>,
+        is_impl: bool,
     ) -> (SubstsRef<'tcx>, GenericArgCountResult) {
-        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment);
+        self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
 
         self.create_substs_for_ast_path(
             span,
@@ -1370,7 +1378,7 @@ trait here instead: `trait NewTrait: {} {{}}`",
                         // A `Self` within the original bound will be substituted with a
                         // `trait_object_dummy_self`, so check for that.
                         let references_self =
-                            pred.skip_binder().ty.walk(tcx).any(|arg| arg == dummy_self.into());
+                            pred.skip_binder().ty.walk().any(|arg| arg == dummy_self.into());
 
                         // If the projection output contains `Self`, force the user to
                         // elaborate it explicitly to avoid a lot of complexity.
@@ -1727,7 +1735,7 @@ pub fn associated_path_to_ty(
                 let variant_def = adt_def
                     .variants
                     .iter()
-                    .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident, adt_def.did));
+                    .find(|vd| tcx.hygienic_eq(assoc_ident, vd.ident(tcx), adt_def.did));
                 if let Some(variant_def) = variant_def {
                     if permit_variants {
                         tcx.check_stability(variant_def.def_id, Some(hir_ref_id), span, None);
@@ -1786,7 +1794,7 @@ pub fn associated_path_to_ty(
                         &adt_def
                             .variants
                             .iter()
-                            .map(|variant| variant.ident.name)
+                            .map(|variant| variant.name)
                             .collect::<Vec<Symbol>>(),
                         assoc_ident.name,
                         None,
@@ -1906,7 +1914,7 @@ fn qpath_to_ty(
                 .and_then(|def_id| {
                     def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
                 })
-                .map(|hir_id| tcx.hir().get_parent_did(hir_id).to_def_id());
+                .map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id());
 
             debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id);
 
@@ -1932,7 +1940,8 @@ fn qpath_to_ty(
 
         debug!("qpath_to_ty: self_type={:?}", self_ty);
 
-        let trait_ref = self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment);
+        let trait_ref =
+            self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
 
         let item_substs = self.create_substs_for_associated_item(
             tcx,
@@ -2216,7 +2225,7 @@ pub fn res_to_ty(
                 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.definitely_needs_subst(tcx) {
+                if forbid_generic && normalized_ty.needs_subst() {
                     let mut err = tcx.sess.struct_span_err(
                         path.span,
                         "generic `Self` types are currently not permitted in anonymous constants",
@@ -2363,8 +2372,14 @@ fn ast_ty_to_ty_inner(&self, ast_ty: &hir::Ty<'_>, borrowed: bool, in_path: bool
                 self.normalize_ty(span, tcx.at(span).type_of(def_id).subst(tcx, substs))
             }
             hir::TyKind::Array(ref ty, ref length) => {
-                let length_def_id = tcx.hir().local_def_id(length.hir_id);
-                let length = ty::Const::from_anon_const(tcx, length_def_id);
+                let length = match length {
+                    &hir::ArrayLen::Infer(_, span) => self.ct_infer(tcx.types.usize, None, span),
+                    hir::ArrayLen::Body(constant) => {
+                        let length_def_id = tcx.hir().local_def_id(constant.hir_id);
+                        ty::Const::from_anon_const(tcx, length_def_id)
+                    }
+                };
+
                 let array_ty = tcx.mk_ty(ty::Array(self.ast_ty_to_ty(ty), length));
                 self.normalize_ty(ast_ty.span, array_ty)
             }
index e67ee1cab3df264fd42f7885e52e92b5fad2f3b7..eea8f40635d74a416ee51b9f6159c164b4222737 100644 (file)
@@ -496,7 +496,7 @@ fn confirm_builtin_call(
             call_expr.span,
             call_expr,
             fn_sig.inputs(),
-            &expected_arg_tys,
+            expected_arg_tys,
             arg_exprs,
             fn_sig.c_variadic,
             TupleArgumentsFlag::DontTupleArguments,
@@ -529,7 +529,7 @@ fn confirm_deferred_closure_call(
             call_expr.span,
             call_expr,
             fn_sig.inputs(),
-            &expected_arg_tys,
+            expected_arg_tys,
             arg_exprs,
             fn_sig.c_variadic,
             TupleArgumentsFlag::TupleArguments,
index fd7b3a55dfb97b59d61bb1e2cca8e3f2c6ae65ce..b884f4c9b8964724c53a57a5c788e08c1b74d5fc 100644 (file)
@@ -462,17 +462,14 @@ pub(super) fn check_opaque_for_inheriting_lifetimes<'tcx>(
     debug!(?item, ?span);
 
     struct FoundParentLifetime;
-    struct FindParentLifetimeVisitor<'tcx>(TyCtxt<'tcx>, &'tcx ty::Generics);
+    struct FindParentLifetimeVisitor<'tcx>(&'tcx ty::Generics);
     impl<'tcx> ty::fold::TypeVisitor<'tcx> for FindParentLifetimeVisitor<'tcx> {
         type BreakTy = FoundParentLifetime;
-        fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-            Some(self.0)
-        }
 
         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.1.parent_count as u32 {
+                if *index < self.0.parent_count as u32 {
                     return ControlFlow::Break(FoundParentLifetime);
                 } else {
                     return ControlFlow::CONTINUE;
@@ -502,16 +499,13 @@ struct ProhibitOpaqueVisitor<'tcx> {
 
     impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
         type BreakTy = Ty<'tcx>;
-        fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-            Some(self.tcx)
-        }
 
         fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
             debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t);
             if t == self.opaque_identity_ty {
                 ControlFlow::CONTINUE
             } else {
-                t.super_visit_with(&mut FindParentLifetimeVisitor(self.tcx, self.generics))
+                t.super_visit_with(&mut FindParentLifetimeVisitor(self.generics))
                     .map_break(|FoundParentLifetime| t)
             }
         }
@@ -626,6 +620,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
 ///
 /// Without this check the above code is incorrectly accepted: we would ICE if
 /// some tried, for example, to clone an `Option<X<&mut ()>>`.
+#[instrument(level = "debug", skip(tcx))]
 fn check_opaque_meets_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
@@ -633,17 +628,14 @@ fn check_opaque_meets_bounds<'tcx>(
     span: Span,
     origin: &hir::OpaqueTyOrigin,
 ) {
-    match origin {
-        // Checked when type checking the function containing them.
-        hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
-        // Can have different predicates to their defining use
-        hir::OpaqueTyOrigin::TyAlias => {}
-    }
-
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let param_env = tcx.param_env(def_id);
+    let defining_use_anchor = match *origin {
+        hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
+        hir::OpaqueTyOrigin::TyAlias => def_id,
+    };
+    let param_env = tcx.param_env(defining_use_anchor);
 
-    tcx.infer_ctxt().enter(move |infcx| {
+    tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).enter(move |infcx| {
         let inh = Inherited::new(infcx, def_id);
         let infcx = &inh.infcx;
         let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
@@ -656,16 +648,15 @@ fn check_opaque_meets_bounds<'tcx>(
 
         let opaque_type_map = infcx.inner.borrow().opaque_types.clone();
         for (OpaqueTypeKey { def_id, substs }, opaque_defn) in opaque_type_map {
-            match infcx
-                .at(&misc_cause, param_env)
-                .eq(opaque_defn.concrete_ty, tcx.type_of(def_id).subst(tcx, substs))
-            {
+            let hidden_type = tcx.type_of(def_id).subst(tcx, substs);
+            trace!(?hidden_type);
+            match infcx.at(&misc_cause, param_env).eq(opaque_defn.concrete_ty, hidden_type) {
                 Ok(infer_ok) => inh.register_infer_ok_obligations(infer_ok),
                 Err(ty_err) => tcx.sess.delay_span_bug(
-                    opaque_defn.definition_span,
+                    span,
                     &format!(
-                        "could not unify `{}` with revealed type:\n{}",
-                        opaque_defn.concrete_ty, ty_err,
+                        "could not check bounds on revealed type `{}`:\n{}",
+                        hidden_type, ty_err,
                     ),
                 ),
             }
@@ -678,10 +669,17 @@ fn check_opaque_meets_bounds<'tcx>(
             infcx.report_fulfillment_errors(&errors, None, false);
         }
 
-        // Finally, resolve all regions. This catches wily misuses of
-        // lifetime parameters.
-        let fcx = FnCtxt::new(&inh, param_env, hir_id);
-        fcx.regionck_item(hir_id, span, FxHashSet::default());
+        match origin {
+            // Checked when type checking the function containing them.
+            hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
+            // Can have different predicates to their defining use
+            hir::OpaqueTyOrigin::TyAlias => {
+                // Finally, resolve all regions. This catches wily misuses of
+                // lifetime parameters.
+                let fcx = FnCtxt::new(&inh, param_env, hir_id);
+                fcx.regionck_item(hir_id, span, FxHashSet::default());
+            }
+        }
     });
 }
 
@@ -841,14 +839,8 @@ pub(super) fn check_specialization_validity<'tcx>(
     trait_def: &ty::TraitDef,
     trait_item: &ty::AssocItem,
     impl_id: DefId,
-    impl_item: &hir::ImplItem<'_>,
+    impl_item: &hir::ImplItemRef,
 ) {
-    let kind = match impl_item.kind {
-        hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
-        hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
-        hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type,
-    };
-
     let ancestors = match trait_def.ancestors(tcx, impl_id) {
         Ok(ancestors) => ancestors,
         Err(_) => return,
@@ -857,7 +849,7 @@ pub(super) fn check_specialization_validity<'tcx>(
         if parent.is_from_trait() {
             None
         } else {
-            Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id)))
+            Some((parent, parent.item(tcx, trait_item.def_id)))
         }
     });
 
@@ -894,7 +886,7 @@ pub(super) fn check_specialization_validity<'tcx>(
     }
 }
 
-pub(super) fn check_impl_items_against_trait<'tcx>(
+fn check_impl_items_against_trait<'tcx>(
     tcx: TyCtxt<'tcx>,
     full_impl_span: Span,
     impl_id: LocalDefId,
@@ -926,174 +918,82 @@ pub(super) fn check_impl_items_against_trait<'tcx>(
         }
     }
 
-    // Locate trait definition and items
     let trait_def = tcx.trait_def(impl_trait_ref.def_id);
-    let impl_items = impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id));
-    let associated_items = tcx.associated_items(impl_trait_ref.def_id);
-
-    // Check existing impl methods to see if they are both present in trait
-    // and compatible with trait signature
-    for impl_item in impl_items {
-        let ty_impl_item = tcx.associated_item(impl_item.def_id);
-
-        let mut items =
-            associated_items.filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id);
-
-        let (compatible_kind, ty_trait_item) = if let Some(ty_trait_item) = items.next() {
-            let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
-                (ty::AssocKind::Const, hir::ImplItemKind::Const(..)) => true,
-                (ty::AssocKind::Fn, hir::ImplItemKind::Fn(..)) => true,
-                (ty::AssocKind::Type, hir::ImplItemKind::TyAlias(..)) => true,
-                _ => false,
-            };
-
-            // If we don't have a compatible item, we'll use the first one whose name matches
-            // to report an error.
-            let mut compatible_kind = is_compatible(&ty_trait_item);
-            let mut trait_item = ty_trait_item;
-
-            if !compatible_kind {
-                if let Some(ty_trait_item) = items.find(is_compatible) {
-                    compatible_kind = true;
-                    trait_item = ty_trait_item;
-                }
-            }
 
-            (compatible_kind, trait_item)
+    for impl_item in impl_item_refs {
+        let ty_impl_item = tcx.associated_item(impl_item.id.def_id);
+        let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
+            tcx.associated_item(trait_item_id)
         } else {
+            // Checked in `associated_item`.
+            tcx.sess.delay_span_bug(impl_item.span, "missing associated item in trait");
             continue;
         };
-
-        if compatible_kind {
-            match impl_item.kind {
-                hir::ImplItemKind::Const(..) => {
-                    // Find associated const definition.
-                    compare_const_impl(
-                        tcx,
-                        &ty_impl_item,
-                        impl_item.span,
-                        &ty_trait_item,
-                        impl_trait_ref,
-                    );
-                }
-                hir::ImplItemKind::Fn(..) => {
-                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
-                    compare_impl_method(
-                        tcx,
-                        &ty_impl_item,
-                        impl_item.span,
-                        &ty_trait_item,
-                        impl_trait_ref,
-                        opt_trait_span,
-                    );
-                }
-                hir::ImplItemKind::TyAlias(impl_ty) => {
-                    let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
-                    compare_ty_impl(
-                        tcx,
-                        &ty_impl_item,
-                        impl_ty.span,
-                        &ty_trait_item,
-                        impl_trait_ref,
-                        opt_trait_span,
-                    );
-                }
+        let impl_item_full = tcx.hir().impl_item(impl_item.id);
+        match impl_item_full.kind {
+            hir::ImplItemKind::Const(..) => {
+                // Find associated const definition.
+                compare_const_impl(
+                    tcx,
+                    &ty_impl_item,
+                    impl_item.span,
+                    &ty_trait_item,
+                    impl_trait_ref,
+                );
+            }
+            hir::ImplItemKind::Fn(..) => {
+                let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+                compare_impl_method(
+                    tcx,
+                    &ty_impl_item,
+                    impl_item.span,
+                    &ty_trait_item,
+                    impl_trait_ref,
+                    opt_trait_span,
+                );
+            }
+            hir::ImplItemKind::TyAlias(impl_ty) => {
+                let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id);
+                compare_ty_impl(
+                    tcx,
+                    &ty_impl_item,
+                    impl_ty.span,
+                    &ty_trait_item,
+                    impl_trait_ref,
+                    opt_trait_span,
+                );
             }
-
-            check_specialization_validity(
-                tcx,
-                trait_def,
-                &ty_trait_item,
-                impl_id.to_def_id(),
-                impl_item,
-            );
-        } else {
-            report_mismatch_error(
-                tcx,
-                ty_trait_item.def_id,
-                impl_trait_ref,
-                impl_item,
-                &ty_impl_item,
-            );
         }
+
+        check_specialization_validity(
+            tcx,
+            trait_def,
+            &ty_trait_item,
+            impl_id.to_def_id(),
+            impl_item,
+        );
     }
 
     if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
-        let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
-
         // Check for missing items from trait
         let mut missing_items = Vec::new();
-        for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() {
+        for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
             let is_implemented = ancestors
-                .leaf_def(tcx, trait_item.ident, trait_item.kind)
-                .map(|node_item| !node_item.defining_node.is_from_trait())
-                .unwrap_or(false);
+                .leaf_def(tcx, trait_item_id)
+                .map_or(false, |node_item| node_item.item.defaultness.has_value());
 
             if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
-                if !trait_item.defaultness.has_value() {
-                    missing_items.push(*trait_item);
-                }
+                missing_items.push(tcx.associated_item(trait_item_id));
             }
         }
 
         if !missing_items.is_empty() {
+            let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
             missing_items_err(tcx, impl_span, &missing_items, full_impl_span);
         }
     }
 }
 
-#[inline(never)]
-#[cold]
-fn report_mismatch_error<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    trait_item_def_id: DefId,
-    impl_trait_ref: ty::TraitRef<'tcx>,
-    impl_item: &hir::ImplItem<'_>,
-    ty_impl_item: &ty::AssocItem,
-) {
-    let mut err = match impl_item.kind {
-        hir::ImplItemKind::Const(..) => {
-            // Find associated const definition.
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0323,
-                "item `{}` is an associated const, which doesn't match its trait `{}`",
-                ty_impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-
-        hir::ImplItemKind::Fn(..) => {
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0324,
-                "item `{}` is an associated method, which doesn't match its trait `{}`",
-                ty_impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-
-        hir::ImplItemKind::TyAlias(_) => {
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0325,
-                "item `{}` is an associated type, which doesn't match its trait `{}`",
-                ty_impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-    };
-
-    err.span_label(impl_item.span, "does not match trait");
-    if let Some(trait_span) = tcx.hir().span_if_local(trait_item_def_id) {
-        err.span_label(trait_span, "item in trait");
-    }
-    err.emit();
-}
-
 /// Checks whether a type can be represented in memory. In particular, it
 /// identifies types that contain themselves without indirection through a
 /// pointer, which would mean their size is unbounded.
@@ -1271,7 +1171,7 @@ pub(super) fn check_packed_inner(
                 if let ty::Adt(def, _) = field.ty(tcx, substs).kind() {
                     if !stack.contains(&def.did) {
                         if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) {
-                            defs.push((def.did, field.ident.span));
+                            defs.push((def.did, field.ident(tcx).span));
                             return Some(defs);
                         }
                     }
@@ -1408,7 +1308,7 @@ fn check_enum<'tcx>(
             let variant_i = tcx.hir().expect_variant(variant_i_hir_id);
             let i_span = match variant_i.disr_expr {
                 Some(ref expr) => tcx.hir().span(expr.hir_id),
-                None => tcx.hir().span(variant_i_hir_id),
+                None => tcx.def_span(variant_did),
             };
             let span = match v.disr_expr {
                 Some(ref expr) => tcx.hir().span(expr.hir_id),
@@ -1475,7 +1375,7 @@ pub(super) fn check_type_params_are_used<'tcx>(
         return;
     }
 
-    for leaf in ty.walk(tcx) {
+    for leaf in ty.walk() {
         if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
             if let ty::Param(param) = leaf_ty.kind() {
                 debug!("found use of ty param {:?}", param);
@@ -1534,8 +1434,8 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
     let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
 
     let mut label = false;
-    if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) {
-        let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id));
+    if let Some((def_id, visitor)) = get_owner_return_paths(tcx, def_id) {
+        let typeck_results = tcx.typeck(def_id);
         if visitor
             .returns
             .iter()
@@ -1573,10 +1473,6 @@ fn opaque_type_cycle_error(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) {
             {
                 struct OpaqueTypeCollector(Vec<DefId>);
                 impl<'tcx> ty::fold::TypeVisitor<'tcx> for OpaqueTypeCollector {
-                    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-                        // Default anon const substs cannot contain opaque types.
-                        None
-                    }
                     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                         match *t.kind() {
                             ty::Opaque(def, _) => {
index 6192c77d6c648e42da1c2e4cfc121f1a96f6b5dd..3668ecd234c64e1c8b216af4f6d07e653ba8038b 100644 (file)
@@ -1575,7 +1575,7 @@ fn report_return_mismatched_types<'a>(
                     expected,
                     found,
                     can_suggest,
-                    fcx.tcx.hir().get_parent_item(id),
+                    fcx.tcx.hir().local_def_id_to_hir_id(fcx.tcx.hir().get_parent_item(id)),
                 );
             }
             if !pointing_at_return_type {
@@ -1584,13 +1584,19 @@ fn report_return_mismatched_types<'a>(
         }
 
         let parent_id = fcx.tcx.hir().get_parent_item(id);
-        let parent_item = fcx.tcx.hir().get(parent_id);
+        let parent_item = fcx.tcx.hir().get_by_def_id(parent_id);
 
         if let (Some((expr, _)), Some((fn_decl, _, _))) =
             (expression, fcx.get_node_fn_decl(parent_item))
         {
             fcx.suggest_missing_break_or_return_expr(
-                &mut err, expr, fn_decl, expected, found, id, parent_id,
+                &mut err,
+                expr,
+                fn_decl,
+                expected,
+                found,
+                id,
+                fcx.tcx.hir().local_def_id_to_hir_id(parent_id),
             );
         }
 
@@ -1667,10 +1673,10 @@ fn add_impl_trait_explanation<'a>(
                     ],
                     Applicability::MachineApplicable,
                 );
-                let sugg = vec![sp, cause.span]
+                let sugg = [sp, cause.span]
                     .into_iter()
                     .flat_map(|sp| {
-                        vec![
+                        [
                             (sp.shrink_to_lo(), "Box::new(".to_string()),
                             (sp.shrink_to_hi(), ")".to_string()),
                         ]
index c942bafcf034bcc67fb411f533607b770d8047aa..74327affede481e5d7e7b7913d835d42291385c0 100644 (file)
@@ -435,10 +435,18 @@ fn check_region_bounds_on_impl_item<'tcx>(
     if trait_params != impl_params {
         let item_kind = assoc_item_kind_str(impl_m);
         let def_span = tcx.sess.source_map().guess_head_span(span);
-        let span = tcx.hir().get_generics(impl_m.def_id).map_or(def_span, |g| g.span);
+        let span = impl_m
+            .def_id
+            .as_local()
+            .and_then(|did| tcx.hir().get_generics(did))
+            .map_or(def_span, |g| g.span);
         let generics_span = tcx.hir().span_if_local(trait_m.def_id).map(|sp| {
             let def_sp = tcx.sess.source_map().guess_head_span(sp);
-            tcx.hir().get_generics(trait_m.def_id).map_or(def_sp, |g| g.span)
+            trait_m
+                .def_id
+                .as_local()
+                .and_then(|did| tcx.hir().get_generics(did))
+                .map_or(def_sp, |g| g.span)
         });
 
         tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait {
index b7e276b69656f84d397f0c74e6d0f67f618868f8..c351a9f70404a8df1fbf8d595025c5a46bc94738 100644 (file)
@@ -31,9 +31,8 @@ pub fn emit_coerce_suggestions(
         error: TypeError<'tcx>,
     ) {
         self.annotate_expected_due_to_let_ty(err, expr, error);
-        self.suggest_box_deref(err, expr, expected, expr_ty);
-        self.suggest_compatible_variants(err, expr, expected, expr_ty);
         self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr);
+        self.suggest_compatible_variants(err, expr, expected, expr_ty);
         if self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) {
             return;
         }
@@ -259,23 +258,6 @@ fn annotate_expected_due_to_let_ty(
         }
     }
 
-    fn suggest_box_deref(
-        &self,
-        err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
-        expected: Ty<'tcx>,
-        expr_ty: Ty<'tcx>,
-    ) {
-        if expr_ty.is_box() && expr_ty.boxed_ty() == expected {
-            err.span_suggestion_verbose(
-                expr.span.shrink_to_lo(),
-                "try dereferencing the `Box`",
-                "*".to_string(),
-                Applicability::MachineApplicable,
-            );
-        }
-    }
-
     /// If the expected type is an enum (Issue #55250) with any variants whose
     /// sole field is of the found type, suggest such variants. (Issue #42764)
     fn suggest_compatible_variants(
@@ -857,14 +839,17 @@ pub fn check_ref(
                                 Applicability::MachineApplicable,
                                 false,
                             ));
-                        } else if self.infcx.type_is_copy_modulo_regions(
-                            self.param_env,
-                            expected,
-                            sp,
-                        ) {
-                            // For this suggestion to make sense, the type would need to be `Copy`.
+                        }
+
+                        // For this suggestion to make sense, the type would need to be `Copy`,
+                        // or we have to be moving out of a `Box<T>`
+                        if self.infcx.type_is_copy_modulo_regions(self.param_env, expected, sp)
+                            || checked_ty.is_box()
+                        {
                             if let Ok(code) = sm.span_to_snippet(expr.span) {
-                                let message = if checked_ty.is_region_ptr() {
+                                let message = if checked_ty.is_box() {
+                                    "consider unboxing the value"
+                                } else if checked_ty.is_region_ptr() {
                                     "consider dereferencing the borrow"
                                 } else {
                                     "consider dereferencing the type"
index 3cc66aaf0d79c3ec8675a7f8c924f6caada1af9c..c8986aa7f53b04cf456b6e33c638f96723d0938a 100644 (file)
@@ -184,8 +184,6 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
     // absent. So we report an error that the Drop impl injected a
     // predicate that is not present on the struct definition.
 
-    let self_type_hir_id = tcx.hir().local_def_id_to_hir_id(self_type_did);
-
     // We can assume the predicates attached to struct/enum definition
     // hold.
     let generic_assumptions = tcx.predicates_of(self_type_did);
@@ -252,7 +250,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
         };
 
         if !assumptions_in_impl_context.iter().copied().any(predicate_matches_closure) {
-            let item_span = tcx.hir().span(self_type_hir_id);
+            let item_span = tcx.def_span(self_type_did);
             let self_descr = tcx.def_kind(self_type_did).descr(self_type_did.to_def_id());
             struct_span_err!(
                 tcx.sess,
index 8d370e440eaf1fedd55d27844464e66b46481e91..8f9f4e82e845d2b58066c7aa1b101a9154030fd4 100644 (file)
@@ -742,7 +742,7 @@ fn check_expr_return(
                 kind: hir::ImplItemKind::Fn(..),
                 span: encl_fn_span,
                 ..
-            })) = self.tcx.hir().find(encl_item_id)
+            })) = self.tcx.hir().find_by_def_id(encl_item_id)
             {
                 // We are inside a function body, so reporting "return statement
                 // outside of function body" needs an explanation.
@@ -751,7 +751,7 @@ fn check_expr_return(
 
                 // If this didn't hold, we would not have to report an error in
                 // the first place.
-                assert_ne!(encl_item_id, encl_body_owner_id);
+                assert_ne!(hir::HirId::make_owner(encl_item_id), encl_body_owner_id);
 
                 let encl_body_id = self.tcx.hir().body_owned_by(encl_body_owner_id);
                 let encl_body = self.tcx.hir().body(encl_body_id);
@@ -1226,7 +1226,7 @@ fn check_expr_const_block(
         let body = self.tcx.hir().body(anon_const.body);
 
         // Create a new function context.
-        let fcx = FnCtxt::new(self, self.param_env, body.value.hir_id);
+        let fcx = FnCtxt::new(self, self.param_env.with_const(), body.value.hir_id);
         crate::check::GatherLocalsVisitor::new(&fcx).visit_body(body);
 
         let ty = fcx.check_expr_with_expectation(&body.value, expected);
@@ -1238,12 +1238,12 @@ fn check_expr_const_block(
     fn check_expr_repeat(
         &self,
         element: &'tcx hir::Expr<'tcx>,
-        count: &'tcx hir::AnonConst,
+        count: &'tcx hir::ArrayLen,
         expected: Expectation<'tcx>,
         _expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
-        let count = self.to_const(count);
+        let count = self.array_length_to_const(count);
 
         let uty = match expected {
             ExpectHasType(uty) => match *uty.kind() {
@@ -1376,7 +1376,7 @@ fn check_expr_struct_fields(
             .fields
             .iter()
             .enumerate()
-            .map(|(i, field)| (field.ident.normalize_to_macros_2_0(), (i, field)))
+            .map(|(i, field)| (field.ident(tcx).normalize_to_macros_2_0(), (i, field)))
             .collect::<FxHashMap<_, _>>();
 
         let mut seen_fields = FxHashMap::default();
@@ -1457,7 +1457,9 @@ fn check_expr_struct_fields(
                                             expr_span,
                                             self.field_ty(base_expr.span, f, base_subs),
                                         );
-                                        let ident = self.tcx.adjust_ident(f.ident, variant.def_id);
+                                        let ident = self
+                                            .tcx
+                                            .adjust_ident(f.ident(self.tcx), variant.def_id);
                                         if let Some(_) = remaining_fields.remove(&ident) {
                                             let target_ty =
                                                 self.field_ty(base_expr.span, f, substs);
@@ -1475,10 +1477,7 @@ fn check_expr_struct_fields(
                                                         &cause,
                                                         target_ty,
                                                         fru_ty,
-                                                        FieldMisMatch(
-                                                            variant.ident.name,
-                                                            ident.name,
-                                                        ),
+                                                        FieldMisMatch(variant.name, ident.name),
                                                     )
                                                     .emit(),
                                             }
@@ -1665,7 +1664,7 @@ fn report_unknown_field(
                     "{} `{}::{}` has no field named `{}`",
                     kind_name,
                     actual,
-                    variant.ident,
+                    variant.name,
                     field.ident
                 ),
                 _ => struct_span_err!(
@@ -1680,15 +1679,17 @@ fn report_unknown_field(
             },
             ty,
         );
+
+        let variant_ident_span = self.tcx.def_ident_span(variant.def_id).unwrap();
         match variant.ctor_kind {
             CtorKind::Fn => match ty.kind() {
                 ty::Adt(adt, ..) if adt.is_enum() => {
                     err.span_label(
-                        variant.ident.span,
+                        variant_ident_span,
                         format!(
                             "`{adt}::{variant}` defined here",
                             adt = ty,
-                            variant = variant.ident,
+                            variant = variant.name,
                         ),
                     );
                     err.span_label(field.ident.span, "field does not exist");
@@ -1697,18 +1698,18 @@ fn report_unknown_field(
                         &format!(
                             "`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax",
                             adt = ty,
-                            variant = variant.ident,
+                            variant = variant.name,
                         ),
                         format!(
                             "{adt}::{variant}(/* fields */)",
                             adt = ty,
-                            variant = variant.ident,
+                            variant = variant.name,
                         ),
                         Applicability::HasPlaceholders,
                     );
                 }
                 _ => {
-                    err.span_label(variant.ident.span, format!("`{adt}` defined here", adt = ty));
+                    err.span_label(variant_ident_span, format!("`{adt}` defined here", adt = ty));
                     err.span_label(field.ident.span, "field does not exist");
                     err.span_suggestion_verbose(
                         expr_span,
@@ -1740,7 +1741,7 @@ fn report_unknown_field(
                             if adt.is_enum() {
                                 err.span_label(
                                     field.ident.span,
-                                    format!("`{}::{}` does not have this field", ty, variant.ident),
+                                    format!("`{}::{}` does not have this field", ty, variant.name),
                                 );
                             } else {
                                 err.span_label(
@@ -1775,12 +1776,12 @@ fn suggest_field_name(
             .iter()
             .filter_map(|field| {
                 // ignore already set fields and private fields from non-local crates
-                if skip.iter().any(|&x| x == field.ident.name)
+                if skip.iter().any(|&x| x == field.name)
                     || (!variant.def_id.is_local() && !field.vis.is_public())
                 {
                     None
                 } else {
-                    Some(field.ident.name)
+                    Some(field.name)
                 }
             })
             .collect::<Vec<Symbol>>();
@@ -1795,11 +1796,11 @@ fn available_field_names(&self, variant: &'tcx ty::VariantDef) -> Vec<Symbol> {
             .filter(|field| {
                 let def_scope = self
                     .tcx
-                    .adjust_ident_and_get_scope(field.ident, variant.def_id, self.body_id)
+                    .adjust_ident_and_get_scope(field.ident(self.tcx), variant.def_id, self.body_id)
                     .1;
                 field.vis.is_accessible_from(def_scope, self.tcx)
             })
-            .map(|field| field.ident.name)
+            .map(|field| field.name)
             .collect()
     }
 
@@ -1834,8 +1835,9 @@ fn check_field(
                     let (ident, def_scope) =
                         self.tcx.adjust_ident_and_get_scope(field, base_def.did, self.body_id);
                     let fields = &base_def.non_enum_variant().fields;
-                    if let Some(index) =
-                        fields.iter().position(|f| f.ident.normalize_to_macros_2_0() == ident)
+                    if let Some(index) = fields
+                        .iter()
+                        .position(|f| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
                     {
                         let field = &fields[index];
                         let field_ty = self.field_ty(expr.span, field, substs);
@@ -1916,7 +1918,12 @@ fn suggest_await_on_field_access(
         if let ty::Adt(def, _) = output_ty.kind() {
             // no field access on enum type
             if !def.is_enum() {
-                if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident) {
+                if def
+                    .non_enum_variant()
+                    .fields
+                    .iter()
+                    .any(|field| field.ident(self.tcx) == field_ident)
+                {
                     add_label = false;
                     err.span_label(
                         field_ident.span,
@@ -2075,7 +2082,7 @@ fn ban_take_value_of_method(&self, expr: &hir::Expr<'_>, expr_t: Ty<'tcx>, field
                             .unwrap()
                             .fields
                             .iter()
-                            .any(|f| f.ident == field)
+                            .any(|f| f.ident(self.tcx) == field)
                     {
                         if let Some(dot_loc) = expr_snippet.rfind('.') {
                             found = true;
@@ -2262,7 +2269,7 @@ fn check_for_nested_field(
             span, candidate_field, field_path
         );
 
-        if candidate_field.ident == target_field {
+        if candidate_field.ident(self.tcx) == target_field {
             Some(field_path)
         } else if field_path.len() > 3 {
             // For compile-time reasons and to avoid infinite recursion we only check for fields
@@ -2271,11 +2278,11 @@ fn check_for_nested_field(
         } else {
             // recursively search fields of `candidate_field` if it's a ty::Adt
 
-            field_path.push(candidate_field.ident.normalize_to_macros_2_0());
+            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) {
                 for field in nested_fields.iter() {
-                    let ident = field.ident.normalize_to_macros_2_0();
+                    let ident = field.ident(self.tcx).normalize_to_macros_2_0();
                     if ident == target_field {
                         return Some(field_path);
                     } else {
index 67630fd4e582bd24c1084df4ed781f40f082beab..a031f802b6d98aab4c3aa566f0eff178ba6bc549 100644 (file)
@@ -235,7 +235,7 @@ pub fn write_user_type_annotation_from_substs(
     ) {
         debug!("fcx {}", self.tag());
 
-        if self.can_contain_user_lifetime_bounds((substs, user_self_ty)) {
+        if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) {
             let canonicalized = self.infcx.canonicalize_user_type_annotation(UserType::TypeOf(
                 def_id,
                 UserSubsts { substs, user_self_ty },
@@ -489,7 +489,7 @@ pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
         let ty = self.to_ty(ast_ty);
         debug!("to_ty_saving_user_provided_ty: ty={:?}", ty);
 
-        if self.can_contain_user_lifetime_bounds(ty) {
+        if Self::can_contain_user_lifetime_bounds(ty) {
             let c_ty = self.infcx.canonicalize_response(UserType::Ty(ty));
             debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty);
             self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty);
@@ -498,6 +498,13 @@ 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> {
+        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> {
         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);
@@ -534,11 +541,11 @@ pub fn const_arg_to_const(
     // reader, although I have my doubts). Also pass in types with inference
     // types, because they may be repeated. Other sorts of things are already
     // sufficiently enforced with erased regions. =)
-    fn can_contain_user_lifetime_bounds<T>(&self, t: T) -> bool
+    fn can_contain_user_lifetime_bounds<T>(t: T) -> bool
     where
         T: TypeFoldable<'tcx>,
     {
-        t.has_free_regions(self.tcx) || t.has_projections() || t.has_infer_types()
+        t.has_free_regions() || t.has_projections() || t.has_infer_types()
     }
 
     pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> {
index 11b63a99043b705451d9439948c07a90a956ec92..4d88feb65d17d4200f2955d6969009f8b25dcf2c 100644 (file)
@@ -62,7 +62,7 @@ pub(in super::super) fn check_method_argument_types(
                 sp,
                 expr,
                 &err_inputs,
-                &[],
+                vec![],
                 args_no_rcvr,
                 false,
                 tuple_arguments,
@@ -73,7 +73,7 @@ pub(in super::super) fn check_method_argument_types(
 
         let method = method.unwrap();
         // HACK(eddyb) ignore self in the definition (see above).
-        let expected_arg_tys = self.expected_inputs_for_expected_output(
+        let expected_input_tys = self.expected_inputs_for_expected_output(
             sp,
             expected,
             method.sig.output(),
@@ -83,7 +83,7 @@ pub(in super::super) fn check_method_argument_types(
             sp,
             expr,
             &method.sig.inputs()[1..],
-            &expected_arg_tys[..],
+            expected_input_tys,
             args_no_rcvr,
             method.sig.c_variadic,
             tuple_arguments,
@@ -96,34 +96,43 @@ pub(in super::super) fn check_method_argument_types(
     /// method calls and overloaded operators.
     pub(in super::super) fn check_argument_types(
         &self,
-        sp: Span,
-        expr: &'tcx hir::Expr<'tcx>,
-        fn_inputs: &[Ty<'tcx>],
-        expected_arg_tys: &[Ty<'tcx>],
-        args: &'tcx [hir::Expr<'tcx>],
+        // Span enclosing the call site
+        call_span: Span,
+        // Expression of the call site
+        call_expr: &'tcx hir::Expr<'tcx>,
+        // Types (as defined in the *signature* of the target function)
+        formal_input_tys: &[Ty<'tcx>],
+        // More specific expected types, after unifying with caller output types
+        expected_input_tys: Vec<Ty<'tcx>>,
+        // The expressions for each provided argument
+        provided_args: &'tcx [hir::Expr<'tcx>],
+        // Whether the function is variadic, for example when imported from C
         c_variadic: bool,
+        // Whether the arguments have been bundled in a tuple (ex: closures)
         tuple_arguments: TupleArgumentsFlag,
-        def_id: Option<DefId>,
+        // The DefId for the function being called, for better error messages
+        fn_def_id: Option<DefId>,
     ) {
         let tcx = self.tcx;
         // Grab the argument types, supplying fresh type variables
         // if the wrong number of arguments were supplied
-        let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 };
+        let supplied_arg_count =
+            if tuple_arguments == DontTupleArguments { provided_args.len() } else { 1 };
 
         // All the input types from the fn signature must outlive the call
         // so as to validate implied bounds.
-        for (&fn_input_ty, arg_expr) in iter::zip(fn_inputs, args) {
+        for (&fn_input_ty, arg_expr) in iter::zip(formal_input_tys, provided_args) {
             self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
         }
 
-        let expected_arg_count = fn_inputs.len();
+        let expected_arg_count = formal_input_tys.len();
 
         let param_count_error = |expected_count: usize,
                                  arg_count: usize,
                                  error_code: &str,
                                  c_variadic: bool,
                                  sugg_unit: bool| {
-            let (span, start_span, args, ctor_of) = match &expr.kind {
+            let (span, start_span, args, ctor_of) = match &call_expr.kind {
                 hir::ExprKind::Call(
                     hir::Expr {
                         span,
@@ -156,14 +165,14 @@ pub(in super::super) fn check_argument_types(
                     &args[1..], // Skip the receiver.
                     None,       // methods are never ctors
                 ),
-                k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k),
+                k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
             };
-            let arg_spans = if args.is_empty() {
+            let arg_spans = if provided_args.is_empty() {
                 // foo()
                 // ^^^-- supplied 0 arguments
                 // |
                 // expected 2 arguments
-                vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())]
+                vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())]
             } else {
                 // foo(1, 2, 3)
                 // ^^^ -  -  - supplied 3 arguments
@@ -196,7 +205,7 @@ pub(in super::super) fn check_argument_types(
                 );
             }
 
-            if let Some(def_id) = def_id {
+            if let Some(def_id) = fn_def_id {
                 if let Some(def_span) = tcx.def_ident_span(def_id) {
                     let mut spans: MultiSpan = def_span.into();
 
@@ -218,7 +227,7 @@ pub(in super::super) fn check_argument_types(
             }
 
             if sugg_unit {
-                let sugg_span = tcx.sess.source_map().end_point(expr.span);
+                let sugg_span = tcx.sess.source_map().end_point(call_expr.span);
                 // remove closing `)` from the span
                 let sugg_span = sugg_span.shrink_to_lo();
                 err.span_suggestion(
@@ -240,110 +249,148 @@ pub(in super::super) fn check_argument_types(
             err.emit();
         };
 
-        let mut expected_arg_tys = expected_arg_tys.to_vec();
-
-        let formal_tys = if tuple_arguments == TupleArguments {
-            let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]);
+        let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
+            let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]);
             match tuple_type.kind() {
-                ty::Tuple(arg_types) if arg_types.len() != args.len() => {
-                    param_count_error(arg_types.len(), args.len(), "E0057", false, false);
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
+                ty::Tuple(arg_types) if arg_types.len() != provided_args.len() => {
+                    param_count_error(arg_types.len(), provided_args.len(), "E0057", false, false);
+                    (self.err_args(provided_args.len()), vec![])
                 }
                 ty::Tuple(arg_types) => {
-                    expected_arg_tys = match expected_arg_tys.get(0) {
+                    let expected_input_tys = match expected_input_tys.get(0) {
                         Some(&ty) => match ty.kind() {
                             ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
                             _ => vec![],
                         },
                         None => vec![],
                     };
-                    arg_types.iter().map(|k| k.expect_ty()).collect()
+                    (arg_types.iter().map(|k| k.expect_ty()).collect(), expected_input_tys)
                 }
                 _ => {
                     struct_span_err!(
                         tcx.sess,
-                        sp,
+                        call_span,
                         E0059,
                         "cannot use call notation; the first type parameter \
                          for the function trait is neither a tuple nor unit"
                     )
                     .emit();
-                    expected_arg_tys = vec![];
-                    self.err_args(args.len())
+                    (self.err_args(provided_args.len()), vec![])
                 }
             }
         } else if expected_arg_count == supplied_arg_count {
-            fn_inputs.to_vec()
+            (formal_input_tys.to_vec(), expected_input_tys)
         } else if c_variadic {
             if supplied_arg_count >= expected_arg_count {
-                fn_inputs.to_vec()
+                (formal_input_tys.to_vec(), expected_input_tys)
             } else {
                 param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
-                expected_arg_tys = vec![];
-                self.err_args(supplied_arg_count)
+                (self.err_args(supplied_arg_count), vec![])
             }
         } else {
             // is the missing argument of type `()`?
-            let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(expected_arg_tys[0]).is_unit()
-            } else if fn_inputs.len() == 1 && supplied_arg_count == 0 {
-                self.resolve_vars_if_possible(fn_inputs[0]).is_unit()
+            let sugg_unit = if expected_input_tys.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(expected_input_tys[0]).is_unit()
+            } else if formal_input_tys.len() == 1 && supplied_arg_count == 0 {
+                self.resolve_vars_if_possible(formal_input_tys[0]).is_unit()
             } else {
                 false
             };
             param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
 
-            expected_arg_tys = vec![];
-            self.err_args(supplied_arg_count)
+            (self.err_args(supplied_arg_count), vec![])
         };
 
         debug!(
-            "check_argument_types: formal_tys={:?}",
-            formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
+            "check_argument_types: formal_input_tys={:?}",
+            formal_input_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>()
         );
 
-        // If there is no expectation, expect formal_tys.
-        let expected_arg_tys =
-            if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() };
+        // If there is no expectation, expect formal_input_tys.
+        let expected_input_tys = if !expected_input_tys.is_empty() {
+            expected_input_tys
+        } else {
+            formal_input_tys.clone()
+        };
+
+        assert_eq!(expected_input_tys.len(), formal_input_tys.len());
 
+        // Keep track of the fully coerced argument types
         let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
 
+        // We introduce a helper function to demand that a given argument satisfy a given input
+        // This is more complicated than just checking type equality, as arguments could be coerced
+        // This version writes those types back so further type checking uses the narrowed types
+        let demand_compatible = |idx, final_arg_types: &mut Vec<(usize, Ty<'tcx>, Ty<'tcx>)>| {
+            let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
+            let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
+            let provided_arg = &provided_args[idx];
+
+            debug!("checking argument {}: {:?} = {:?}", idx, provided_arg, formal_input_ty);
+
+            // The special-cased logic below has three functions:
+            // 1. Provide as good of an expected type as possible.
+            let expectation = Expectation::rvalue_hint(self, expected_input_ty);
+
+            let checked_ty = self.check_expr_with_expectation(provided_arg, expectation);
+
+            // 2. Coerce to the most detailed type that could be coerced
+            //    to, which is `expected_ty` if `rvalue_hint` returns an
+            //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
+            let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
+
+            // Keep track of these for below
+            final_arg_types.push((idx, checked_ty, coerced_ty));
+
+            // Cause selection errors caused by resolving a single argument to point at the
+            // argument and not the call. This is otherwise redundant with the `demand_coerce`
+            // call immediately after, but it lets us customize the span pointed to in the
+            // fulfillment error to be more accurate.
+            let _ =
+                self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| {
+                    self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
+                    self.point_at_arg_instead_of_call_if_possible(
+                        errors,
+                        &final_arg_types,
+                        call_expr,
+                        call_span,
+                        provided_args,
+                    );
+                });
+
+            // We're processing function arguments so we definitely want to use
+            // two-phase borrows.
+            self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes);
+
+            // 3. Relate the expected type and the formal one,
+            //    if the expected type was used for the coercion.
+            self.demand_suptype(provided_arg.span, formal_input_ty, coerced_ty);
+        };
+
         // Check the arguments.
         // We do this in a pretty awful way: first we type-check any arguments
         // that are not closures, then we type-check the closures. This is so
         // that we have more information about the types of arguments when we
         // type-check the functions. This isn't really the right way to do this.
         for check_closures in [false, true] {
-            debug!("check_closures={}", check_closures);
-
             // More awful hacks: before we check argument types, try to do
             // an "opportunistic" trait resolution of any trait bounds on
             // the call. This helps coercions.
             if check_closures {
                 self.select_obligations_where_possible(false, |errors| {
-                    self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
+                    self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
                     self.point_at_arg_instead_of_call_if_possible(
                         errors,
                         &final_arg_types,
-                        expr,
-                        sp,
-                        &args,
+                        call_expr,
+                        call_span,
+                        &provided_args,
                     );
                 })
             }
 
-            // For C-variadic functions, we don't have a declared type for all of
-            // the arguments hence we only do our usual type checking with
-            // the arguments who's types we do know.
-            let t = if c_variadic {
-                expected_arg_count
-            } else if tuple_arguments == TupleArguments {
-                args.len()
-            } else {
-                supplied_arg_count
-            };
-            for (i, arg) in args.iter().take(t).enumerate() {
+            let minimum_input_count = formal_input_tys.len();
+            for (idx, arg) in provided_args.iter().enumerate() {
                 // Warn only for the first loop (the "no closures" one).
                 // Closure arguments themselves can't be diverging, but
                 // a previous argument can, e.g., `foo(panic!(), || {})`.
@@ -351,53 +398,21 @@ pub(in super::super) fn check_argument_types(
                     self.warn_if_unreachable(arg.hir_id, arg.span, "expression");
                 }
 
-                let is_closure = matches!(arg.kind, ExprKind::Closure(..));
+                // For C-variadic functions, we don't have a declared type for all of
+                // the arguments hence we only do our usual type checking with
+                // the arguments who's types we do know. However, we *can* check
+                // for unreachable expressions (see above).
+                // FIXME: unreachable warning current isn't emitted
+                if idx >= minimum_input_count {
+                    continue;
+                }
 
+                let is_closure = matches!(arg.kind, ExprKind::Closure(..));
                 if is_closure != check_closures {
                     continue;
                 }
 
-                let formal_ty = formal_tys[i];
-                debug!("checking argument {}: {:?} = {:?}", i, arg, formal_ty);
-
-                // The special-cased logic below has three functions:
-                // 1. Provide as good of an expected type as possible.
-                let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]);
-
-                let checked_ty = self.check_expr_with_expectation(&arg, expected);
-
-                // 2. Coerce to the most detailed type that could be coerced
-                //    to, which is `expected_ty` if `rvalue_hint` returns an
-                //    `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise.
-                let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty);
-
-                final_arg_types.push((i, checked_ty, coerce_ty));
-
-                // Cause selection errors caused by resolving a single argument to point at the
-                // argument and not the call. This is otherwise redundant with the `demand_coerce`
-                // call immediately after, but it lets us customize the span pointed to in the
-                // fulfillment error to be more accurate.
-                let _ = self.resolve_vars_with_obligations_and_mutate_fulfillment(
-                    coerce_ty,
-                    |errors| {
-                        self.point_at_type_arg_instead_of_call_if_possible(errors, expr);
-                        self.point_at_arg_instead_of_call_if_possible(
-                            errors,
-                            &final_arg_types,
-                            expr,
-                            sp,
-                            args,
-                        );
-                    },
-                );
-
-                // We're processing function arguments so we definitely want to use
-                // two-phase borrows.
-                self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes);
-
-                // 3. Relate the expected type and the formal one,
-                //    if the expected type was used for the coercion.
-                self.demand_suptype(arg.span, formal_ty, coerce_ty);
+                demand_compatible(idx, &mut final_arg_types);
             }
         }
 
@@ -410,7 +425,7 @@ fn variadic_error<'tcx>(sess: &Session, span: Span, ty: Ty<'tcx>, cast_ty: &str)
                 MissingCastForVariadicArg { sess, span, ty, cast_ty }.diagnostic().emit()
             }
 
-            for arg in args.iter().skip(expected_arg_count) {
+            for arg in provided_args.iter().skip(expected_arg_count) {
                 let arg_ty = self.check_expr(&arg);
 
                 // There are a few types which get autopromoted when passed via varargs
@@ -831,7 +846,7 @@ fn consider_hint_about_removing_semicolon(
     }
 
     fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
-        let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id));
+        let node = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(id));
         match node {
             Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. })
             | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => {
@@ -847,7 +862,7 @@ fn parent_item_span(&self, id: hir::HirId) -> Option<Span> {
 
     /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
     fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
-        let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id));
+        let parent = self.tcx.hir().get_by_def_id(self.tcx.hir().get_parent_item(blk_id));
         self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident))
     }
 
@@ -1021,7 +1036,7 @@ fn unpeel_to_top(
                     let ty = self.resolve_vars_if_possible(ty);
                     // We walk the argument type because the argument's type could have
                     // been `Option<T>`, but the `FulfillmentError` references `T`.
-                    if ty.walk(self.tcx).any(|arg| arg == self_) { Some(i) } else { None }
+                    if ty.walk().any(|arg| arg == self_) { Some(i) } else { None }
                 })
                 .collect::<Vec<usize>>();
 
index 9c70d2cb365b2714ff563cca9402aa7ff2c7b44d..3a81af03162862f8c8d99024fd92681fd8cb7acb 100644 (file)
@@ -188,8 +188,7 @@ fn get_type_parameter_bounds(
     ) -> ty::GenericPredicates<'tcx> {
         let tcx = self.tcx;
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-        let item_id = tcx.hir().ty_param_owner(hir_id);
-        let item_def_id = tcx.hir().local_def_id(item_id);
+        let item_def_id = tcx.hir().ty_param_owner(hir_id);
         let generics = tcx.generics_of(item_def_id);
         let index = generics.param_def_id_to_index[&def_id];
         ty::GenericPredicates {
index 6c7d3a0c9c0bb1af96ea9e805b5d57b88ab2ea09..e8a0cc946b5e118d1ceba3bb1cd20f3c44953a7f 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_hir::def::{CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Expr, ExprKind, ItemKind, Node, Path, QPath, Stmt, StmtKind, TyKind};
-use rustc_infer::infer;
+use rustc_infer::infer::{self, TyCtxtInferExt};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, Binder, Ty};
 use rustc_span::symbol::{kw, sym};
@@ -608,6 +608,17 @@ pub(in super::super) fn suggest_missing_break_or_return_expr(
             let bound_vars = self.tcx.late_bound_vars(fn_id);
             let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
             let ty = self.normalize_associated_types_in(expr.span, ty);
+            let ty = match self.tcx.asyncness(fn_id.owner) {
+                hir::IsAsync::Async => self.tcx.infer_ctxt().enter(|infcx| {
+                    infcx.get_impl_future_output_ty(ty).unwrap_or_else(|| {
+                        span_bug!(
+                            fn_decl.output.span(),
+                            "failed to get output type of async function"
+                        )
+                    })
+                }),
+                hir::IsAsync::NotAsync => ty,
+            };
             if self.can_coerce(found, ty) {
                 err.multipart_suggestion(
                     "you might have meant to return this value",
index f7f4c52c2a1d3cf1afe3eaf95e2941fa5b75c167..d2dc21d84f6f112e125f90b301b7e803508c4934 100644 (file)
@@ -359,6 +359,8 @@ pub(super) fn lookup_method_in_trait(
         let (obligation, substs) =
             self.obligation_for_method(span, trait_def_id, self_ty, opt_input_types);
 
+        debug!(?obligation);
+
         // Now we want to know if this can be matched
         if !self.predicate_may_hold(&obligation) {
             debug!("--> Cannot match obligation");
@@ -369,7 +371,7 @@ pub(super) fn lookup_method_in_trait(
         // Trait must have a method named `m_name` and it should not have
         // type parameters or early-bound regions.
         let tcx = self.tcx;
-        let method_item = match self.associated_item(trait_def_id, m_name, Namespace::ValueNS) {
+        let method_item = match self.associated_value(trait_def_id, m_name) {
             Some(method_item) => method_item,
             None => {
                 tcx.sess.delay_span_bug(
@@ -482,7 +484,7 @@ pub fn resolve_fully_qualified_call(
                 let variant_def = adt_def
                     .variants
                     .iter()
-                    .find(|vd| tcx.hygienic_eq(method_name, vd.ident, adt_def.did));
+                    .find(|vd| tcx.hygienic_eq(method_name, vd.ident(tcx), adt_def.did));
                 if let Some(variant_def) = variant_def {
                     // Braced variants generate unusable names in value namespace (reserved for
                     // possible future use), so variants resolved as associated items may refer to
@@ -538,15 +540,10 @@ pub fn resolve_fully_qualified_call(
 
     /// Finds item with name `item_name` defined in impl/trait `def_id`
     /// and return it, or `None`, if no such item was defined there.
-    pub fn associated_item(
-        &self,
-        def_id: DefId,
-        item_name: Ident,
-        ns: Namespace,
-    ) -> Option<ty::AssocItem> {
+    pub fn associated_value(&self, def_id: DefId, item_name: Ident) -> Option<ty::AssocItem> {
         self.tcx
             .associated_items(def_id)
-            .find_by_name_and_namespace(self.tcx, item_name, ns, def_id)
+            .find_by_name_and_namespace(self.tcx, item_name, Namespace::ValueNS, def_id)
             .copied()
     }
 }
index 5615a08369dffc9af3c4921be94303065b6e3e3a..b704ff8c7cb2a2546dfa35918602589e5850cd6b 100644 (file)
@@ -1915,7 +1915,7 @@ fn erase_late_bound_regions<T>(&self, value: ty::Binder<'tcx, T>) -> T
                     .collect()
             } else {
                 self.fcx
-                    .associated_item(def_id, name, Namespace::ValueNS)
+                    .associated_value(def_id, name)
                     .map_or_else(SmallVec::new, |x| SmallVec::from_buf([x]))
             }
         } else {
index 7f9c75c7fee642933ab1a5a5ada5c40387dcc710..f2fe4403d558ccab3d6284e93b65e97bd3f12465 100644 (file)
@@ -5,7 +5,6 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
-use rustc_hir::def::Namespace;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, Node, QPath};
@@ -15,7 +14,7 @@
 use rustc_middle::ty::{self, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable};
 use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
-use rustc_span::{source_map, FileName, MultiSpan, Span, Symbol};
+use rustc_span::{source_map, FileName, MultiSpan, Span};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::{
     FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
@@ -99,16 +98,10 @@ pub fn report_method_error(
                     CandidateSource::ImplSource(impl_did) => {
                         // Provide the best span we can. Use the item, if local to crate, else
                         // the impl, if local to crate (item may be defaulted), else nothing.
-                        let item = match self
-                            .associated_item(impl_did, item_name, Namespace::ValueNS)
-                            .or_else(|| {
-                                let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
-                                self.associated_item(
-                                    impl_trait_ref.def_id,
-                                    item_name,
-                                    Namespace::ValueNS,
-                                )
-                            }) {
+                        let item = match self.associated_value(impl_did, item_name).or_else(|| {
+                            let impl_trait_ref = self.tcx.impl_trait_ref(impl_did)?;
+                            self.associated_value(impl_trait_ref.def_id, item_name)
+                        }) {
                             Some(item) => item,
                             None => continue,
                         };
@@ -187,11 +180,10 @@ pub fn report_method_error(
                         }
                     }
                     CandidateSource::TraitSource(trait_did) => {
-                        let item =
-                            match self.associated_item(trait_did, item_name, Namespace::ValueNS) {
-                                Some(item) => item,
-                                None => continue,
-                            };
+                        let item = match self.associated_value(trait_did, item_name) {
+                            Some(item) => item,
+                            None => continue,
+                        };
                         let item_span = self
                             .tcx
                             .sess
@@ -271,16 +263,14 @@ pub fn report_method_error(
                     // Suggest clamping down the type if the method that is being attempted to
                     // be used exists at all, and the type is an ambiguous numeric type
                     // ({integer}/{float}).
-                    let mut candidates = all_traits(self.tcx).into_iter().filter_map(|info| {
-                        self.associated_item(info.def_id, item_name, Namespace::ValueNS)
-                    });
+                    let mut candidates = all_traits(self.tcx)
+                        .into_iter()
+                        .filter_map(|info| self.associated_value(info.def_id, item_name));
                     // There are methods that are defined on the primitive types and won't be
                     // found when exploring `all_traits`, but we also need them to be acurate on
                     // our suggestions (#47759).
                     let fund_assoc = |opt_def_id: Option<DefId>| {
-                        opt_def_id
-                            .and_then(|id| self.associated_item(id, item_name, Namespace::ValueNS))
-                            .is_some()
+                        opt_def_id.and_then(|id| self.associated_value(id, item_name)).is_some()
                     };
                     let lang_items = tcx.lang_items();
                     let found_candidate = candidates.next().is_some()
@@ -398,11 +388,7 @@ pub fn report_method_error(
                                             .inherent_impls(adt_deref.did)
                                             .iter()
                                             .filter_map(|def_id| {
-                                                self.associated_item(
-                                                    *def_id,
-                                                    item_name,
-                                                    Namespace::ValueNS,
-                                                )
+                                                self.associated_value(*def_id, item_name)
                                             })
                                             .count()
                                             >= 1
@@ -515,9 +501,7 @@ pub fn report_method_error(
                                 .iter()
                                 .copied()
                                 .filter(|def_id| {
-                                    if let Some(assoc) =
-                                        self.associated_item(*def_id, item_name, Namespace::ValueNS)
-                                    {
+                                    if let Some(assoc) = self.associated_value(*def_id, item_name) {
                                         // Check for both mode is the same so we avoid suggesting
                                         // incorrect associated item.
                                         match (mode, assoc.fn_has_self_parameter, source) {
@@ -997,7 +981,7 @@ trait bound{s}",
                 if unsatisfied_predicates.is_empty() && actual.is_enum() {
                     let adt_def = actual.ty_adt_def().expect("enum is not an ADT");
                     if let Some(suggestion) = lev_distance::find_best_match_for_name(
-                        &adt_def.variants.iter().map(|s| s.ident.name).collect::<Vec<_>>(),
+                        &adt_def.variants.iter().map(|s| s.name).collect::<Vec<_>>(),
                         item_name.name,
                         None,
                     ) {
@@ -1321,7 +1305,7 @@ fn suggest_use_candidates(
                 if Some(*parent_did) != self.tcx.parent(*trait_did)
                     && self
                         .tcx
-                        .item_children(*parent_did)
+                        .module_children(*parent_did)
                         .iter()
                         .filter(|child| child.res.opt_def_id() == Some(*trait_did))
                         .all(|child| child.ident.name == kw::Underscore)
@@ -1524,8 +1508,7 @@ fn suggest_traits_to_import(
                             // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not
                             // implement the `AsRef` trait.
                             let skip = skippable.contains(&did)
-                                || (("Pin::new" == *pre)
-                                    && (Symbol::intern("as_ref") == item_name.name));
+                                || (("Pin::new" == *pre) && (sym::as_ref == item_name.name));
                             // Make sure the method is defined for the *actual* receiver: we don't
                             // want to treat `Box<Self>` as a receiver if it only works because of
                             // an autoderef to `&self`
@@ -1588,7 +1571,7 @@ fn suggest_traits_to_import(
                     }
                 }) && (type_is_local || info.def_id.is_local())
                     && self
-                        .associated_item(info.def_id, item_name, Namespace::ValueNS)
+                        .associated_value(info.def_id, item_name)
                         .filter(|item| {
                             if let ty::AssocKind::Fn = item.kind {
                                 let id = item
index a9e6b1caff07b03d55d67d979c52368b1031fd6a..719266ad5a4355b9ff70add27239001e09b93fea 100644 (file)
@@ -511,19 +511,15 @@ struct GeneratorTypes<'tcx> {
 fn get_owner_return_paths<'tcx>(
     tcx: TyCtxt<'tcx>,
     def_id: LocalDefId,
-) -> Option<(hir::HirId, ReturnsVisitor<'tcx>)> {
+) -> Option<(LocalDefId, ReturnsVisitor<'tcx>)> {
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-    let id = tcx.hir().get_parent_item(hir_id);
-    tcx.hir()
-        .find(id)
-        .map(|n| (id, n))
-        .and_then(|(hir_id, node)| node.body_id().map(|b| (hir_id, b)))
-        .map(|(hir_id, body_id)| {
-            let body = tcx.hir().body(body_id);
-            let mut visitor = ReturnsVisitor::default();
-            visitor.visit_body(body);
-            (hir_id, visitor)
-        })
+    let parent_id = tcx.hir().get_parent_item(hir_id);
+    tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| {
+        let body = tcx.hir().body(body_id);
+        let mut visitor = ReturnsVisitor::default();
+        visitor.visit_body(body);
+        (parent_id, visitor)
+    })
 }
 
 // Forbid defining intrinsics in Rust code,
@@ -566,7 +562,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: S
 
 fn report_forbidden_specialization(
     tcx: TyCtxt<'_>,
-    impl_item: &hir::ImplItem<'_>,
+    impl_item: &hir::ImplItemRef,
     parent_impl: DefId,
 ) {
     let mut err = struct_span_err!(
@@ -598,7 +594,7 @@ fn report_forbidden_specialization(
 fn missing_items_err(
     tcx: TyCtxt<'_>,
     impl_span: Span,
-    missing_items: &[ty::AssocItem],
+    missing_items: &[&ty::AssocItem],
     full_impl_span: Span,
 ) {
     let missing_items_msg = missing_items
index 8ebfcdd539b67382d883710ab5c40bf25137309b..c20c457de85c8796f6429c20ef6d365a474cb249 100644 (file)
@@ -423,7 +423,7 @@ fn check_overloaded_binop(
                     }
                 }
                 if let Some(missing_trait) = missing_trait {
-                    let mut visitor = TypeParamVisitor(self.tcx, vec![]);
+                    let mut visitor = TypeParamVisitor(vec![]);
                     visitor.visit_ty(lhs_ty);
 
                     if op.node == hir::BinOpKind::Add
@@ -434,7 +434,7 @@ fn check_overloaded_binop(
                         // This has nothing here because it means we did string
                         // concatenation (e.g., "Hello " + "World!"). This means
                         // we don't want the note in the else clause to be emitted
-                    } else if let [ty] = &visitor.1[..] {
+                    } else if let [ty] = &visitor.0[..] {
                         if let ty::Param(p) = *ty.kind() {
                             // Check if the method would be found if the type param wasn't
                             // involved. If so, it means that adding a trait bound to the param is
@@ -972,7 +972,7 @@ fn suggest_constraining_param(
     if let Some(generics) = param_def_id
         .as_local()
         .map(|id| hir.local_def_id_to_hir_id(id))
-        .and_then(|id| hir.find(hir.get_parent_item(id)))
+        .and_then(|id| hir.find_by_def_id(hir.get_parent_item(id)))
         .as_ref()
         .and_then(|node| node.generics())
     {
@@ -991,15 +991,12 @@ fn suggest_constraining_param(
     }
 }
 
-struct TypeParamVisitor<'tcx>(TyCtxt<'tcx>, Vec<Ty<'tcx>>);
+struct TypeParamVisitor<'tcx>(Vec<Ty<'tcx>>);
 
 impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.0)
-    }
     fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         if let ty::Param(_) = ty.kind() {
-            self.1.push(ty);
+            self.0.push(ty);
         }
         ty.super_visit_with(self)
     }
index ec06e0b11264d9683f31b944520f7dad3419b202..17b97d4cad1d4ba7c23af88cd4a9784001ca170e 100644 (file)
@@ -1029,7 +1029,7 @@ fn e0023(
         let field_def_spans = if fields.is_empty() {
             vec![res_span]
         } else {
-            fields.iter().map(|f| f.ident.span).collect()
+            fields.iter().map(|f| f.ident(self.tcx).span).collect()
         };
         let last_field_def_span = *field_def_spans.last().unwrap();
 
@@ -1231,7 +1231,7 @@ fn check_struct_pat_fields(
             .fields
             .iter()
             .enumerate()
-            .map(|(i, field)| (field.ident.normalize_to_macros_2_0(), (i, field)))
+            .map(|(i, field)| (field.ident(self.tcx).normalize_to_macros_2_0(), (i, field)))
             .collect::<FxHashMap<_, _>>();
 
         // Keep track of which fields have already appeared in the pattern.
@@ -1272,7 +1272,7 @@ fn check_struct_pat_fields(
         let mut unmentioned_fields = variant
             .fields
             .iter()
-            .map(|field| (field, field.ident.normalize_to_macros_2_0()))
+            .map(|field| (field, field.ident(self.tcx).normalize_to_macros_2_0()))
             .filter(|(_, ident)| !used_fields.contains_key(ident))
             .collect::<Vec<_>>();
 
@@ -1579,7 +1579,8 @@ fn get_suggested_tuple_struct_pattern(
         fields: &[hir::PatField<'_>],
         variant: &VariantDef,
     ) -> String {
-        let variant_field_idents = variant.fields.iter().map(|f| f.ident).collect::<Vec<Ident>>();
+        let variant_field_idents =
+            variant.fields.iter().map(|f| f.ident(self.tcx)).collect::<Vec<Ident>>();
         fields
             .iter()
             .map(|field| {
index 1b42edc83be20d18c07a4d59e12daa896ba565d3..0c2f40733505d6a74379384fbc6fff1e855d284e 100644 (file)
@@ -859,15 +859,15 @@ fn link_upvar_region(
                     self.sub_regions(
                         infer::ReborrowUpvar(span, upvar_id),
                         borrow_region,
-                        upvar_borrow.region,
+                        captured_place.region.unwrap(),
                     );
-                    if let ty::ImmBorrow = upvar_borrow.kind {
+                    if let ty::ImmBorrow = upvar_borrow {
                         debug!("link_upvar_region: capture by shared ref");
                     } else {
                         all_captures_are_imm_borrow = false;
                     }
                 }
-                ty::UpvarCapture::ByValue(_) => {
+                ty::UpvarCapture::ByValue => {
                     all_captures_are_imm_borrow = false;
                 }
             }
index ffd7d29bbbbeedb9eb52986d8cbfde4910c59653..8d3c70b05734fe7be65cb4b90e49ac305d940883 100644 (file)
@@ -33,7 +33,6 @@
 use super::FnCtxt;
 
 use crate::expr_use_visitor as euv;
-use rustc_data_structures::fx::FxIndexMap;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -72,7 +71,7 @@ enum PlaceAncestryRelation {
 /// Intermediate format to store a captured `Place` and associated `ty::CaptureInfo`
 /// during capture analysis. Information in this map feeds into the minimum capture
 /// analysis pass.
-type InferredCaptureInformation<'tcx> = FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>;
+type InferredCaptureInformation<'tcx> = Vec<(Place<'tcx>, ty::CaptureInfo)>;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) {
@@ -207,8 +206,7 @@ fn analyze_closure(
         assert_eq!(body_owner_def_id.to_def_id(), closure_def_id);
         let mut delegate = InferBorrowKind {
             fcx: self,
-            closure_def_id,
-            closure_span: span,
+            closure_def_id: local_def_id,
             capture_information: Default::default(),
             fake_reads: Default::default(),
         };
@@ -231,7 +229,7 @@ fn analyze_closure(
         let (capture_information, closure_kind, origin) = self
             .process_collected_capture_information(capture_clause, delegate.capture_information);
 
-        self.compute_min_captures(closure_def_id, capture_information);
+        self.compute_min_captures(closure_def_id, capture_information, span);
 
         let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
 
@@ -252,21 +250,19 @@ fn analyze_closure(
 
                     debug!("seed place {:?}", place);
 
-                    let upvar_id = ty::UpvarId::new(*var_hir_id, local_def_id);
-                    let capture_kind =
-                        self.init_capture_kind_for_place(&place, capture_clause, upvar_id, span);
+                    let capture_kind = self.init_capture_kind_for_place(&place, capture_clause);
                     let fake_info = ty::CaptureInfo {
                         capture_kind_expr_id: None,
                         path_expr_id: None,
                         capture_kind,
                     };
 
-                    capture_information.insert(place, fake_info);
+                    capture_information.push((place, fake_info));
                 }
             }
 
             // This will update the min captures based on this new fake information.
-            self.compute_min_captures(closure_def_id, capture_information);
+            self.compute_min_captures(closure_def_id, capture_information, span);
         }
 
         let before_feature_tys = self.final_upvar_tys(closure_def_id);
@@ -362,7 +358,7 @@ fn final_upvar_tys(&self, closure_id: DefId) -> Vec<Ty<'tcx>> {
                     captured_place.place, upvar_ty, capture, captured_place.mutability,
                 );
 
-                apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture)
+                apply_capture_kind_on_capture_ty(self.tcx, upvar_ty, capture, captured_place.region)
             })
             .collect()
     }
@@ -387,77 +383,68 @@ fn process_collected_capture_information(
         capture_clause: hir::CaptureBy,
         capture_information: InferredCaptureInformation<'tcx>,
     ) -> (InferredCaptureInformation<'tcx>, ty::ClosureKind, Option<(Span, Place<'tcx>)>) {
-        let mut processed: InferredCaptureInformation<'tcx> = Default::default();
-
         let mut closure_kind = ty::ClosureKind::LATTICE_BOTTOM;
         let mut origin: Option<(Span, Place<'tcx>)> = None;
 
-        for (place, mut capture_info) in capture_information {
-            // Apply rules for safety before inferring closure kind
-            let (place, capture_kind) =
-                restrict_capture_precision(place, capture_info.capture_kind);
-            capture_info.capture_kind = capture_kind;
+        let processed = capture_information
+            .into_iter()
+            .map(|(place, mut capture_info)| {
+                // Apply rules for safety before inferring closure kind
+                let (place, capture_kind) =
+                    restrict_capture_precision(place, capture_info.capture_kind);
 
-            let (place, capture_kind) =
-                truncate_capture_for_optimization(place, capture_info.capture_kind);
-            capture_info.capture_kind = capture_kind;
+                let (place, capture_kind) = truncate_capture_for_optimization(place, capture_kind);
 
-            let usage_span = if let Some(usage_expr) = capture_info.path_expr_id {
-                self.tcx.hir().span(usage_expr)
-            } else {
-                unreachable!()
-            };
+                let usage_span = if let Some(usage_expr) = capture_info.path_expr_id {
+                    self.tcx.hir().span(usage_expr)
+                } else {
+                    unreachable!()
+                };
 
-            let updated = match capture_info.capture_kind {
-                ty::UpvarCapture::ByValue(..) => match closure_kind {
-                    ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
-                        (ty::ClosureKind::FnOnce, Some((usage_span, place.clone())))
-                    }
-                    // If closure is already FnOnce, don't update
-                    ty::ClosureKind::FnOnce => (closure_kind, origin),
-                },
+                let updated = match capture_kind {
+                    ty::UpvarCapture::ByValue => match closure_kind {
+                        ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
+                            (ty::ClosureKind::FnOnce, Some((usage_span, place.clone())))
+                        }
+                        // If closure is already FnOnce, don't update
+                        ty::ClosureKind::FnOnce => (closure_kind, origin.take()),
+                    },
 
-                ty::UpvarCapture::ByRef(ty::UpvarBorrow {
-                    kind: ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
-                    ..
-                }) => {
-                    match closure_kind {
-                        ty::ClosureKind::Fn => {
-                            (ty::ClosureKind::FnMut, Some((usage_span, place.clone())))
+                    ty::UpvarCapture::ByRef(
+                        ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
+                    ) => {
+                        match closure_kind {
+                            ty::ClosureKind::Fn => {
+                                (ty::ClosureKind::FnMut, Some((usage_span, place.clone())))
+                            }
+                            // Don't update the origin
+                            ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce => {
+                                (closure_kind, origin.take())
+                            }
                         }
-                        // Don't update the origin
-                        ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce => (closure_kind, origin),
                     }
-                }
 
-                _ => (closure_kind, origin),
-            };
-
-            closure_kind = updated.0;
-            origin = updated.1;
+                    _ => (closure_kind, origin.take()),
+                };
 
-            let (place, capture_kind) = match capture_clause {
-                hir::CaptureBy::Value => adjust_for_move_closure(place, capture_info.capture_kind),
-                hir::CaptureBy::Ref => {
-                    adjust_for_non_move_closure(place, capture_info.capture_kind)
-                }
-            };
+                closure_kind = updated.0;
+                origin = updated.1;
 
-            // This restriction needs to be applied after we have handled adjustments for `move`
-            // closures. We want to make sure any adjustment that might make us move the place into
-            // the closure gets handled.
-            let (place, capture_kind) =
-                restrict_precision_for_drop_types(self, place, capture_kind, usage_span);
+                let (place, capture_kind) = match capture_clause {
+                    hir::CaptureBy::Value => adjust_for_move_closure(place, capture_kind),
+                    hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
+                };
 
-            capture_info.capture_kind = capture_kind;
+                // This restriction needs to be applied after we have handled adjustments for `move`
+                // closures. We want to make sure any adjustment that might make us move the place into
+                // the closure gets handled.
+                let (place, capture_kind) =
+                    restrict_precision_for_drop_types(self, place, capture_kind, usage_span);
 
-            let capture_info = if let Some(existing) = processed.get(&place) {
-                determine_capture_info(*existing, capture_info)
-            } else {
-                capture_info
-            };
-            processed.insert(place, capture_info);
-        }
+                capture_info.capture_kind = capture_kind;
+                (place, capture_info)
+            })
+            .collect();
 
         (processed, closure_kind, origin)
     }
@@ -535,6 +522,7 @@ fn compute_min_captures(
         &self,
         closure_def_id: DefId,
         capture_information: InferredCaptureInformation<'tcx>,
+        closure_span: Span,
     ) {
         if capture_information.is_empty() {
             return;
@@ -554,8 +542,12 @@ fn compute_min_captures(
             let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
                 None => {
                     let mutability = self.determine_capture_mutability(&typeck_results, &place);
-                    let min_cap_list =
-                        vec![ty::CapturedPlace { place, info: capture_info, mutability }];
+                    let min_cap_list = vec![ty::CapturedPlace {
+                        place,
+                        info: capture_info,
+                        mutability,
+                        region: None,
+                    }];
                     root_var_min_capture_list.insert(var_hir_id, min_cap_list);
                     continue;
                 }
@@ -608,8 +600,18 @@ fn compute_min_captures(
             if !descendant_found {
                 for possible_ancestor in min_cap_list.iter_mut() {
                     match determine_place_ancestry_relation(&place, &possible_ancestor.place) {
+                        PlaceAncestryRelation::SamePlace => {
+                            ancestor_found = true;
+                            possible_ancestor.info = determine_capture_info(
+                                possible_ancestor.info,
+                                updated_capture_info,
+                            );
+
+                            // Only one related place will be in the list.
+                            break;
+                        }
                         // current place is descendant of possible_ancestor
-                        PlaceAncestryRelation::Descendant | PlaceAncestryRelation::SamePlace => {
+                        PlaceAncestryRelation::Descendant => {
                             ancestor_found = true;
                             let backup_path_expr_id = possible_ancestor.info.path_expr_id;
 
@@ -629,7 +631,7 @@ fn compute_min_captures(
                             // we need to keep the ancestor's `path_expr_id`
                             possible_ancestor.info.path_expr_id = backup_path_expr_id;
 
-                            // Only one ancestor of the current place will be in the list.
+                            // Only one related place will be in the list.
                             break;
                         }
                         _ => {}
@@ -640,12 +642,31 @@ fn compute_min_captures(
             // Only need to insert when we don't have an ancestor in the existing min capture list
             if !ancestor_found {
                 let mutability = self.determine_capture_mutability(&typeck_results, &place);
-                let captured_place =
-                    ty::CapturedPlace { place, info: updated_capture_info, mutability };
+                let captured_place = ty::CapturedPlace {
+                    place,
+                    info: updated_capture_info,
+                    mutability,
+                    region: None,
+                };
                 min_cap_list.push(captured_place);
             }
         }
 
+        // For each capture that is determined to be captured by ref, add region info.
+        for (_, captures) in &mut root_var_min_capture_list {
+            for capture in captures {
+                match capture.info.capture_kind {
+                    ty::UpvarCapture::ByRef(_) => {
+                        let PlaceBase::Upvar(upvar_id) = capture.place.base else { bug!("expected upvar") };
+                        let origin = UpvarRegion(upvar_id, closure_span);
+                        let upvar_region = self.next_region_var(origin);
+                        capture.region = Some(upvar_region);
+                    }
+                    _ => (),
+                }
+            }
+        }
+
         debug!(
             "For closure={:?}, min_captures before sorting={:?}",
             closure_def_id, root_var_min_capture_list
@@ -947,7 +968,12 @@ fn compute_2229_migrations_for_trait(
                     max_capture_info = determine_capture_info(max_capture_info, capture.info);
                 }
 
-                apply_capture_kind_on_capture_ty(self.tcx, ty, max_capture_info.capture_kind)
+                apply_capture_kind_on_capture_ty(
+                    self.tcx,
+                    ty,
+                    max_capture_info.capture_kind,
+                    Some(&ty::ReErased),
+                )
             }
         };
 
@@ -977,6 +1003,7 @@ fn compute_2229_migrations_for_trait(
                 self.tcx,
                 capture.place.ty(),
                 capture.info.capture_kind,
+                Some(&ty::ReErased),
             );
 
             // Checks if a capture implements any of the auto traits
@@ -1086,7 +1113,7 @@ fn compute_2229_migrations_for_drop(
         for captured_place in root_var_min_capture_list.iter() {
             match captured_place.info.capture_kind {
                 // Only care about captures that are moved into the closure
-                ty::UpvarCapture::ByValue(..) => {
+                ty::UpvarCapture::ByValue => {
                     projections_list.push(captured_place.place.projections.as_slice());
                     diagnostics_info.insert(UpvarMigrationInfo::CapturingPrecise {
                         source_expr: captured_place.info.path_expr_id,
@@ -1470,9 +1497,7 @@ fn init_capture_kind_for_place(
         &self,
         place: &Place<'tcx>,
         capture_clause: hir::CaptureBy,
-        upvar_id: ty::UpvarId,
-        closure_span: Span,
-    ) -> ty::UpvarCapture<'tcx> {
+    ) -> ty::UpvarCapture {
         match capture_clause {
             // In case of a move closure if the data is accessed through a reference we
             // want to capture by ref to allow precise capture using reborrows.
@@ -1481,14 +1506,9 @@ fn init_capture_kind_for_place(
             // 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) => {
-                ty::UpvarCapture::ByValue(None)
-            }
-            hir::CaptureBy::Value | hir::CaptureBy::Ref => {
-                let origin = UpvarRegion(upvar_id, closure_span);
-                let upvar_region = self.next_region_var(origin);
-                let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
-                ty::UpvarCapture::ByRef(upvar_borrow)
+                ty::UpvarCapture::ByValue
             }
+            hir::CaptureBy::Value | hir::CaptureBy::Ref => ty::UpvarCapture::ByRef(ty::ImmBorrow),
         }
     }
 
@@ -1513,7 +1533,7 @@ fn should_log_capture_analysis(&self, closure_def_id: DefId) -> bool {
     fn log_capture_analysis_first_pass(
         &self,
         closure_def_id: rustc_hir::def_id::DefId,
-        capture_information: &FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>,
+        capture_information: &InferredCaptureInformation<'tcx>,
         closure_span: Span,
     ) {
         if self.should_log_capture_analysis(closure_def_id) {
@@ -1629,9 +1649,9 @@ fn determine_capture_mutability(
 fn restrict_repr_packed_field_ref_capture<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    place: &Place<'tcx>,
-    mut curr_borrow_kind: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    mut place: Place<'tcx>,
+    mut curr_borrow_kind: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let pos = place.projections.iter().enumerate().position(|(i, p)| {
         let ty = place.ty_before_projection(i);
 
@@ -1662,8 +1682,6 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
         }
     });
 
-    let mut place = place.clone();
-
     if let Some(pos) = pos {
         truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_borrow_kind, pos);
     }
@@ -1675,12 +1693,14 @@ fn restrict_repr_packed_field_ref_capture<'tcx>(
 fn apply_capture_kind_on_capture_ty<'tcx>(
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
-    capture_kind: UpvarCapture<'tcx>,
+    capture_kind: UpvarCapture,
+    region: Option<ty::Region<'tcx>>,
 ) -> Ty<'tcx> {
     match capture_kind {
-        ty::UpvarCapture::ByValue(_) => ty,
-        ty::UpvarCapture::ByRef(borrow) => tcx
-            .mk_ref(borrow.region, ty::TypeAndMut { ty: ty, mutbl: borrow.kind.to_mutbl_lossy() }),
+        ty::UpvarCapture::ByValue => ty,
+        ty::UpvarCapture::ByRef(kind) => {
+            tcx.mk_ref(region.unwrap(), ty::TypeAndMut { ty: ty, mutbl: kind.to_mutbl_lossy() })
+        }
     }
 }
 
@@ -1708,9 +1728,7 @@ struct InferBorrowKind<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
 
     // The def-id of the closure whose kind and upvar accesses are being inferred.
-    closure_def_id: DefId,
-
-    closure_span: Span,
+    closure_def_id: LocalDefId,
 
     /// For each Place that is captured by the closure, we track the minimal kind of
     /// access we need (ref, ref mut, move, etc) and the expression that resulted in such access.
@@ -1742,184 +1760,38 @@ struct InferBorrowKind<'a, 'tcx> {
     fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>,
 }
 
-impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
-    #[instrument(skip(self), level = "debug")]
-    fn adjust_upvar_borrow_kind_for_consume(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-    ) {
-        let tcx = self.fcx.tcx;
-        let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else {
-            return;
-        };
-
-        debug!(?upvar_id);
-
-        let usage_span = tcx.hir().span(diag_expr_id);
-
-        let capture_info = ty::CaptureInfo {
-            capture_kind_expr_id: Some(diag_expr_id),
-            path_expr_id: Some(diag_expr_id),
-            capture_kind: ty::UpvarCapture::ByValue(Some(usage_span)),
-        };
-
-        let curr_info = self.capture_information[&place_with_id.place];
-        let updated_info = determine_capture_info(curr_info, capture_info);
-
-        self.capture_information[&place_with_id.place] = updated_info;
-    }
-
-    /// Indicates that `place_with_id` is being directly mutated (e.g., assigned
-    /// to). If the place is based on a by-ref upvar, this implies that
-    /// the upvar must be borrowed using an `&mut` borrow.
-    #[instrument(skip(self), level = "debug")]
-    fn adjust_upvar_borrow_kind_for_mut(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-    ) {
-        if let PlaceBase::Upvar(_) = place_with_id.place.base {
-            // Raw pointers don't inherit mutability
-            if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
-                return;
-            }
-            self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::MutBorrow);
-        }
-    }
-
-    #[instrument(skip(self), level = "debug")]
-    fn adjust_upvar_borrow_kind_for_unique(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-    ) {
-        if let PlaceBase::Upvar(_) = place_with_id.place.base {
-            if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
-                // Raw pointers don't inherit mutability.
-                return;
-            }
-            // for a borrowed pointer to be unique, its base must be unique
-            self.adjust_upvar_deref(place_with_id, diag_expr_id, ty::UniqueImmBorrow);
-        }
-    }
-
-    fn adjust_upvar_deref(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-        borrow_kind: ty::BorrowKind,
-    ) {
-        assert!(match borrow_kind {
-            ty::MutBorrow => true,
-            ty::UniqueImmBorrow => true,
-
-            // imm borrows never require adjusting any kinds, so we don't wind up here
-            ty::ImmBorrow => false,
-        });
-
-        // if this is an implicit deref of an
-        // upvar, then we need to modify the
-        // borrow_kind of the upvar to make sure it
-        // is inferred to mutable if necessary
-        self.adjust_upvar_borrow_kind(place_with_id, diag_expr_id, borrow_kind);
-    }
-
-    /// We infer the borrow_kind with which to borrow upvars in a stack closure.
-    /// The borrow_kind basically follows a lattice of `imm < unique-imm < mut`,
-    /// moving from left to right as needed (but never right to left).
-    /// Here the argument `mutbl` is the borrow_kind that is required by
-    /// some particular use.
-    #[instrument(skip(self), level = "debug")]
-    fn adjust_upvar_borrow_kind(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-        kind: ty::BorrowKind,
-    ) {
-        let curr_capture_info = self.capture_information[&place_with_id.place];
-
-        debug!(?curr_capture_info);
-
-        if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind {
-            // It's already captured by value, we don't need to do anything here
-            return;
-        } else if let ty::UpvarCapture::ByRef(curr_upvar_borrow) = curr_capture_info.capture_kind {
-            // Use the same region as the current capture information
-            // Doesn't matter since only one of the UpvarBorrow will be used.
-            let new_upvar_borrow = ty::UpvarBorrow { kind, region: curr_upvar_borrow.region };
-
-            let capture_info = ty::CaptureInfo {
-                capture_kind_expr_id: Some(diag_expr_id),
-                path_expr_id: Some(diag_expr_id),
-                capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow),
-            };
-            let updated_info = determine_capture_info(curr_capture_info, capture_info);
-            self.capture_information[&place_with_id.place] = updated_info;
-        };
-    }
-
-    #[instrument(skip(self, diag_expr_id), level = "debug")]
-    fn init_capture_info_for_place(
-        &mut self,
-        place_with_id: &PlaceWithHirId<'tcx>,
-        diag_expr_id: hir::HirId,
-    ) {
-        if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base {
-            assert_eq!(self.closure_def_id.expect_local(), upvar_id.closure_expr_id);
-
-            // Initialize to ImmBorrow
-            // We will escalate the CaptureKind based on any uses we see or in `process_collected_capture_information`.
-            let origin = UpvarRegion(upvar_id, self.closure_span);
-            let upvar_region = self.fcx.next_region_var(origin);
-            let upvar_borrow = ty::UpvarBorrow { kind: ty::ImmBorrow, region: upvar_region };
-            let capture_kind = ty::UpvarCapture::ByRef(upvar_borrow);
-
-            let expr_id = Some(diag_expr_id);
-            let capture_info = ty::CaptureInfo {
-                capture_kind_expr_id: expr_id,
-                path_expr_id: expr_id,
-                capture_kind,
-            };
-
-            debug!("Capturing new place {:?}, capture_info={:?}", place_with_id, capture_info);
-
-            self.capture_information.insert(place_with_id.place.clone(), capture_info);
-        } else {
-            debug!("Not upvar");
-        }
-    }
-}
-
 impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
     fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
-        if let PlaceBase::Upvar(_) = place.base {
-            // We need to restrict Fake Read precision to avoid fake reading unsafe code,
-            // such as deref of a raw pointer.
-            let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::UpvarBorrow {
-                kind: ty::BorrowKind::ImmBorrow,
-                region: &ty::ReErased,
-            });
+        let PlaceBase::Upvar(_) = place.base else { return };
 
-            let (place, _) = restrict_capture_precision(place, dummy_capture_kind);
+        // We need to restrict Fake Read precision to avoid fake reading unsafe code,
+        // such as deref of a raw pointer.
+        let dummy_capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow);
 
-            let (place, _) = restrict_repr_packed_field_ref_capture(
-                self.fcx.tcx,
-                self.fcx.param_env,
-                &place,
-                dummy_capture_kind,
-            );
-            self.fake_reads.push((place, cause, diag_expr_id));
-        }
+        let (place, _) = restrict_capture_precision(place, dummy_capture_kind);
+
+        let (place, _) = restrict_repr_packed_field_ref_capture(
+            self.fcx.tcx,
+            self.fcx.param_env,
+            place,
+            dummy_capture_kind,
+        );
+        self.fake_reads.push((place, cause, diag_expr_id));
     }
 
     #[instrument(skip(self), level = "debug")]
     fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: hir::HirId) {
-        if !self.capture_information.contains_key(&place_with_id.place) {
-            self.init_capture_info_for_place(place_with_id, diag_expr_id);
-        }
+        let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
+        assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
 
-        self.adjust_upvar_borrow_kind_for_consume(place_with_id, diag_expr_id);
+        self.capture_information.push((
+            place_with_id.place.clone(),
+            ty::CaptureInfo {
+                capture_kind_expr_id: Some(diag_expr_id),
+                path_expr_id: Some(diag_expr_id),
+                capture_kind: ty::UpvarCapture::ByValue,
+            },
+        ));
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -1929,40 +1801,35 @@ fn borrow(
         diag_expr_id: hir::HirId,
         bk: ty::BorrowKind,
     ) {
+        let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
+        assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
+
         // The region here will get discarded/ignored
-        let dummy_capture_kind =
-            ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: bk, region: &ty::ReErased });
+        let capture_kind = ty::UpvarCapture::ByRef(bk);
 
         // We only want repr packed restriction to be applied to reading references into a packed
         // struct, and not when the data is being moved. Therefore we call this method here instead
         // of in `restrict_capture_precision`.
-        let (place, updated_kind) = restrict_repr_packed_field_ref_capture(
+        let (place, mut capture_kind) = restrict_repr_packed_field_ref_capture(
             self.fcx.tcx,
             self.fcx.param_env,
-            &place_with_id.place,
-            dummy_capture_kind,
+            place_with_id.place.clone(),
+            capture_kind,
         );
 
-        let place_with_id = PlaceWithHirId { place, ..*place_with_id };
-
-        if !self.capture_information.contains_key(&place_with_id.place) {
-            self.init_capture_info_for_place(&place_with_id, diag_expr_id);
+        // Raw pointers don't inherit mutability
+        if place_with_id.place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
+            capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow);
         }
 
-        match updated_kind {
-            ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind, .. }) => match kind {
-                ty::ImmBorrow => {}
-                ty::UniqueImmBorrow => {
-                    self.adjust_upvar_borrow_kind_for_unique(&place_with_id, diag_expr_id);
-                }
-                ty::MutBorrow => {
-                    self.adjust_upvar_borrow_kind_for_mut(&place_with_id, diag_expr_id);
-                }
+        self.capture_information.push((
+            place,
+            ty::CaptureInfo {
+                capture_kind_expr_id: Some(diag_expr_id),
+                path_expr_id: Some(diag_expr_id),
+                capture_kind,
             },
-
-            // Just truncating the place will never cause capture kind to be updated to ByValue
-            ty::UpvarCapture::ByValue(..) => unreachable!(),
-        }
+        ));
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -1975,12 +1842,12 @@ fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: hir::H
 fn restrict_precision_for_drop_types<'a, 'tcx>(
     fcx: &'a FnCtxt<'a, 'tcx>,
     mut place: Place<'tcx>,
-    mut curr_mode: ty::UpvarCapture<'tcx>,
+    mut curr_mode: ty::UpvarCapture,
     span: Span,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let is_copy_type = fcx.infcx.type_is_copy_modulo_regions(fcx.param_env, place.ty(), span);
 
-    if let (false, UpvarCapture::ByValue(..)) = (is_copy_type, curr_mode) {
+    if let (false, UpvarCapture::ByValue) = (is_copy_type, curr_mode) {
         for i in 0..place.projections.len() {
             match place.ty_before_projection(i).kind() {
                 ty::Adt(def, _) if def.destructor(fcx.tcx).is_some() => {
@@ -2001,8 +1868,8 @@ fn restrict_precision_for_drop_types<'a, 'tcx>(
 /// - No projections are applied on top of Union ADTs, since these require unsafe blocks.
 fn restrict_precision_for_unsafe<'tcx>(
     mut place: Place<'tcx>,
-    mut curr_mode: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    mut curr_mode: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     if place.base_ty.is_unsafe_ptr() {
         truncate_place_to_len_and_update_capture_kind(&mut place, &mut curr_mode, 0);
     }
@@ -2034,8 +1901,8 @@ fn restrict_precision_for_unsafe<'tcx>(
 /// Returns the truncated place and updated cature mode.
 fn restrict_capture_precision<'tcx>(
     place: Place<'tcx>,
-    curr_mode: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    curr_mode: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let (mut place, mut curr_mode) = restrict_precision_for_unsafe(place, curr_mode);
 
     if place.projections.is_empty() {
@@ -2062,30 +1929,28 @@ fn restrict_capture_precision<'tcx>(
 /// Truncate deref of any reference.
 fn adjust_for_move_closure<'tcx>(
     mut place: Place<'tcx>,
-    mut kind: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    mut kind: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let first_deref = place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
 
     if let Some(idx) = first_deref {
         truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
     }
 
-    // AMAN: I think we don't need the span inside the ByValue anymore
-    //       we have more detailed span in CaptureInfo
-    (place, ty::UpvarCapture::ByValue(None))
+    (place, ty::UpvarCapture::ByValue)
 }
 
 /// Adjust closure capture just that if taking ownership of data, only move data
 /// from enclosing stack frame.
 fn adjust_for_non_move_closure<'tcx>(
     mut place: Place<'tcx>,
-    mut kind: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    mut kind: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let contains_deref =
         place.projections.iter().position(|proj| proj.kind == ProjectionKind::Deref);
 
     match kind {
-        ty::UpvarCapture::ByValue(..) => {
+        ty::UpvarCapture::ByValue => {
             if let Some(idx) = contains_deref {
                 truncate_place_to_len_and_update_capture_kind(&mut place, &mut kind, idx);
             }
@@ -2123,13 +1988,13 @@ fn construct_place_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String
 fn construct_capture_kind_reason_string<'tcx>(
     tcx: TyCtxt<'_>,
     place: &Place<'tcx>,
-    capture_info: &ty::CaptureInfo<'tcx>,
+    capture_info: &ty::CaptureInfo,
 ) -> String {
     let place_str = construct_place_string(tcx, place);
 
     let capture_kind_str = match capture_info.capture_kind {
-        ty::UpvarCapture::ByValue(_) => "ByValue".into(),
-        ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
+        ty::UpvarCapture::ByValue => "ByValue".into(),
+        ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind),
     };
 
     format!("{} captured as {} here", place_str, capture_kind_str)
@@ -2144,13 +2009,13 @@ fn construct_path_string<'tcx>(tcx: TyCtxt<'_>, place: &Place<'tcx>) -> String {
 fn construct_capture_info_string<'tcx>(
     tcx: TyCtxt<'_>,
     place: &Place<'tcx>,
-    capture_info: &ty::CaptureInfo<'tcx>,
+    capture_info: &ty::CaptureInfo,
 ) -> String {
     let place_str = construct_place_string(tcx, place);
 
     let capture_kind_str = match capture_info.capture_kind {
-        ty::UpvarCapture::ByValue(_) => "ByValue".into(),
-        ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind),
+        ty::UpvarCapture::ByValue => "ByValue".into(),
+        ty::UpvarCapture::ByRef(kind) => format!("{:?}", kind),
     };
     format!("{} -> {}", place_str, capture_kind_str)
 }
@@ -2233,25 +2098,16 @@ fn migration_suggestion_for_2229(
 /// would've already handled `E1`, and have an existing capture_information for it.
 /// Calling `determine_capture_info(existing_info_e1, current_info_e2)` will return
 /// `existing_info_e1` in this case, allowing us to point to `E1` in case of diagnostics.
-fn determine_capture_info<'tcx>(
-    capture_info_a: ty::CaptureInfo<'tcx>,
-    capture_info_b: ty::CaptureInfo<'tcx>,
-) -> ty::CaptureInfo<'tcx> {
+fn determine_capture_info(
+    capture_info_a: ty::CaptureInfo,
+    capture_info_b: ty::CaptureInfo,
+) -> ty::CaptureInfo {
     // If the capture kind is equivalent then, we don't need to escalate and can compare the
     // expressions.
     let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
-        (ty::UpvarCapture::ByValue(_), ty::UpvarCapture::ByValue(_)) => {
-            // We don't need to worry about the spans being ignored here.
-            //
-            // The expr_id in capture_info corresponds to the span that is stored within
-            // ByValue(span) and therefore it gets handled with priortizing based on
-            // expressions below.
-            true
-        }
-        (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
-            ref_a.kind == ref_b.kind
-        }
-        (ty::UpvarCapture::ByValue(_), _) | (ty::UpvarCapture::ByRef(_), _) => false,
+        (ty::UpvarCapture::ByValue, ty::UpvarCapture::ByValue) => true,
+        (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => ref_a == ref_b,
+        (ty::UpvarCapture::ByValue, _) | (ty::UpvarCapture::ByRef(_), _) => false,
     };
 
     if eq_capture_kind {
@@ -2263,10 +2119,10 @@ fn determine_capture_info<'tcx>(
         // We select the CaptureKind which ranks higher based the following priority order:
         // ByValue > MutBorrow > UniqueImmBorrow > ImmBorrow
         match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
-            (ty::UpvarCapture::ByValue(_), _) => capture_info_a,
-            (_, ty::UpvarCapture::ByValue(_)) => capture_info_b,
+            (ty::UpvarCapture::ByValue, _) => capture_info_a,
+            (_, ty::UpvarCapture::ByValue) => capture_info_b,
             (ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
-                match (ref_a.kind, ref_b.kind) {
+                match (ref_a, ref_b) {
                     // Take LHS:
                     (ty::UniqueImmBorrow | ty::MutBorrow, ty::ImmBorrow)
                     | (ty::MutBorrow, ty::UniqueImmBorrow) => capture_info_a,
@@ -2294,7 +2150,7 @@ fn determine_capture_info<'tcx>(
 /// contained `Deref` of `&mut`.
 fn truncate_place_to_len_and_update_capture_kind<'tcx>(
     place: &mut Place<'tcx>,
-    curr_mode: &mut ty::UpvarCapture<'tcx>,
+    curr_mode: &mut ty::UpvarCapture,
     len: usize,
 ) {
     let is_mut_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Mut));
@@ -2304,22 +2160,19 @@ fn truncate_place_to_len_and_update_capture_kind<'tcx>(
     // Note that if the place contained Deref of a raw pointer it would've not been MutBorrow, so
     // we don't need to worry about that case here.
     match curr_mode {
-        ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: ty::BorrowKind::MutBorrow, region }) => {
+        ty::UpvarCapture::ByRef(ty::BorrowKind::MutBorrow) => {
             for i in len..place.projections.len() {
                 if place.projections[i].kind == ProjectionKind::Deref
                     && is_mut_ref(place.ty_before_projection(i))
                 {
-                    *curr_mode = ty::UpvarCapture::ByRef(ty::UpvarBorrow {
-                        kind: ty::BorrowKind::UniqueImmBorrow,
-                        region,
-                    });
+                    *curr_mode = ty::UpvarCapture::ByRef(ty::BorrowKind::UniqueImmBorrow);
                     break;
                 }
             }
         }
 
         ty::UpvarCapture::ByRef(..) => {}
-        ty::UpvarCapture::ByValue(..) => {}
+        ty::UpvarCapture::ByValue => {}
     }
 
     place.projections.truncate(len);
@@ -2390,8 +2243,8 @@ fn determine_place_ancestry_relation<'tcx>(
 /// ```
 fn truncate_capture_for_optimization<'tcx>(
     mut place: Place<'tcx>,
-    mut curr_mode: ty::UpvarCapture<'tcx>,
-) -> (Place<'tcx>, ty::UpvarCapture<'tcx>) {
+    mut curr_mode: ty::UpvarCapture,
+) -> (Place<'tcx>, ty::UpvarCapture) {
     let is_shared_ref = |ty: Ty<'_>| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not));
 
     // Find the right-most deref (if any). All the projections that come after this
index 7c4f5d16abcaba934f1755ded4f77c385a842ea8..964d4523bc01c92e65fba2fd277a0014f860db6f 100644 (file)
@@ -14,8 +14,9 @@
 use rustc_hir::ItemKind;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::outlives::obligations::TypeOutlives;
-use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::infer::{self, RegionckMode, SubregionOrigin};
+use rustc_infer::infer::region_constraints::GenericKind;
+use rustc_infer::infer::{self, RegionckMode};
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::hir::map as hir_map;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
@@ -205,7 +206,7 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     check_object_unsafe_self_trait_by_name(tcx, trait_item);
     check_associated_item(tcx, trait_item.def_id, span, method_sig);
 
-    let encl_trait_def_id = tcx.hir().get_parent_did(hir_id);
+    let encl_trait_def_id = tcx.hir().get_parent_item(hir_id);
     let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
     let encl_trait_def_id = encl_trait.def_id.to_def_id();
     let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
@@ -311,7 +312,7 @@ fn check_gat_where_clauses(
         // 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());
+            GATSubstCollector::visit(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
@@ -332,6 +333,12 @@ fn check_gat_where_clauses(
         // 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 {
+                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) {
@@ -371,10 +378,19 @@ fn check_gat_where_clauses(
         // 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 {
+                continue;
+            }
             for (region_b, region_b_idx) in &regions {
                 if region_a == region_b {
                     continue;
                 }
+                if let ty::ReStatic = region_b {
+                    continue;
+                }
 
                 if region_known_to_outlive(tcx, id, param_env, &wf_tys, *region_a, *region_b) {
                     debug!(?region_a_idx, ?region_b_idx);
@@ -502,8 +518,6 @@ fn check_gat_where_clauses(
     }
 }
 
-// FIXME(jackh726): refactor some of the shared logic between the two functions below
-
 /// 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>(
@@ -514,47 +528,21 @@ fn ty_known_to_outlive<'tcx>(
     ty: Ty<'tcx>,
     region: ty::Region<'tcx>,
 ) -> bool {
-    // Unfortunately, we have to use a new `InferCtxt` each call, because
-    // region constraints get added and solved there and we need to test each
-    // call individually.
-    tcx.infer_ctxt().enter(|infcx| {
-        let mut outlives_environment = OutlivesEnvironment::new(param_env);
-        outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
-        outlives_environment.save_implied_bounds(id);
-        let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
-
-        let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
-
-        let sup_type = ty;
-        let sub_region = region;
-
-        let origin = SubregionOrigin::from_obligation_cause(&cause, || {
-            infer::RelateParamBound(cause.span, sup_type, None)
-        });
-
+    resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |infcx, region_bound_pairs| {
+        let origin = infer::RelateParamBound(DUMMY_SP, ty, None);
         let outlives = &mut TypeOutlives::new(
-            &infcx,
+            infcx,
             tcx,
-            &region_bound_pairs,
+            region_bound_pairs,
             Some(infcx.tcx.lifetimes.re_root_empty),
             param_env,
         );
-        outlives.type_must_outlive(origin, sup_type, sub_region);
-
-        let errors = infcx.resolve_regions(
-            id.expect_owner().to_def_id(),
-            &outlives_environment,
-            RegionckMode::default(),
-        );
-
-        debug!(?errors, "errors");
-
-        // If we were able to prove that the type outlives the region without
-        // an error, it must be because of the implied or explicit bounds...
-        errors.is_empty()
+        outlives.type_must_outlive(origin, ty, region);
     })
 }
 
+/// Given a known `param_env` and a set of well formed types, can we prove that
+/// `region_a` outlives `region_b`
 fn region_known_to_outlive<'tcx>(
     tcx: TyCtxt<'tcx>,
     id: hir::HirId,
@@ -562,6 +550,27 @@ fn region_known_to_outlive<'tcx>(
     wf_tys: &FxHashSet<Ty<'tcx>>,
     region_a: ty::Region<'tcx>,
     region_b: ty::Region<'tcx>,
+) -> bool {
+    resolve_regions_with_wf_tys(tcx, id, param_env, &wf_tys, |mut infcx, _| {
+        use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
+        let origin = infer::RelateRegionParamBound(DUMMY_SP);
+        // `region_a: region_b` -> `region_b <= region_a`
+        infcx.push_sub_region_constraint(origin, region_b, region_a);
+    })
+}
+
+/// Given a known `param_env` and a set of well formed types, set up an
+/// `InferCtxt`, call the passed function (to e.g. set up region constraints
+/// to be tested), then resolve region and return errors
+fn resolve_regions_with_wf_tys<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    id: hir::HirId,
+    param_env: ty::ParamEnv<'tcx>,
+    wf_tys: &FxHashSet<Ty<'tcx>>,
+    add_constraints: impl for<'a> FnOnce(
+        &'a InferCtxt<'a, 'tcx>,
+        &'a Vec<(&'tcx ty::RegionKind, GenericKind<'tcx>)>,
+    ),
 ) -> bool {
     // Unfortunately, we have to use a new `InferCtxt` each call, because
     // region constraints get added and solved there and we need to test each
@@ -570,16 +579,9 @@ fn region_known_to_outlive<'tcx>(
         let mut outlives_environment = OutlivesEnvironment::new(param_env);
         outlives_environment.add_implied_bounds(&infcx, wf_tys.clone(), id, DUMMY_SP);
         outlives_environment.save_implied_bounds(id);
+        let region_bound_pairs = outlives_environment.region_bound_pairs_map().get(&id).unwrap();
 
-        let cause = ObligationCause::new(DUMMY_SP, id, ObligationCauseCode::MiscObligation);
-
-        let origin = SubregionOrigin::from_obligation_cause(&cause, || {
-            infer::RelateRegionParamBound(cause.span)
-        });
-
-        use rustc_infer::infer::outlives::obligations::TypeOutlivesDelegate;
-        // `region_a: region_b` -> `region_b <= region_a`
-        (&infcx).push_sub_region_constraint(origin, region_b, region_a);
+        add_constraints(&infcx, region_bound_pairs);
 
         let errors = infcx.resolve_regions(
             id.expect_owner().to_def_id(),
@@ -600,7 +602,6 @@ fn region_known_to_outlive<'tcx>(
 /// the two vectors, `regions` and `types` (depending on their kind). For each
 /// parameter `Pi` also track the index `i`.
 struct GATSubstCollector<'tcx> {
-    tcx: TyCtxt<'tcx>,
     gat: DefId,
     // Which region appears and which parameter index its subsituted for
     regions: FxHashSet<(ty::Region<'tcx>, usize)>,
@@ -610,16 +611,11 @@ struct GATSubstCollector<'tcx> {
 
 impl<'tcx> GATSubstCollector<'tcx> {
     fn visit<T: TypeFoldable<'tcx>>(
-        tcx: TyCtxt<'tcx>,
         gat: DefId,
         t: T,
     ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
-        let mut visitor = GATSubstCollector {
-            tcx,
-            gat,
-            regions: FxHashSet::default(),
-            types: FxHashSet::default(),
-        };
+        let mut visitor =
+            GATSubstCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() };
         t.visit_with(&mut visitor);
         (visitor.regions, visitor.types)
     }
@@ -647,10 +643,6 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         }
         t.super_visit_with(self)
     }
-
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.tcx)
-    }
 }
 
 fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
@@ -666,13 +658,14 @@ fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
 /// Detect when an object unsafe trait is referring to itself in one of its associated items.
 /// When this is done, suggest using `Self` instead.
 fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem<'_>) {
-    let (trait_name, trait_def_id) = match tcx.hir().get(tcx.hir().get_parent_item(item.hir_id())) {
-        hir::Node::Item(item) => match item.kind {
-            hir::ItemKind::Trait(..) => (item.ident, item.def_id),
+    let (trait_name, trait_def_id) =
+        match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(item.hir_id())) {
+            hir::Node::Item(item) => match item.kind {
+                hir::ItemKind::Trait(..) => (item.ident, item.def_id),
+                _ => return,
+            },
             _ => return,
-        },
-        _ => return,
-    };
+        };
     let mut trait_should_be_self = vec![];
     match &item.kind {
         hir::TraitItemKind::Const(ty, _) | hir::TraitItemKind::Type(_, Some(ty))
@@ -784,9 +777,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
                 }
             };
 
-            if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
-                .is_some()
-            {
+            if traits::search_for_structural_match_violation(param.span, tcx, ty).is_some() {
                 // We use the same error code in both branches, because this is really the same
                 // issue: we just special-case the message for type parameters to make it
                 // clearer.
@@ -1197,7 +1188,7 @@ fn check_where_clauses<'tcx, 'fcx>(
                     // Ignore dependent defaults -- that is, where the default of one type
                     // parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
                     // be sure if it will error or not as user might always specify the other.
-                    if !ty.definitely_needs_subst(tcx) {
+                    if !ty.needs_subst() {
                         fcx.register_wf_obligation(
                             ty.into(),
                             tcx.def_span(param.def_id),
@@ -1213,7 +1204,7 @@ fn check_where_clauses<'tcx, 'fcx>(
                     // for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
                     // we should eagerly error.
                     let default_ct = tcx.const_param_default(param.def_id);
-                    if !default_ct.definitely_needs_subst(tcx) {
+                    if !default_ct.needs_subst() {
                         fcx.register_wf_obligation(
                             default_ct.into(),
                             tcx.def_span(param.def_id),
@@ -1247,7 +1238,7 @@ fn check_where_clauses<'tcx, 'fcx>(
                 if is_our_default(param) {
                     let default_ty = tcx.type_of(param.def_id);
                     // ... and it's not a dependent default, ...
-                    if !default_ty.definitely_needs_subst(tcx) {
+                    if !default_ty.needs_subst() {
                         // ... then substitute it with the default.
                         return default_ty.into();
                     }
@@ -1260,7 +1251,7 @@ fn check_where_clauses<'tcx, 'fcx>(
                 if is_our_default(param) {
                     let default_ct = tcx.const_param_default(param.def_id);
                     // ... and it's not a dependent default, ...
-                    if !default_ct.definitely_needs_subst(tcx) {
+                    if !default_ct.needs_subst() {
                         // ... then substitute it with the default.
                         return default_ct.into();
                     }
@@ -1276,15 +1267,12 @@ fn check_where_clauses<'tcx, 'fcx>(
         .predicates
         .iter()
         .flat_map(|&(pred, sp)| {
-            struct CountParams<'tcx> {
-                tcx: TyCtxt<'tcx>,
+            #[derive(Default)]
+            struct CountParams {
                 params: FxHashSet<u32>,
             }
-            impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams<'tcx> {
+            impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
                 type BreakTy = ();
-                fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-                    Some(self.tcx)
-                }
 
                 fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
                     if let ty::Param(param) = t.kind() {
@@ -1304,12 +1292,12 @@ fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> ControlFlow<Self::BreakTy
                     c.super_visit_with(self)
                 }
             }
-            let mut param_count = CountParams { tcx: fcx.tcx, params: FxHashSet::default() };
+            let mut param_count = CountParams::default();
             let has_region = pred.visit_with(&mut param_count).is_break();
             let substituted_pred = pred.subst(tcx, substs);
             // Don't check non-defaulted params, dependent defaults (including lifetimes)
             // or preds with multiple params.
-            if substituted_pred.definitely_has_param_types_or_consts(tcx)
+            if substituted_pred.has_param_types_or_consts()
                 || param_count.params.len() > 1
                 || has_region
             {
@@ -1697,7 +1685,7 @@ fn check_false_global_bounds(fcx: &FnCtxt<'_, '_>, mut span: Span, id: hir::HirI
     for obligation in implied_obligations {
         let pred = obligation.predicate;
         // Match the existing behavior.
-        if pred.is_global(fcx.tcx) && !pred.has_late_bound_regions() {
+        if pred.is_global() && !pred.has_late_bound_regions() {
             let pred = fcx.normalize_associated_types_in(span, pred);
             let hir_node = fcx.tcx.hir().find(id);
 
index fdc8b6b5e64519d57642ad6549ec858d880fcc89..bb407d563e7aac52c0f024195722129542450c8b 100644 (file)
@@ -130,7 +130,7 @@ fn tcx(&self) -> TyCtxt<'tcx> {
 
     fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) {
         debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty);
-        assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions(self.tcx()));
+        assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions());
         self.typeck_results.node_types_mut().insert(hir_id, ty);
     }
 
@@ -750,7 +750,7 @@ fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
         self.tcx
     }
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
-        if ty.has_type_flags(ty::TypeFlags::HAS_POTENTIAL_FREE_REGIONS) {
+        if ty.has_type_flags(ty::TypeFlags::HAS_FREE_REGIONS) {
             ty.super_fold_with(self)
         } else {
             ty
index d5494c5a6854847a48f571a844a6719ecbf7bca7..dff6b7b58a0f9986520e9a37e544ae18ce653ae6 100644 (file)
@@ -199,7 +199,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
                                 )
                                 .note(&format!(
                                     "extra field `{}` of type `{}` is not allowed",
-                                    field.ident, ty_a,
+                                    field.name, ty_a,
                                 ))
                                 .emit();
 
@@ -235,7 +235,7 @@ fn visit_implementation_of_dispatch_from_dyn<'tcx>(tcx: TyCtxt<'tcx>, impl_did:
                             .map(|field| {
                                 format!(
                                     "`{}` (`{}` to `{}`)",
-                                    field.ident,
+                                    field.name,
                                     field.ty(tcx, substs_a),
                                     field.ty(tcx, substs_b),
                                 )
@@ -479,7 +479,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUn
                         diff_fields
                             .iter()
                             .map(|&(i, a, b)| {
-                                format!("`{}` (`{}` to `{}`)", fields[i].ident, a, b)
+                                format!("`{}` (`{}` to `{}`)", fields[i].name, a, b)
                             })
                             .collect::<Vec<_>>()
                             .join(", ")
index 377ebf1fe2a9f5fdad1b5a23e4ebc4492182d594..055818f55f0c8f6a84dd476db41bbca640a4f0b3 100644 (file)
@@ -121,28 +121,6 @@ fn enforce_trait_manually_implementable(
             return;
         }
     }
-
-    let trait_name = if did == li.fn_trait() {
-        "Fn"
-    } else if did == li.fn_mut_trait() {
-        "FnMut"
-    } else if did == li.fn_once_trait() {
-        "FnOnce"
-    } else {
-        return; // everything OK
-    };
-
-    let span = impl_header_span(tcx, impl_def_id);
-    struct_span_err!(
-        tcx.sess,
-        span,
-        E0183,
-        "manual implementations of `{}` are experimental",
-        trait_name
-    )
-    .span_label(span, format!("manual implementations of `{}` are experimental", trait_name))
-    .help("add `#![feature(unboxed_closures)]` to the crate attributes to enable")
-    .emit();
 }
 
 /// We allow impls of marker traits to overlap, so they can't override impls
index 2fb5590016ef88514547d39fe3b27c9f473e7360..fbb630004cacd58c5bfa92cc3e754169f3c97cef 100644 (file)
@@ -21,7 +21,6 @@
 use crate::errors;
 use crate::middle::resolve_lifetime as rl;
 use rustc_ast as ast;
-use rustc_ast::Attribute;
 use rustc_ast::{MetaItemKind, NestedMetaItem};
 use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_data_structures::captures::Captures;
@@ -29,7 +28,7 @@
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind};
-use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_hir::weak_lang_items;
 use rustc_hir::{GenericParamKind, HirId, Node};
@@ -68,7 +67,6 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         opt_const_param_of: type_of::opt_const_param_of,
-        default_anon_const_substs: type_of::default_anon_const_substs,
         type_of: type_of::type_of,
         item_bounds: item_bounds::item_bounds,
         explicit_item_bounds: item_bounds::explicit_item_bounds,
@@ -182,7 +180,7 @@ struct CollectItemTypesVisitor<'tcx> {
         sugg.push((span, format!(", {}", type_name)));
     }
 
-    let mut err = bad_placeholder_type(tcx, placeholder_types, kind);
+    let mut err = bad_placeholder(tcx, "type", placeholder_types, kind);
 
     // Suggest, but only if it is not a function in const or static
     if suggest {
@@ -295,7 +293,9 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         if let hir::ExprKind::Closure(..) = expr.kind {
             let def_id = self.tcx.hir().local_def_id(expr.hir_id);
             self.tcx.ensure().generics_of(def_id);
-            self.tcx.ensure().type_of(def_id);
+            // We do not call `type_of` for closures here as that
+            // depends on typecheck and would therefore hide
+            // any further errors in case one typeck fails.
         }
         intravisit::walk_expr(self, expr);
     }
@@ -314,8 +314,9 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
 ///////////////////////////////////////////////////////////////////////////
 // Utility types and common code for the above passes.
 
-fn bad_placeholder_type<'tcx>(
+fn bad_placeholder<'tcx>(
     tcx: TyCtxt<'tcx>,
+    placeholder_kind: &'static str,
     mut spans: Vec<Span>,
     kind: &'static str,
 ) -> rustc_errors::DiagnosticBuilder<'tcx> {
@@ -326,7 +327,8 @@ fn bad_placeholder_type<'tcx>(
         tcx.sess,
         spans.clone(),
         E0121,
-        "the type placeholder `_` is not allowed within types on item signatures for {}",
+        "the {} placeholder `_` is not allowed within types on item signatures for {}",
+        placeholder_kind,
         kind
     );
     for span in spans {
@@ -393,7 +395,7 @@ fn ct_infer(
         _: Option<&ty::GenericParamDef>,
         span: Span,
     ) -> &'tcx Const<'tcx> {
-        bad_placeholder_type(self.tcx(), vec![span], "generic").emit();
+        bad_placeholder(self.tcx(), "const", vec![span], "generic").emit();
         // Typeck doesn't expect erased regions to be returned from `type_of`.
         let ty = self.tcx.fold_regions(ty, &mut false, |r, _| match r {
             ty::ReErased => self.tcx.lifetimes.re_static,
@@ -432,7 +434,7 @@ fn projected_ty_from_poly_trait_ref(
             match self.node() {
                 hir::Node::Field(_) | hir::Node::Ctor(_) | hir::Node::Variant(_) => {
                     let item =
-                        self.tcx.hir().expect_item(self.tcx.hir().get_parent_did(self.hir_id()));
+                        self.tcx.hir().expect_item(self.tcx.hir().get_parent_item(self.hir_id()));
                     match &item.kind {
                         hir::ItemKind::Enum(_, generics)
                         | hir::ItemKind::Struct(_, generics)
@@ -566,13 +568,12 @@ fn type_param_predicates(
 
     let param_id = tcx.hir().local_def_id_to_hir_id(def_id);
     let param_owner = tcx.hir().ty_param_owner(param_id);
-    let param_owner_def_id = tcx.hir().local_def_id(param_owner);
-    let generics = tcx.generics_of(param_owner_def_id);
+    let generics = tcx.generics_of(param_owner);
     let index = generics.param_def_id_to_index[&def_id.to_def_id()];
     let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(param_id));
 
     // Don't look for bounds where the type parameter isn't in scope.
-    let parent = if item_def_id == param_owner_def_id.to_def_id() {
+    let parent = if item_def_id == param_owner.to_def_id() {
         None
     } else {
         tcx.generics_of(item_def_id).parent
@@ -991,7 +992,7 @@ fn convert_variant(
                 seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span);
             }
 
-            ty::FieldDef { did: fid.to_def_id(), ident: f.ident, vis: tcx.visibility(fid) }
+            ty::FieldDef { did: fid.to_def_id(), name: f.ident.name, vis: tcx.visibility(fid) }
         })
         .collect();
     let recovered = match def {
@@ -999,7 +1000,7 @@ fn convert_variant(
         _ => false,
     };
     ty::VariantDef::new(
-        ident,
+        ident.name,
         variant_did.map(LocalDefId::to_def_id),
         ctor_did.map(LocalDefId::to_def_id),
         discr,
@@ -1393,13 +1394,12 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
         | Node::Ctor(..)
         | Node::Field(_) => {
             let parent_id = tcx.hir().get_parent_item(hir_id);
-            Some(tcx.hir().local_def_id(parent_id).to_def_id())
+            Some(parent_id.to_def_id())
         }
         // FIXME(#43408) always enable this once `lazy_normalization` is
         // stable enough and does not need a feature gate anymore.
         Node::AnonConst(_) => {
-            let parent_id = tcx.hir().get_parent_item(hir_id);
-            let parent_def_id = tcx.hir().local_def_id(parent_id);
+            let parent_def_id = tcx.hir().get_parent_item(hir_id);
 
             let mut in_param_ty = false;
             for (_parent, node) in tcx.hir().parent_iter(hir_id) {
@@ -1482,7 +1482,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                     // `enum` discriminants (i.e. `D` in `enum Foo { Bar = D }`),
                     // as they shouldn't be able to cause query cycle errors.
                     Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
-                    | Node::Variant(Variant { disr_expr: Some(ref constant), .. })
+                        if constant.hir_id() == hir_id =>
+                    {
+                        Some(parent_def_id.to_def_id())
+                    }
+                    Node::Variant(Variant { disr_expr: Some(ref constant), .. })
                         if constant.hir_id == hir_id =>
                     {
                         Some(parent_def_id.to_def_id())
@@ -1505,11 +1509,11 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             }) => Some(fn_def_id.to_def_id()),
             ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
                 let parent_id = tcx.hir().get_parent_item(hir_id);
-                assert!(parent_id != hir_id && parent_id != CRATE_HIR_ID);
+                assert_ne!(parent_id, CRATE_DEF_ID);
                 debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
                 // Opaque types are always nested within another item, and
                 // inherit the generics of the item.
-                Some(tcx.hir().local_def_id(parent_id).to_def_id())
+                Some(parent_id.to_def_id())
             }
             _ => None,
         },
@@ -1788,7 +1792,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
 
                     let mut visitor = PlaceholderHirTyCollector::default();
                     visitor.visit_ty(ty);
-                    let mut diag = bad_placeholder_type(tcx, visitor.0, "return type");
+                    let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type");
                     let ret_ty = fn_sig.skip_binder().output();
                     if !ret_ty.references_error() {
                         if !ret_ty.is_closure() {
@@ -1854,7 +1858,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
         }
 
         Ctor(data) | Variant(hir::Variant { data, .. }) if data.ctor_hir_id().is_some() => {
-            let ty = tcx.type_of(tcx.hir().get_parent_did(hir_id).to_def_id());
+            let ty = tcx.type_of(tcx.hir().get_parent_item(hir_id));
             let inputs =
                 data.fields().iter().map(|f| tcx.type_of(tcx.hir().local_def_id(f.hir_id)));
             ty::Binder::dummy(tcx.mk_fn_sig(
@@ -2272,7 +2276,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
             tcx,
             &mut predicates,
             trait_ref,
-            &mut cgp::parameters_for_impl(tcx, self_ty, trait_ref),
+            &mut cgp::parameters_for_impl(self_ty, trait_ref),
         );
     }
 
@@ -2424,8 +2428,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat
                 //        parent of generics returned by `generics_of`
                 //
                 // In the above code we want the anon const to have predicates in its param env for `T: Trait`
-                let item_id = tcx.hir().get_parent_item(hir_id);
-                let item_def_id = tcx.hir().local_def_id(item_id).to_def_id();
+                let item_def_id = tcx.hir().get_parent_item(hir_id);
                 // In the above code example we would be calling `explicit_predicates_of(Foo)` here
                 return tcx.explicit_predicates_of(item_def_id);
             }
@@ -3112,8 +3115,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
     if tcx.is_weak_lang_item(id) {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
     }
-    let check_name = |attr: &Attribute, sym| attr.has_name(sym);
-    if let Some(name) = weak_lang_items::link_name(check_name, attrs) {
+    if let Some(name) = weak_lang_items::link_name(attrs) {
         codegen_fn_attrs.export_name = Some(name);
         codegen_fn_attrs.link_name = Some(name);
     }
@@ -3142,21 +3144,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
 /// applied to the method prototype.
 fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     if let Some(impl_item) = tcx.opt_associated_item(def_id) {
-        if let ty::AssocItemContainer::ImplContainer(impl_def_id) = impl_item.container {
-            if let Some(trait_def_id) = tcx.trait_id_of_impl(impl_def_id) {
-                if let Some(trait_item) = tcx
-                    .associated_items(trait_def_id)
-                    .filter_by_name_unhygienic(impl_item.ident.name)
-                    .find(move |trait_item| {
-                        trait_item.kind == ty::AssocKind::Fn
-                            && tcx.hygienic_eq(impl_item.ident, trait_item.ident, trait_def_id)
-                    })
-                {
-                    return tcx
-                        .codegen_fn_attrs(trait_item.def_id)
-                        .flags
-                        .intersects(CodegenFnAttrFlags::TRACK_CALLER);
-                }
+        if let ty::AssocItemContainer::ImplContainer(_) = impl_item.container {
+            if let Some(trait_item) = impl_item.trait_item_def_id {
+                return tcx
+                    .codegen_fn_attrs(trait_item)
+                    .flags
+                    .intersects(CodegenFnAttrFlags::TRACK_CALLER);
             }
         }
     }
@@ -3233,7 +3226,7 @@ fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span:
     let hir_id = tcx.hir().local_def_id_to_hir_id(id);
     let node = tcx.hir().get(hir_id);
     if let Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) = node {
-        let parent_id = tcx.hir().get_parent_did(hir_id);
+        let parent_id = tcx.hir().get_parent_item(hir_id);
         let parent_item = tcx.hir().expect_item(parent_id);
         if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = parent_item.kind {
             tcx.sess
index 99fddcb00ceca52b2a2994e8c16a174d4b5d8a62..403310a865ad8755ba62aecd2444b30305ba5cdb 100644 (file)
@@ -6,18 +6,19 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{HirId, Node};
 use rustc_middle::hir::map::Map;
-use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
+use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt, TypeFoldable, TypeFolder};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
 use super::ItemCtxt;
-use super::{bad_placeholder_type, is_suggestable_infer_ty};
+use super::{bad_placeholder, is_suggestable_infer_ty};
 
 /// Computes the relevant generic parameter for a potential generic const argument.
 ///
 /// This should be called using the query `tcx.opt_const_param_of`.
+#[instrument(level = "debug", skip(tcx))]
 pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
     // FIXME(generic_arg_infer): allow for returning DefIds of inference of
     // GenericArg::Infer below. This may require a change where GenericArg::Infer has some flag
@@ -25,231 +26,228 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
     use hir::*;
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
-    if let Node::AnonConst(_) = tcx.hir().get(hir_id) {
-        let parent_node_id = tcx.hir().get_parent_node(hir_id);
-        let parent_node = tcx.hir().get(parent_node_id);
+    match tcx.hir().get(hir_id) {
+        Node::AnonConst(_) => (),
+        _ => return None,
+    };
 
-        match parent_node {
-            // This match arm is for when the def_id appears in a GAT whose
-            // path can't be resolved without typechecking e.g.
-            //
-            // trait Foo {
-            //   type Assoc<const N: usize>;
-            //   fn foo() -> Self::Assoc<3>;
-            // }
-            //
-            // In the above code we would call this query with the def_id of 3 and
-            // the parent_node we match on would be the hir node for Self::Assoc<3>
-            //
-            // `Self::Assoc<3>` cant be resolved without typchecking here as we
-            // didnt write <Self as Foo>::Assoc<3>. If we did then another match
-            // arm would handle this.
-            //
-            // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
-            Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
-                // Find the Item containing the associated type so we can create an ItemCtxt.
-                // Using the ItemCtxt convert the HIR for the unresolved assoc type into a
-                // ty which is a fully resolved projection.
-                // For the code example above, this would mean converting Self::Assoc<3>
-                // into a ty::Projection(<Self as Foo>::Assoc<3>)
-                let item_hir_id = tcx
-                    .hir()
-                    .parent_iter(hir_id)
-                    .filter(|(_, node)| matches!(node, Node::Item(_)))
-                    .map(|(id, _)| id)
-                    .next()
-                    .unwrap();
-                let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
-                let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
-                let ty = item_ctxt.ast_ty_to_ty(hir_ty);
-
-                // Iterate through the generics of the projection to find the one that corresponds to
-                // the def_id that this query was called with. We filter to only const args here as a
-                // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
-                // but it can't hurt to be safe ^^
-                if let ty::Projection(projection) = ty.kind() {
-                    let generics = tcx.generics_of(projection.item_def_id);
-
-                    let arg_index = segment
-                        .args
-                        .and_then(|args| {
-                            args.args
-                                .iter()
-                                .filter(|arg| arg.is_const())
-                                .position(|arg| arg.id() == hir_id)
-                        })
-                        .unwrap_or_else(|| {
-                            bug!("no arg matching AnonConst in segment");
-                        });
+    let parent_node_id = tcx.hir().get_parent_node(hir_id);
+    let parent_node = tcx.hir().get(parent_node_id);
 
-                    return generics
-                        .params
-                        .iter()
-                        .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
-                        .nth(arg_index)
-                        .map(|param| param.def_id);
-                }
-
-                // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
-                tcx.sess.delay_span_bug(
-                    tcx.def_span(def_id),
-                    "unexpected non-GAT usage of an anon const",
-                );
-                return None;
-            }
-            Node::Expr(&Expr {
-                kind:
-                    ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
-                ..
-            }) => {
-                let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
-                let tables = tcx.typeck(body_owner);
-                // This may fail in case the method/path does not actually exist.
-                // As there is no relevant param for `def_id`, we simply return
-                // `None` here.
-                let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?;
-                let idx = segment
+    let (generics, arg_idx) = match parent_node {
+        // This match arm is for when the def_id appears in a GAT whose
+        // path can't be resolved without typechecking e.g.
+        //
+        // trait Foo {
+        //   type Assoc<const N: usize>;
+        //   fn foo() -> Self::Assoc<3>;
+        // }
+        //
+        // In the above code we would call this query with the def_id of 3 and
+        // the parent_node we match on would be the hir node for Self::Assoc<3>
+        //
+        // `Self::Assoc<3>` cant be resolved without typchecking here as we
+        // didnt write <Self as Foo>::Assoc<3>. If we did then another match
+        // arm would handle this.
+        //
+        // I believe this match arm is only needed for GAT but I am not 100% sure - BoxyUwU
+        Node::Ty(hir_ty @ Ty { kind: TyKind::Path(QPath::TypeRelative(_, segment)), .. }) => {
+            // Find the Item containing the associated type so we can create an ItemCtxt.
+            // Using the ItemCtxt convert the HIR for the unresolved assoc type into a
+            // ty which is a fully resolved projection.
+            // For the code example above, this would mean converting Self::Assoc<3>
+            // into a ty::Projection(<Self as Foo>::Assoc<3>)
+            let item_hir_id = tcx
+                .hir()
+                .parent_iter(hir_id)
+                .filter(|(_, node)| matches!(node, Node::Item(_)))
+                .map(|(id, _)| id)
+                .next()
+                .unwrap();
+            let item_did = tcx.hir().local_def_id(item_hir_id).to_def_id();
+            let item_ctxt = &ItemCtxt::new(tcx, item_did) as &dyn crate::astconv::AstConv<'_>;
+            let ty = item_ctxt.ast_ty_to_ty(hir_ty);
+
+            // Iterate through the generics of the projection to find the one that corresponds to
+            // the def_id that this query was called with. We filter to only const args here as a
+            // precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
+            // but it can't hurt to be safe ^^
+            if let ty::Projection(projection) = ty.kind() {
+                let generics = tcx.generics_of(projection.item_def_id);
+
+                let arg_index = segment
                     .args
                     .and_then(|args| {
                         args.args
                             .iter()
-                            .filter(|arg| arg.is_const())
+                            .filter(|arg| arg.is_ty_or_const())
                             .position(|arg| arg.id() == hir_id)
                     })
                     .unwrap_or_else(|| {
                         bug!("no arg matching AnonConst in segment");
                     });
 
-                tcx.generics_of(type_dependent_def)
-                    .params
-                    .iter()
-                    .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
-                    .nth(idx)
-                    .map(|param| param.def_id)
+                (generics, arg_index)
+            } else {
+                // I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
+                tcx.sess.delay_span_bug(
+                    tcx.def_span(def_id),
+                    "unexpected non-GAT usage of an anon const",
+                );
+                return None;
             }
+        }
+        Node::Expr(&Expr {
+            kind:
+                ExprKind::MethodCall(segment, ..) | ExprKind::Path(QPath::TypeRelative(_, segment)),
+            ..
+        }) => {
+            let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
+            let tables = tcx.typeck(body_owner);
+            // This may fail in case the method/path does not actually exist.
+            // As there is no relevant param for `def_id`, we simply return
+            // `None` here.
+            let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?;
+            let idx = segment
+                .args
+                .and_then(|args| {
+                    args.args
+                        .iter()
+                        .filter(|arg| arg.is_ty_or_const())
+                        .position(|arg| arg.id() == hir_id)
+                })
+                .unwrap_or_else(|| {
+                    bug!("no arg matching AnonConst in segment");
+                });
 
-            Node::Ty(&Ty { kind: TyKind::Path(_), .. })
-            | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
-            | Node::TraitRef(..)
-            | Node::Pat(_) => {
-                let path = match parent_node {
-                    Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
-                    | Node::TraitRef(&TraitRef { path, .. }) => &*path,
-                    Node::Expr(&Expr {
-                        kind:
-                            ExprKind::Path(QPath::Resolved(_, path))
-                            | ExprKind::Struct(&QPath::Resolved(_, path), ..),
-                        ..
-                    }) => {
-                        let body_owner =
-                            tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
-                        let _tables = tcx.typeck(body_owner);
-                        &*path
-                    }
-                    Node::Pat(pat) => {
-                        if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
-                            path
-                        } else {
-                            tcx.sess.delay_span_bug(
-                                tcx.def_span(def_id),
-                                &format!(
-                                    "unable to find const parent for {} in pat {:?}",
-                                    hir_id, pat
-                                ),
-                            );
-                            return None;
-                        }
-                    }
-                    _ => {
-                        tcx.sess.delay_span_bug(
-                            tcx.def_span(def_id),
-                            &format!("unexpected const parent path {:?}", parent_node),
-                        );
-                        return None;
-                    }
-                };
-
-                // We've encountered an `AnonConst` in some path, so we need to
-                // figure out which generic parameter it corresponds to and return
-                // the relevant type.
-                let filtered = path
-                    .segments
-                    .iter()
-                    .filter_map(|seg| seg.args.map(|args| (args.args, seg)))
-                    .find_map(|(args, seg)| {
-                        args.iter()
-                            .filter(|arg| arg.is_const())
-                            .position(|arg| arg.id() == hir_id)
-                            .map(|index| (index, seg))
-                    });
-                let (arg_index, segment) = match filtered {
-                    None => {
-                        tcx.sess.delay_span_bug(
-                            tcx.def_span(def_id),
-                            "no arg matching AnonConst in path",
-                        );
-                        return None;
-                    }
-                    Some(inner) => inner,
-                };
-
-                // Try to use the segment resolution if it is valid, otherwise we
-                // default to the path resolution.
-                let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
-                use def::CtorOf;
-                let generics = match res {
-                    Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx.generics_of(
-                        tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap(),
-                    ),
-                    Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
-                        tcx.generics_of(tcx.parent(def_id).unwrap())
-                    }
-                    // Other `DefKind`s don't have generics and would ICE when calling
-                    // `generics_of`.
-                    Res::Def(
-                        DefKind::Struct
-                        | DefKind::Union
-                        | DefKind::Enum
-                        | DefKind::Trait
-                        | DefKind::OpaqueTy
-                        | DefKind::TyAlias
-                        | DefKind::ForeignTy
-                        | DefKind::TraitAlias
-                        | DefKind::AssocTy
-                        | DefKind::Fn
-                        | DefKind::AssocFn
-                        | DefKind::AssocConst
-                        | DefKind::Impl,
-                        def_id,
-                    ) => tcx.generics_of(def_id),
-                    Res::Err => {
-                        tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err");
-                        return None;
-                    }
-                    _ => {
-                        // If the user tries to specify generics on a type that does not take them,
-                        // e.g. `usize<T>`, we may hit this branch, in which case we treat it as if
-                        // no arguments have been passed. An error should already have been emitted.
+            (tcx.generics_of(type_dependent_def), idx)
+        }
+
+        Node::Ty(&Ty { kind: TyKind::Path(_), .. })
+        | Node::Expr(&Expr { kind: ExprKind::Path(_) | ExprKind::Struct(..), .. })
+        | Node::TraitRef(..)
+        | Node::Pat(_) => {
+            let path = match parent_node {
+                Node::Ty(&Ty { kind: TyKind::Path(QPath::Resolved(_, path)), .. })
+                | Node::TraitRef(&TraitRef { path, .. }) => &*path,
+                Node::Expr(&Expr {
+                    kind:
+                        ExprKind::Path(QPath::Resolved(_, path))
+                        | ExprKind::Struct(&QPath::Resolved(_, path), ..),
+                    ..
+                }) => {
+                    let body_owner = tcx.hir().local_def_id(tcx.hir().enclosing_body_owner(hir_id));
+                    let _tables = tcx.typeck(body_owner);
+                    &*path
+                }
+                Node::Pat(pat) => {
+                    if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
+                        path
+                    } else {
                         tcx.sess.delay_span_bug(
                             tcx.def_span(def_id),
-                            &format!("unexpected anon const res {:?} in path: {:?}", res, path),
+                            &format!("unable to find const parent for {} in pat {:?}", hir_id, pat),
                         );
                         return None;
                     }
-                };
-
-                generics
-                    .params
-                    .iter()
-                    .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
-                    .nth(arg_index)
-                    .map(|param| param.def_id)
+                }
+                _ => {
+                    tcx.sess.delay_span_bug(
+                        tcx.def_span(def_id),
+                        &format!("unexpected const parent path {:?}", parent_node),
+                    );
+                    return None;
+                }
+            };
+
+            // We've encountered an `AnonConst` in some path, so we need to
+            // figure out which generic parameter it corresponds to and return
+            // the relevant type.
+            let filtered = path
+                .segments
+                .iter()
+                .filter_map(|seg| seg.args.map(|args| (args.args, seg)))
+                .find_map(|(args, seg)| {
+                    args.iter()
+                        .filter(|arg| arg.is_ty_or_const())
+                        .position(|arg| arg.id() == hir_id)
+                        .map(|index| (index, seg))
+                });
+            let (arg_index, segment) = match filtered {
+                None => {
+                    tcx.sess
+                        .delay_span_bug(tcx.def_span(def_id), "no arg matching AnonConst in path");
+                    return None;
+                }
+                Some(inner) => inner,
+            };
+
+            // Try to use the segment resolution if it is valid, otherwise we
+            // default to the path resolution.
+            let res = segment.res.filter(|&r| r != Res::Err).unwrap_or(path.res);
+            use def::CtorOf;
+            let generics = match res {
+                Res::Def(DefKind::Ctor(CtorOf::Variant, _), def_id) => tcx
+                    .generics_of(tcx.parent(def_id).and_then(|def_id| tcx.parent(def_id)).unwrap()),
+                Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Struct, _), def_id) => {
+                    tcx.generics_of(tcx.parent(def_id).unwrap())
+                }
+                // Other `DefKind`s don't have generics and would ICE when calling
+                // `generics_of`.
+                Res::Def(
+                    DefKind::Struct
+                    | DefKind::Union
+                    | DefKind::Enum
+                    | DefKind::Trait
+                    | DefKind::OpaqueTy
+                    | DefKind::TyAlias
+                    | DefKind::ForeignTy
+                    | DefKind::TraitAlias
+                    | DefKind::AssocTy
+                    | DefKind::Fn
+                    | DefKind::AssocFn
+                    | DefKind::AssocConst
+                    | DefKind::Impl,
+                    def_id,
+                ) => tcx.generics_of(def_id),
+                Res::Err => {
+                    tcx.sess.delay_span_bug(tcx.def_span(def_id), "anon const with Res::Err");
+                    return None;
+                }
+                _ => {
+                    // If the user tries to specify generics on a type that does not take them,
+                    // e.g. `usize<T>`, we may hit this branch, in which case we treat it as if
+                    // no arguments have been passed. An error should already have been emitted.
+                    tcx.sess.delay_span_bug(
+                        tcx.def_span(def_id),
+                        &format!("unexpected anon const res {:?} in path: {:?}", res, path),
+                    );
+                    return None;
+                }
+            };
+
+            (generics, arg_index)
+        }
+        _ => return None,
+    };
+
+    debug!(?parent_node);
+    debug!(?generics, ?arg_idx);
+    generics
+        .params
+        .iter()
+        .filter(|param| param.kind.is_ty_or_const())
+        .nth(match generics.has_self && generics.parent.is_none() {
+            true => arg_idx + 1,
+            false => arg_idx,
+        })
+        .and_then(|param| match param.kind {
+            ty::GenericParamDefKind::Const { .. } => {
+                debug!(?param);
+                Some(param.def_id)
             }
             _ => None,
-        }
-    } else {
-        None
-    }
+        })
 }
 
 fn get_path_containing_arg_in_pat<'hir>(
@@ -280,32 +278,6 @@ fn get_path_containing_arg_in_pat<'hir>(
     arg_path
 }
 
-pub(super) fn default_anon_const_substs(tcx: TyCtxt<'_>, def_id: DefId) -> SubstsRef<'_> {
-    let generics = tcx.generics_of(def_id);
-    if let Some(parent) = generics.parent {
-        // This is the reason we bother with having optional anon const substs.
-        //
-        // In the future the substs of an anon const will depend on its parents predicates
-        // at which point eagerly looking at them will cause a query cycle.
-        //
-        // So for now this is only an assurance that this approach won't cause cycle errors in
-        // the future.
-        let _cycle_check = tcx.predicates_of(parent);
-    }
-
-    let substs = InternalSubsts::identity_for_item(tcx, def_id);
-    // We only expect substs with the following type flags as default substs.
-    //
-    // Getting this wrong can lead to ICE and unsoundness, so we assert it here.
-    for arg in substs.iter() {
-        let allowed_flags = ty::TypeFlags::MAY_NEED_DEFAULT_CONST_SUBSTS
-            | ty::TypeFlags::STILL_FURTHER_SPECIALIZABLE
-            | ty::TypeFlags::HAS_ERROR;
-        assert!(!arg.has_type_flags(!allowed_flags));
-    }
-    substs
-}
-
 pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
     let def_id = def_id.expect_local();
     use rustc_hir::*;
@@ -350,7 +322,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                 }
             }
             ImplItemKind::TyAlias(ty) => {
-                if tcx.impl_trait_ref(tcx.hir().get_parent_did(hir_id).to_def_id()).is_none() {
+                if tcx.impl_trait_ref(tcx.hir().get_parent_item(hir_id)).is_none() {
                     check_feature_inherent_assoc_ty(tcx, item.span);
                 }
 
@@ -460,7 +432,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
 
         Node::Ctor(&ref def) | Node::Variant(Variant { data: ref def, .. }) => match *def {
             VariantData::Unit(..) | VariantData::Struct(..) => {
-                tcx.type_of(tcx.hir().get_parent_did(hir_id).to_def_id())
+                tcx.type_of(tcx.hir().get_parent_item(hir_id))
             }
             VariantData::Tuple(..) => {
                 let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
@@ -470,14 +442,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
 
         Node::Field(field) => icx.to_ty(field.ty),
 
-        Node::Expr(&Expr { kind: ExprKind::Closure(.., gen), .. }) => {
-            let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
-            if let Some(movability) = gen {
-                tcx.mk_generator(def_id.to_def_id(), substs, movability)
-            } else {
-                tcx.mk_closure(def_id.to_def_id(), substs)
-            }
-        }
+        Node::Expr(&Expr { kind: ExprKind::Closure(..), .. }) => tcx.typeck(def_id).node_type(hir_id),
 
         Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
             // We defer to `type_of` of the corresponding parameter
@@ -490,7 +455,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
             match parent_node {
                 Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
                 | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
-                    if constant.hir_id == hir_id =>
+                    if constant.hir_id() == hir_id =>
                 {
                     tcx.types.usize
                 }
@@ -516,7 +481,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                 }
 
                 Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => tcx
-                    .adt_def(tcx.hir().get_parent_did(hir_id).to_def_id())
+                    .adt_def(tcx.hir().get_parent_item(hir_id))
                     .repr
                     .discr_type()
                     .to_ty(tcx),
@@ -788,7 +753,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             err.emit();
         }
         None => {
-            let mut diag = bad_placeholder_type(tcx, vec![span], kind);
+            let mut diag = bad_placeholder(tcx, "type", vec![span], kind);
 
             if !ty.references_error() {
                 let mut mk_nameable = MakeNameable::new(tcx);
index 88877ad78525a95ad7e24cee0411fafb15beff32..1095290132347c85c570b1c0fa04898d896257f9 100644 (file)
@@ -27,13 +27,12 @@ fn from(param: ty::ParamConst) -> Self {
 
 /// Returns the set of parameters constrained by the impl header.
 pub fn parameters_for_impl<'tcx>(
-    tcx: TyCtxt<'tcx>,
     impl_self_ty: Ty<'tcx>,
     impl_trait_ref: Option<ty::TraitRef<'tcx>>,
 ) -> FxHashSet<Parameter> {
     let vec = match impl_trait_ref {
-        Some(tr) => parameters_for(tcx, &tr, false),
-        None => parameters_for(tcx, &impl_self_ty, false),
+        Some(tr) => parameters_for(&tr, false),
+        None => parameters_for(&impl_self_ty, false),
     };
     vec.into_iter().collect()
 }
@@ -44,26 +43,20 @@ pub fn parameters_for_impl<'tcx>(
 /// of parameters whose values are needed in order to constrain `ty` - these
 /// differ, with the latter being a superset, in the presence of projections.
 pub fn parameters_for<'tcx>(
-    tcx: TyCtxt<'tcx>,
     t: &impl TypeFoldable<'tcx>,
     include_nonconstraining: bool,
 ) -> Vec<Parameter> {
-    let mut collector = ParameterCollector { tcx, parameters: vec![], include_nonconstraining };
+    let mut collector = ParameterCollector { parameters: vec![], include_nonconstraining };
     t.visit_with(&mut collector);
     collector.parameters
 }
 
-struct ParameterCollector<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct ParameterCollector {
     parameters: Vec<Parameter>,
     include_nonconstraining: bool,
 }
 
-impl<'tcx> TypeVisitor<'tcx> for ParameterCollector<'tcx> {
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.tcx)
-    }
-
+impl<'tcx> TypeVisitor<'tcx> for ParameterCollector {
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match *t.kind() {
             ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => {
@@ -205,12 +198,12 @@ pub fn setup_constraining_predicates<'tcx>(
                 //     `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
                 // Then the projection only applies if `T` is known, but it still
                 // does not determine `U`.
-                let inputs = parameters_for(tcx, &projection.projection_ty, true);
+                let inputs = parameters_for(&projection.projection_ty, true);
                 let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
                 if !relies_only_on_inputs {
                     continue;
                 }
-                input_parameters.extend(parameters_for(tcx, &projection.ty, false));
+                input_parameters.extend(parameters_for(&projection.ty, false));
             } else {
                 continue;
             }
index 32b4018f626b27f9cdb4eab668d81560f0e31baf..352cdefc0b47b415a5e26974a7e6c1be84c5d4c4 100644 (file)
@@ -715,13 +715,14 @@ fn upvar_is_local_variable<'tcx>(
 
         debug!("walk_captures({:?})", closure_expr);
 
-        let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id).to_def_id();
-        let upvars = self.tcx().upvars_mentioned(self.body_owner);
+        let tcx = self.tcx();
+        let closure_def_id = tcx.hir().local_def_id(closure_expr.hir_id).to_def_id();
+        let upvars = tcx.upvars_mentioned(self.body_owner);
 
         // For purposes of this function, generator and closures are equivalent.
         let body_owner_is_closure = matches!(
-            self.tcx().type_of(self.body_owner.to_def_id()).kind(),
-            ty::Closure(..) | ty::Generator(..)
+            tcx.hir().body_owner_kind(tcx.hir().local_def_id_to_hir_id(self.body_owner)),
+            hir::BodyOwnerKind::Closure,
         );
 
         // If we have a nested closure, we want to include the fake reads present in the nested closure.
@@ -795,14 +796,14 @@ fn upvar_is_local_variable<'tcx>(
                     );
 
                     match capture_info.capture_kind {
-                        ty::UpvarCapture::ByValue(_) => {
+                        ty::UpvarCapture::ByValue => {
                             self.delegate_consume(&place_with_id, place_with_id.hir_id);
                         }
                         ty::UpvarCapture::ByRef(upvar_borrow) => {
                             self.delegate.borrow(
                                 &place_with_id,
                                 place_with_id.hir_id,
-                                upvar_borrow.kind,
+                                upvar_borrow,
                             );
                         }
                     }
index ae6321de7f2d5d34aa8546063a03a44135eca0fe..16049089151c40f44d9239f22c5d8d5c74a13f91 100644 (file)
@@ -117,7 +117,7 @@ fn enforce_impl_params_are_constrained(
     let impl_predicates = tcx.predicates_of(impl_def_id);
     let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
 
-    let mut input_parameters = cgp::parameters_for_impl(tcx, impl_self_ty, impl_trait_ref);
+    let mut input_parameters = cgp::parameters_for_impl(impl_self_ty, impl_trait_ref);
     cgp::identify_constrained_generic_params(
         tcx,
         impl_predicates,
@@ -134,7 +134,7 @@ fn enforce_impl_params_are_constrained(
             match item.kind {
                 ty::AssocKind::Type => {
                     if item.defaultness.has_value() {
-                        cgp::parameters_for(tcx, &tcx.type_of(def_id), true)
+                        cgp::parameters_for(&tcx.type_of(def_id), true)
                     } else {
                         Vec::new()
                     }
index 4fb422c801b1def85f9c2ae9609eed393584704b..6296f2ab32a5236d26e77d967de9f52cf7a1f40b 100644 (file)
@@ -206,15 +206,15 @@ fn unconstrained_parent_impl_substs<'tcx>(
                 continue;
             }
 
-            unconstrained_parameters.extend(cgp::parameters_for(tcx, &projection_ty, true));
+            unconstrained_parameters.extend(cgp::parameters_for(&projection_ty, true));
 
-            for param in cgp::parameters_for(tcx, &projected_ty, false) {
+            for param in cgp::parameters_for(&projected_ty, false) {
                 if !unconstrained_parameters.contains(&param) {
                     constrained_params.insert(param.0);
                 }
             }
 
-            unconstrained_parameters.extend(cgp::parameters_for(tcx, &projected_ty, true));
+            unconstrained_parameters.extend(cgp::parameters_for(&projected_ty, true));
         }
     }
 
@@ -248,7 +248,7 @@ fn check_duplicate_params<'tcx>(
     parent_substs: &Vec<GenericArg<'tcx>>,
     span: Span,
 ) {
-    let mut base_params = cgp::parameters_for(tcx, parent_substs, true);
+    let mut base_params = cgp::parameters_for(parent_substs, true);
     base_params.sort_by_key(|param| param.0);
     if let (_, [duplicate, ..]) = base_params.partition_dedup() {
         let param = impl1_substs[duplicate.0 as usize];
@@ -376,7 +376,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
     match predicate.kind().skip_binder() {
         // Global predicates are either always true or always false, so we
         // are fine to specialize on.
-        _ if predicate.is_global(tcx) => (),
+        _ if predicate.is_global() => (),
         // We allow specializing on explicitly marked traits with no associated
         // items.
         ty::PredicateKind::Trait(ty::TraitPredicate {
index 24e427f4bcff90f23c4ea51a06ab51c20047b228..6a9f154844a5752ab32cd328cbab24f6ee588dde 100644 (file)
@@ -543,8 +543,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
     // In case there are any projections, etc., find the "environment"
     // def-ID that will be used to determine the traits/predicates in
     // scope.  This is derived from the enclosing item-like thing.
-    let env_node_id = tcx.hir().get_parent_item(hir_ty.hir_id);
-    let env_def_id = tcx.hir().local_def_id(env_node_id);
+    let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
     <dyn AstConv<'_>>::ast_ty_to_ty(&item_cx, hir_ty)
 }
@@ -557,8 +556,7 @@ pub fn hir_trait_to_predicates<'tcx>(
     // In case there are any projections, etc., find the "environment"
     // def-ID that will be used to determine the traits/predicates in
     // scope.  This is derived from the enclosing item-like thing.
-    let env_hir_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
-    let env_def_id = tcx.hir().local_def_id(env_hir_id);
+    let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
     let mut bounds = Bounds::default();
     let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref(
index 86d712e2d792258ec4372bc14f6610b9266c29ad..89f0bd8d4215440424d990b78e0e7ea12328bed0 100644 (file)
@@ -114,18 +114,7 @@ fn insert_required_predicates_to_be_wf<'tcx>(
     required_predicates: &mut RequiredPredicates<'tcx>,
     explicit_map: &mut ExplicitPredicatesMap<'tcx>,
 ) {
-    // We must not look into the default substs of consts
-    // as computing those depends on the results of `predicates_of`.
-    //
-    // Luckily the only types contained in default substs are type
-    // parameters which don't matter here.
-    //
-    // FIXME(adt_const_params): Once complex const parameter types
-    // are allowed, this might be incorrect. I think that we will still be
-    // fine, as all outlives relations of the const param types should also
-    // be part of the adt containing it, but we should still both update the
-    // documentation and add some tests for this.
-    for arg in field_ty.walk_ignoring_default_const_substs() {
+    for arg in field_ty.walk() {
         let ty = match arg.unpack() {
             GenericArgKind::Type(ty) => ty,
 
@@ -317,7 +306,7 @@ pub fn check_explicit_predicates<'tcx>(
         // 'b`.
         if let Some(self_ty) = ignored_self_ty {
             if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() {
-                if ty.walk(tcx).any(|arg| arg == self_ty.into()) {
+                if ty.walk().any(|arg| arg == self_ty.into()) {
                     debug!("skipping self ty = {:?}", &ty);
                     continue;
                 }
index eb3853b6b3dee9e85eb26a08318607b5e008babb..78a9cb33fbac5e95504ef1176165abc19ddf3812 100644 (file)
@@ -35,8 +35,7 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: DefId) -> &[(ty::Predicate
             //        parent of generics returned by `generics_of`
             //
             // In the above code we want the anon const to have predicates in its param env for `'b: 'a`
-            let item_id = tcx.hir().get_parent_item(id);
-            let item_def_id = tcx.hir().local_def_id(item_id).to_def_id();
+            let item_def_id = tcx.hir().get_parent_item(id);
             // In the above code example we would be calling `inferred_outlives_of(Foo)` here
             return tcx.inferred_outlives_of(item_def_id);
         }
index 33c27ce86ddb5f8357f2a42a763b9559afbb3932..b2b607a2ffc2899453867cfc8cc442a0f194b2cc 100644 (file)
@@ -405,8 +405,7 @@ fn add_constraints_from_const(
 
         match &val.val {
             ty::ConstKind::Unevaluated(uv) => {
-                let substs = uv.substs(self.tcx());
-                self.add_constraints_from_invariant_substs(current, substs, variance);
+                self.add_constraints_from_invariant_substs(current, uv.substs, variance);
             }
             _ => {}
         }
index d7f9df668bf36d08c3b24775bbaac2a51fd7f6eb..36fbfc21ff58c4b1282de4b7cbe3700b4c311d23 100644 (file)
@@ -86,7 +86,7 @@ pub fn determine_parameters_to_be_inferred<'a, 'tcx>(
 
 fn lang_items(tcx: TyCtxt<'_>) -> Vec<(hir::HirId, Vec<ty::Variance>)> {
     let lang_items = tcx.lang_items();
-    let all = vec![
+    let all = [
         (lang_items.phantom_data(), vec![ty::Covariant]),
         (lang_items.unsafe_cell_type(), vec![ty::Invariant]),
     ];
index b3ff0fd0a313c583854ec492f99b561f3bca3431..265020209eb12742c64b4c8c48a98856bc55ed7b 100644 (file)
@@ -6,7 +6,7 @@ repository = "https://github.com/rust-lang/rust.git"
 description = "The Rust core allocation and collections library"
 autotests = false
 autobenches = false
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 core = { path = "../core" }
index 66ef92558d8b563c4d149fe5966c54ad60a657ad..d075658f51a3e7b3fb7c46df8619787e77b6b68b 100644 (file)
@@ -323,17 +323,21 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
 
 #[cfg_attr(not(test), lang = "box_free")]
 #[inline]
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
 // This signature has to be the same as `Box`, otherwise an ICE will happen.
 // When an additional parameter to `Box` is added (like `A: Allocator`), this has to be added here as
 // well.
 // For example if `Box` is changed to  `struct Box<T: ?Sized, A: Allocator>(Unique<T>, A)`,
 // this function has to be changed to `fn box_free<T: ?Sized, A: Allocator>(Unique<T>, A)` as well.
-pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A) {
+pub(crate) const unsafe fn box_free<T: ?Sized, A: ~const Allocator + ~const Drop>(
+    ptr: Unique<T>,
+    alloc: A,
+) {
     unsafe {
         let size = size_of_val(ptr.as_ref());
         let align = min_align_of_val(ptr.as_ref());
         let layout = Layout::from_size_align_unchecked(size, align);
-        alloc.deallocate(ptr.cast().into(), layout)
+        alloc.deallocate(From::from(ptr.cast()), layout)
     }
 }
 
@@ -361,13 +365,22 @@ pub(crate) unsafe fn box_free<T: ?Sized, A: Allocator>(ptr: Unique<T>, alloc: A)
 /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
 /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
 #[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 fn handle_alloc_error(layout: Layout) -> ! {
-    unsafe {
-        __rust_alloc_error_handler(layout.size(), layout.align());
+pub const fn handle_alloc_error(layout: Layout) -> ! {
+    const fn ct_error(_: Layout) -> ! {
+        panic!("allocation failed");
     }
+
+    fn rt_error(layout: Layout) -> ! {
+        unsafe {
+            __rust_alloc_error_handler(layout.size(), layout.align());
+        }
+    }
+
+    unsafe { core::intrinsics::const_eval_select((layout,), ct_error, rt_error) }
 }
 
 // For alloc test `std::alloc::handle_alloc_error` can be used directly.
index ab41f5646e5e50d3015c61bd796b59af69f2c7dc..aa7344ba405a988c31598701bcf7759940ea1e2f 100644 (file)
@@ -346,9 +346,13 @@ impl<T, A: Allocator> Box<T, A> {
     /// ```
     #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[must_use]
     #[inline]
-    pub fn new_in(x: T, alloc: A) -> Self {
+    pub const fn new_in(x: T, alloc: A) -> Self
+    where
+        A: ~const Allocator + ~const Drop,
+    {
         let mut boxed = Self::new_uninit_in(alloc);
         unsafe {
             boxed.as_mut_ptr().write(x);
@@ -372,8 +376,13 @@ pub fn new_in(x: T, alloc: A) -> Self {
     /// # Ok::<(), std::alloc::AllocError>(())
     /// ```
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError> {
+    pub const fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError>
+    where
+        T: ~const Drop,
+        A: ~const Allocator + ~const Drop,
+    {
         let mut boxed = Self::try_new_uninit_in(alloc)?;
         unsafe {
             boxed.as_mut_ptr().write(x);
@@ -402,10 +411,14 @@ pub fn try_new_in(x: T, alloc: A) -> Result<Self, AllocError> {
     /// assert_eq!(*five, 5)
     /// ```
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[cfg(not(no_global_oom_handling))]
     #[must_use]
     // #[unstable(feature = "new_uninit", issue = "63291")]
-    pub fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
+    pub const fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A>
+    where
+        A: ~const Allocator + ~const Drop,
+    {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
         // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable.
         // That would make code size bigger.
@@ -439,7 +452,11 @@ pub fn new_uninit_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
     /// ```
     #[unstable(feature = "allocator_api", issue = "32838")]
     // #[unstable(feature = "new_uninit", issue = "63291")]
-    pub fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> {
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+    pub const fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError>
+    where
+        A: ~const Allocator + ~const Drop,
+    {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
         let ptr = alloc.allocate(layout)?.cast();
         unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
@@ -466,10 +483,14 @@ pub fn try_new_uninit_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE
     ///
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[cfg(not(no_global_oom_handling))]
     // #[unstable(feature = "new_uninit", issue = "63291")]
     #[must_use]
-    pub fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
+    pub const fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A>
+    where
+        A: ~const Allocator + ~const Drop,
+    {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
         // NOTE: Prefer match over unwrap_or_else since closure sometimes not inlineable.
         // That would make code size bigger.
@@ -503,7 +524,11 @@ pub fn new_zeroed_in(alloc: A) -> Box<mem::MaybeUninit<T>, A> {
     /// [zeroed]: mem::MaybeUninit::zeroed
     #[unstable(feature = "allocator_api", issue = "32838")]
     // #[unstable(feature = "new_uninit", issue = "63291")]
-    pub fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError> {
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+    pub const fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocError>
+    where
+        A: ~const Allocator + ~const Drop,
+    {
         let layout = Layout::new::<mem::MaybeUninit<T>>();
         let ptr = alloc.allocate_zeroed(layout)?.cast();
         unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
@@ -513,20 +538,22 @@ pub fn try_new_zeroed_in(alloc: A) -> Result<Box<mem::MaybeUninit<T>, A>, AllocE
     /// `x` will be pinned in memory and unable to be moved.
     #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[must_use]
     #[inline(always)]
-    pub fn pin_in(x: T, alloc: A) -> Pin<Self>
+    pub const fn pin_in(x: T, alloc: A) -> Pin<Self>
     where
-        A: 'static,
+        A: 'static + ~const Allocator + ~const Drop,
     {
-        Self::new_in(x, alloc).into()
+        Self::into_pin(Self::new_in(x, alloc))
     }
 
     /// Converts a `Box<T>` into a `Box<[T]>`
     ///
     /// This conversion does not allocate on the heap and happens in place.
     #[unstable(feature = "box_into_boxed_slice", issue = "71582")]
-    pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> {
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+    pub const fn into_boxed_slice(boxed: Self) -> Box<[T], A> {
         let (raw, alloc) = Box::into_raw_with_allocator(boxed);
         unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) }
     }
@@ -543,8 +570,12 @@ pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> {
     /// assert_eq!(Box::into_inner(c), 5);
     /// ```
     #[unstable(feature = "box_into_inner", issue = "80437")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn into_inner(boxed: Self) -> T {
+    pub const fn into_inner(boxed: Self) -> T
+    where
+        Self: ~const Drop,
+    {
         *boxed
     }
 }
@@ -758,8 +789,9 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
     /// assert_eq!(*five, 5)
     /// ```
     #[unstable(feature = "new_uninit", issue = "63291")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub unsafe fn assume_init(self) -> Box<T, A> {
+    pub const unsafe fn assume_init(self) -> Box<T, A> {
         let (raw, alloc) = Box::into_raw_with_allocator(self);
         unsafe { Box::from_raw_in(raw as *mut T, alloc) }
     }
@@ -792,8 +824,9 @@ pub unsafe fn assume_init(self) -> Box<T, A> {
     /// }
     /// ```
     #[unstable(feature = "new_uninit", issue = "63291")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn write(mut boxed: Self, value: T) -> Box<T, A> {
+    pub const fn write(mut boxed: Self, value: T) -> Box<T, A> {
         unsafe {
             (*boxed).write(value);
             boxed.assume_init()
@@ -938,8 +971,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
     /// [memory layout]: self#memory-layout
     /// [`Layout`]: crate::Layout
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
+    pub const unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
         Box(unsafe { Unique::new_unchecked(raw) }, alloc)
     }
 
@@ -1035,8 +1069,9 @@ pub fn into_raw(b: Self) -> *mut T {
     ///
     /// [memory layout]: self#memory-layout
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
+    pub const fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
         let (leaked, alloc) = Box::into_unique(b);
         (leaked.as_ptr(), alloc)
     }
@@ -1046,9 +1081,10 @@ pub fn into_raw_with_allocator(b: Self) -> (*mut T, A) {
         issue = "none",
         reason = "use `Box::leak(b).into()` or `Unique::from(Box::leak(b))` instead"
     )]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
     #[doc(hidden)]
-    pub fn into_unique(b: Self) -> (Unique<T>, A) {
+    pub const fn into_unique(b: Self) -> (Unique<T>, A) {
         // Box is recognized as a "unique pointer" by Stacked Borrows, but internally it is a
         // raw pointer for the type system. Turning it directly into a raw pointer would not be
         // recognized as "releasing" the unique pointer to permit aliased raw accesses,
@@ -1064,8 +1100,9 @@ pub fn into_unique(b: Self) -> (Unique<T>, A) {
     /// to call it as `Box::allocator(&b)` instead of `b.allocator()`. This
     /// is so that there is no conflict with a method on the inner type.
     #[unstable(feature = "allocator_api", issue = "32838")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn allocator(b: &Self) -> &A {
+    pub const fn allocator(b: &Self) -> &A {
         &b.1
     }
 
@@ -1105,8 +1142,9 @@ pub fn allocator(b: &Self) -> &A {
     /// assert_eq!(*static_ref, [4, 2, 3]);
     /// ```
     #[stable(feature = "box_leak", since = "1.26.0")]
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
     #[inline]
-    pub fn leak<'a>(b: Self) -> &'a mut T
+    pub const fn leak<'a>(b: Self) -> &'a mut T
     where
         A: 'a,
     {
@@ -1119,7 +1157,8 @@ pub fn leak<'a>(b: Self) -> &'a mut T
     ///
     /// This is also available via [`From`].
     #[unstable(feature = "box_into_pin", issue = "62370")]
-    pub fn into_pin(boxed: Self) -> Pin<Self>
+    #[rustc_const_unstable(feature = "const_box", issue = "92521")]
+    pub const fn into_pin(boxed: Self) -> Pin<Self>
     where
         A: 'static,
     {
@@ -1131,7 +1170,8 @@ pub fn into_pin(boxed: Self) -> Pin<Self>
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> const Drop for Box<T, A> {
     fn drop(&mut self) {
         // FIXME: Do nothing, drop is currently performed by compiler.
     }
@@ -1341,7 +1381,8 @@ fn from(t: T) -> Self {
 }
 
 #[stable(feature = "pin", since = "1.33.0")]
-impl<T: ?Sized, A: Allocator> From<Box<T, A>> for Pin<Box<T, A>>
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const From<Box<T, A>> for Pin<Box<T, A>>
 where
     A: 'static,
 {
@@ -1720,7 +1761,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, A: Allocator> Deref for Box<T, A> {
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const Deref for Box<T, A> {
     type Target = T;
 
     fn deref(&self) -> &T {
@@ -1729,7 +1771,8 @@ fn deref(&self) -> &T {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, A: Allocator> DerefMut for Box<T, A> {
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const DerefMut for Box<T, A> {
     fn deref_mut(&mut self) -> &mut T {
         &mut **self
     }
@@ -1908,7 +1951,8 @@ fn as_mut(&mut self) -> &mut T {
  *  could have a method to project a Pin<T> from it.
  */
 #[stable(feature = "pin", since = "1.33.0")]
-impl<T: ?Sized, A: Allocator> Unpin for Box<T, A> where A: 'static {}
+#[rustc_const_unstable(feature = "const_box", issue = "92521")]
+impl<T: ?Sized, A: Allocator> const Unpin for Box<T, A> where A: 'static {}
 
 #[unstable(feature = "generator_trait", issue = "43122")]
 impl<G: ?Sized + Generator<R> + Unpin, R, A: Allocator> Generator<R> for Box<G, A>
index 199c05dc5df3e4e4471f2dcda41f772eb002e59b..62153efbb393baeeb89df1a8c251365457b686dc 100644 (file)
 use super::search::SearchResult::*;
 
 mod entry;
+
+#[stable(feature = "rust1", since = "1.0.0")]
 pub use entry::{Entry, OccupiedEntry, OccupiedError, VacantEntry};
+
 use Entry::*;
 
 /// Minimum number of elements in a node that is not a root.
index c95aeeaa605586abb9c138e7ae244083c1e55c2b..b39b5409ae44f0dfe39ea4f96ea93f024a4bc10b 100644 (file)
@@ -728,7 +728,7 @@ fn check<'a, L, R>(lhs: L, rhs: R)
 #[test]
 fn test_range_inclusive_max_value() {
     let max = usize::MAX;
-    let map: BTreeMap<_, _> = vec![(max, 0)].into_iter().collect();
+    let map: BTreeMap<_, _> = [(max, 0)].into_iter().collect();
 
     assert_eq!(map.range(max..=max).collect::<Vec<_>>(), &[(&max, &0)]);
 }
@@ -2128,7 +2128,7 @@ fn test_into_iter_drop_leak_height_1() {
 
 #[test]
 fn test_into_keys() {
-    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+    let vec = [(1, 'a'), (2, 'b'), (3, 'c')];
     let map: BTreeMap<_, _> = vec.into_iter().collect();
     let keys: Vec<_> = map.into_keys().collect();
 
index 075becfb7d11ab2934ef3a435558895df5d2b9d3..1259c53bfab153d9617f6d4488cc4eab939f6dec 100644 (file)
@@ -669,7 +669,7 @@ pub fn capacity(&self) -> usize {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut buf: VecDeque<i32> = vec![1].into_iter().collect();
+    /// let mut buf: VecDeque<i32> = [1].into_iter().collect();
     /// buf.reserve_exact(10);
     /// assert!(buf.capacity() >= 11);
     /// ```
@@ -692,7 +692,7 @@ pub fn reserve_exact(&mut self, additional: usize) {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut buf: VecDeque<i32> = vec![1].into_iter().collect();
+    /// let mut buf: VecDeque<i32> = [1].into_iter().collect();
     /// buf.reserve(10);
     /// assert!(buf.capacity() >= 11);
     /// ```
@@ -1153,7 +1153,7 @@ fn range_tail_head<R>(&self, range: R) -> (usize, usize)
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
+    /// let v: VecDeque<_> = [1, 2, 3].into_iter().collect();
     /// let range = v.range(2..).copied().collect::<VecDeque<_>>();
     /// assert_eq!(range, [3]);
     ///
@@ -1188,7 +1188,7 @@ pub fn range<R>(&self, range: R) -> Iter<'_, T>
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
+    /// let mut v: VecDeque<_> = [1, 2, 3].into_iter().collect();
     /// for v in v.range_mut(2..) {
     ///   *v *= 2;
     /// }
@@ -1235,7 +1235,7 @@ pub fn range_mut<R>(&mut self, range: R) -> IterMut<'_, T>
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut v: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
+    /// let mut v: VecDeque<_> = [1, 2, 3].into_iter().collect();
     /// let drained = v.drain(2..).collect::<VecDeque<_>>();
     /// assert_eq!(drained, [3]);
     /// assert_eq!(v, [1, 2]);
@@ -2025,7 +2025,7 @@ pub fn remove(&mut self, index: usize) -> Option<T> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut buf: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
+    /// let mut buf: VecDeque<_> = [1, 2, 3].into_iter().collect();
     /// let buf2 = buf.split_off(1);
     /// assert_eq!(buf, [1]);
     /// assert_eq!(buf2, [2, 3]);
@@ -2091,8 +2091,8 @@ pub fn split_off(&mut self, at: usize) -> Self
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut buf: VecDeque<_> = vec![1, 2].into_iter().collect();
-    /// let mut buf2: VecDeque<_> = vec![3, 4].into_iter().collect();
+    /// let mut buf: VecDeque<_> = [1, 2].into_iter().collect();
+    /// let mut buf2: VecDeque<_> = [3, 4].into_iter().collect();
     /// buf.append(&mut buf2);
     /// assert_eq!(buf, [1, 2, 3, 4]);
     /// assert_eq!(buf2, []);
index 600862c4224a100967514466a7eba81d14bf8cdc..1cbc2b65f4dbdad1910c8c5b74d178516f0c5a15 100644 (file)
 #![feature(array_windows)]
 #![feature(async_stream)]
 #![feature(coerce_unsized)]
+#![cfg_attr(not(no_global_oom_handling), feature(const_alloc_error))]
+#![feature(const_box)]
 #![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))]
 #![feature(const_cow_is_borrowed)]
+#![feature(const_convert)]
+#![feature(const_size_of_val)]
+#![feature(const_align_of_val)]
+#![feature(const_ptr_read)]
+#![feature(const_maybe_uninit_write)]
+#![feature(const_maybe_uninit_as_mut_ptr)]
+#![feature(const_refs_to_cell)]
 #![feature(core_intrinsics)]
+#![feature(const_eval_select)]
+#![feature(const_pin)]
 #![feature(dispatch_from_dyn)]
 #![feature(exact_size_is_empty)]
 #![feature(extend_one)]
 #![feature(inplace_iteration)]
 #![feature(iter_advance_by)]
 #![feature(layout_for_ptr)]
-#![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_slice)]
 #![cfg_attr(test, feature(new_uninit))]
 #![feature(nonnull_slice_from_raw_parts)]
 #![feature(box_syntax)]
 #![feature(cfg_sanitize)]
 #![feature(cfg_target_has_atomic)]
+#![feature(const_deref)]
 #![feature(const_fn_trait_bound)]
+#![feature(const_mut_refs)]
+#![feature(const_ptr_write)]
+#![feature(const_precise_live_drops)]
 #![feature(const_trait_impl)]
+#![feature(const_try)]
 #![cfg_attr(bootstrap, feature(destructuring_assignment))]
 #![feature(dropck_eyepatch)]
 #![feature(exclusive_range_pattern)]
index ae730be0d25a57155e6e2cc8cf99bec1e9d902ae..8853577371ad6d7dd62e1d65bba4c851eea5bbc6 100644 (file)
@@ -892,7 +892,7 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
             //    performance than with the 2nd method.
             //
             // All methods were benchmarked, and the 3rd showed best results. So we chose that one.
-            let mut tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
+            let tmp = mem::ManuallyDrop::new(ptr::read(&v[0]));
 
             // Intermediate state of the insertion process is always tracked by `hole`, which
             // serves two purposes:
@@ -904,7 +904,7 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
             // If `is_less` panics at any point during the process, `hole` will get dropped and
             // fill the hole in `v` with `tmp`, thus ensuring that `v` still holds every object it
             // initially held exactly once.
-            let mut hole = InsertionHole { src: &mut *tmp, dest: &mut v[1] };
+            let mut hole = InsertionHole { src: &*tmp, dest: &mut v[1] };
             ptr::copy_nonoverlapping(&v[1], &mut v[0], 1);
 
             for i in 2..v.len() {
@@ -920,7 +920,7 @@ fn insert_head<T, F>(v: &mut [T], is_less: &mut F)
 
     // When dropped, copies from `src` into `dest`.
     struct InsertionHole<T> {
-        src: *mut T,
+        src: *const T,
         dest: *mut T,
     }
 
index b151842458d355789feaac777ac36da32be195b2..7c0faf0659a2cd0c042364dccf8cd246b2abf0ce 100644 (file)
@@ -1062,7 +1062,7 @@ pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>
     ///     let mut output = String::new();
     ///
     ///     // Pre-reserve the memory, exiting if we can't
-    ///     output.try_reserve(data.len())?;
+    ///     output.try_reserve_exact(data.len())?;
     ///
     ///     // Now we know this can't OOM in the middle of our complex work
     ///     output.push_str(data);
index 18e191f2b59a28db44c2a045c1fae9da8d94bf85..f985fb78465b9a459ce72547e61123a521c793cc 100644 (file)
@@ -125,7 +125,7 @@ fn as_ref(&self) -> &[T] {
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<T: Send, A: Allocator + Send> Send for IntoIter<T, A> {}
 #[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync, A: Allocator> Sync for IntoIter<T, A> {}
+unsafe impl<T: Sync, A: Allocator + Sync> Sync for IntoIter<T, A> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, A: Allocator> Iterator for IntoIter<T, A> {
index fffdc2c3ac09d234e25defd6d2da3dd3842dd26c..78f989e730d2474e41b9f7ab80135cdbfb026275 100644 (file)
 #[cfg(not(no_global_oom_handling))]
 mod spec_extend;
 
-/// A contiguous growable array type, written as `Vec<T>` and pronounced 'vector'.
+/// A contiguous growable array type, written as `Vec<T>`, short for 'vector'.
 ///
 /// # Examples
 ///
@@ -2277,16 +2277,6 @@ fn last(self) -> T {
     }
 }
 
-struct ExtendDefault;
-impl<T: Default> ExtendWith<T> for ExtendDefault {
-    fn next(&mut self) -> T {
-        Default::default()
-    }
-    fn last(self) -> T {
-        Default::default()
-    }
-}
-
 struct ExtendFunc<F>(F);
 impl<T, F: FnMut() -> T> ExtendWith<T> for ExtendFunc<F> {
     fn next(&mut self) -> T {
@@ -3014,14 +3004,12 @@ fn from(s: &str) -> Vec<u8> {
     /// # Examples
     ///
     /// ```
-    /// use std::convert::TryInto;
     /// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3]));
     /// assert_eq!(<Vec<i32>>::new().try_into(), Ok([]));
     /// ```
     ///
     /// If the length doesn't match, the input comes back in `Err`:
     /// ```
-    /// use std::convert::TryInto;
     /// let r: Result<[i32; 4], _> = (0..10).collect::<Vec<_>>().try_into();
     /// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]));
     /// ```
@@ -3029,7 +3017,6 @@ fn from(s: &str) -> Vec<u8> {
     /// If you're fine with just getting a prefix of the `Vec<T>`,
     /// you can call [`.truncate(N)`](Vec::truncate) first.
     /// ```
-    /// use std::convert::TryInto;
     /// let mut v = String::from("hello world").into_bytes();
     /// v.sort();
     /// v.truncate(2);
index bfe66b2687ef4d89644a76df2901784bb35a7f19..0d7acfed8c6a1b36f0354714fa375f9de8efd9b4 100644 (file)
@@ -1,6 +1,7 @@
-use std::cell::Cell;
-use std::mem::MaybeUninit;
-use std::ptr::NonNull;
+use core::alloc::{AllocError, Allocator, Layout};
+use core::cell::Cell;
+use core::mem::MaybeUninit;
+use core::ptr::NonNull;
 
 #[test]
 fn uninitialized_zero_size_box() {
@@ -57,3 +58,110 @@ fn box_deref_lval() {
     x.set(1000);
     assert_eq!(x.get(), 1000);
 }
+
+pub struct ConstAllocator;
+
+unsafe impl const Allocator for ConstAllocator {
+    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+        match layout.size() {
+            0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
+            _ => unsafe {
+                let ptr = core::intrinsics::const_allocate(layout.size(), layout.align());
+                Ok(NonNull::new_unchecked(ptr as *mut [u8; 0] as *mut [u8]))
+            },
+        }
+    }
+
+    unsafe fn deallocate(&self, _ptr: NonNull<u8>, layout: Layout) {
+        match layout.size() {
+            0 => { /* do nothing */ }
+            _ => { /* do nothing too */ }
+        }
+    }
+
+    fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
+        let ptr = self.allocate(layout)?;
+        if layout.size() > 0 {
+            unsafe {
+                ptr.as_mut_ptr().write_bytes(0, layout.size());
+            }
+        }
+        Ok(ptr)
+    }
+
+    unsafe fn grow(
+        &self,
+        ptr: NonNull<u8>,
+        old_layout: Layout,
+        new_layout: Layout,
+    ) -> Result<NonNull<[u8]>, AllocError> {
+        debug_assert!(
+            new_layout.size() >= old_layout.size(),
+            "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
+        );
+
+        let new_ptr = self.allocate(new_layout)?;
+        if new_layout.size() > 0 {
+            new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), old_layout.size());
+            self.deallocate(ptr, old_layout);
+        }
+        Ok(new_ptr)
+    }
+
+    unsafe fn grow_zeroed(
+        &self,
+        ptr: NonNull<u8>,
+        old_layout: Layout,
+        new_layout: Layout,
+    ) -> Result<NonNull<[u8]>, AllocError> {
+        let new_ptr = self.grow(ptr, old_layout, new_layout)?;
+        if new_layout.size() > 0 {
+            let old_size = old_layout.size();
+            let new_size = new_layout.size();
+            let raw_ptr = new_ptr.as_mut_ptr();
+            raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
+        }
+        Ok(new_ptr)
+    }
+
+    unsafe fn shrink(
+        &self,
+        ptr: NonNull<u8>,
+        old_layout: Layout,
+        new_layout: Layout,
+    ) -> Result<NonNull<[u8]>, AllocError> {
+        debug_assert!(
+            new_layout.size() <= old_layout.size(),
+            "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
+        );
+
+        let new_ptr = self.allocate(new_layout)?;
+        if new_layout.size() > 0 {
+            new_ptr.as_mut_ptr().copy_from_nonoverlapping(ptr.as_ptr(), new_layout.size());
+            self.deallocate(ptr, old_layout);
+        }
+        Ok(new_ptr)
+    }
+
+    fn by_ref(&self) -> &Self
+    where
+        Self: Sized,
+    {
+        self
+    }
+}
+
+#[test]
+fn const_box() {
+    const VALUE: u32 = {
+        let mut boxed = Box::new_in(1u32, ConstAllocator);
+        assert!(*boxed == 1);
+
+        *boxed = 42;
+        assert!(*boxed == 42);
+
+        *boxed
+    };
+
+    assert!(VALUE == 42);
+}
index 68e48348b076e18e5489c3f9560b6fdcbe070931..7b8eeb90b5a80ff7980c9ab8461c2e13b5ad2019 100644 (file)
@@ -1,8 +1,19 @@
 #![feature(allocator_api)]
+#![feature(alloc_layout_extra)]
 #![feature(assert_matches)]
 #![feature(box_syntax)]
 #![feature(cow_is_borrowed)]
+#![feature(const_box)]
+#![feature(const_convert)]
 #![feature(const_cow_is_borrowed)]
+#![feature(const_heap)]
+#![feature(const_intrinsic_copy)]
+#![feature(const_mut_refs)]
+#![feature(const_nonnull_slice_from_raw_parts)]
+#![feature(const_ptr_offset)]
+#![feature(const_ptr_write)]
+#![feature(const_try)]
+#![feature(core_intrinsics)]
 #![feature(drain_filter)]
 #![feature(exact_size_is_empty)]
 #![feature(new_uninit)]
@@ -26,6 +37,8 @@
 #![feature(const_default_impls)]
 #![feature(const_trait_impl)]
 #![feature(const_str_from_utf8)]
+#![feature(nonnull_slice_from_raw_parts)]
+#![feature(panic_update_hook)]
 
 use std::collections::hash_map::DefaultHasher;
 use std::hash::{Hash, Hasher};
index afcb9e03fd097db71203c13a44c58322341e3777..5f5bd9af2fe5f37e9df1decce3fd4e8902208648 100644 (file)
@@ -304,7 +304,7 @@ fn test_show() {
     let list: LinkedList<_> = (0..10).collect();
     assert_eq!(format!("{:?}", list), "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]");
 
-    let list: LinkedList<_> = vec!["just", "one", "test", "more"].iter().cloned().collect();
+    let list: LinkedList<_> = ["just", "one", "test", "more"].into_iter().collect();
     assert_eq!(format!("{:?}", list), "[\"just\", \"one\", \"test\", \"more\"]");
 }
 
@@ -336,7 +336,7 @@ fn test_extend() {
     assert_eq!(a.len(), 4);
     assert!(a.iter().eq(&[1, 2, 3, 4]));
 
-    let b: LinkedList<_> = vec![5, 6, 7].into_iter().collect();
+    let b: LinkedList<_> = [5, 6, 7].into_iter().collect();
     a.extend(b); // specializes to `append`
 
     assert_eq!(a.len(), 7);
@@ -375,7 +375,7 @@ fn drain_filter_empty() {
 
 #[test]
 fn drain_filter_zst() {
-    let mut list: LinkedList<_> = vec![(), (), (), (), ()].into_iter().collect();
+    let mut list: LinkedList<_> = [(), (), (), (), ()].into_iter().collect();
     let initial_len = list.len();
     let mut count = 0;
 
@@ -398,7 +398,7 @@ fn drain_filter_zst() {
 
 #[test]
 fn drain_filter_false() {
-    let mut list: LinkedList<_> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+    let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
 
     let initial_len = list.len();
     let mut count = 0;
@@ -421,7 +421,7 @@ fn drain_filter_false() {
 
 #[test]
 fn drain_filter_true() {
-    let mut list: LinkedList<_> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+    let mut list: LinkedList<_> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
 
     let initial_len = list.len();
     let mut count = 0;
@@ -447,7 +447,7 @@ fn drain_filter_true() {
 fn drain_filter_complex() {
     {
         //                [+xxx++++++xxxxx++++x+x++]
-        let mut list = vec![
+        let mut list = [
             1, 2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37,
             39,
         ]
@@ -467,11 +467,10 @@ fn drain_filter_complex() {
 
     {
         // [xxx++++++xxxxx++++x+x++]
-        let mut list = vec![
-            2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39,
-        ]
-        .into_iter()
-        .collect::<LinkedList<_>>();
+        let mut list =
+            [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36, 37, 39]
+                .into_iter()
+                .collect::<LinkedList<_>>();
 
         let removed = list.drain_filter(|x| *x % 2 == 0).collect::<Vec<_>>();
         assert_eq!(removed.len(), 10);
@@ -487,7 +486,7 @@ fn drain_filter_complex() {
     {
         // [xxx++++++xxxxx++++x+x]
         let mut list =
-            vec![2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]
+            [2, 4, 6, 7, 9, 11, 13, 15, 17, 18, 20, 22, 24, 26, 27, 29, 31, 33, 34, 35, 36]
                 .into_iter()
                 .collect::<LinkedList<_>>();
 
@@ -504,7 +503,7 @@ fn drain_filter_complex() {
 
     {
         // [xxxxxxxxxx+++++++++++]
-        let mut list = vec![2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
+        let mut list = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
             .into_iter()
             .collect::<LinkedList<_>>();
 
@@ -518,7 +517,7 @@ fn drain_filter_complex() {
 
     {
         // [+++++++++++xxxxxxxxxx]
-        let mut list = vec![1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
+        let mut list = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
             .into_iter()
             .collect::<LinkedList<_>>();
 
index 18ea6a214137703403e2f36da7bb94ae4bc2310c..b93d7938bc9a5cd1e5a8db56734d4992633b2ecb 100644 (file)
@@ -1783,12 +1783,11 @@ macro_rules! test {
 #[test]
 #[cfg_attr(target_os = "emscripten", ignore)] // no threads
 fn panic_safe() {
-    let prev = panic::take_hook();
-    panic::set_hook(Box::new(move |info| {
+    panic::update_hook(move |prev, info| {
         if !SILENCE_PANIC.with(|s| s.get()) {
             prev(info);
         }
-    }));
+    });
 
     let mut rng = thread_rng();
 
index 7be137131ff0100d4feac67e7203c6e8edd1a53d..893283e5a248572658bff274b08be9445f379ca0 100644 (file)
@@ -489,7 +489,7 @@ fn test_from_iterator() {
     b.extend(u.chars());
     assert_eq!(s, b);
 
-    let c: String = vec![t, u].into_iter().collect();
+    let c: String = [t, u].into_iter().collect();
     assert_eq!(s, c);
 
     let mut d = t.to_string();
index 773142825329b7dd4130ad8111ff7c226c11f76d..705914b44971c4fd011a2de1c48a4b220e897c93 100644 (file)
@@ -449,10 +449,10 @@ fn zero_sized_values() {
 
 #[test]
 fn test_partition() {
-    assert_eq!(vec![].into_iter().partition(|x: &i32| *x < 3), (vec![], vec![]));
-    assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 4), (vec![1, 2, 3], vec![]));
-    assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 2), (vec![1], vec![2, 3]));
-    assert_eq!(vec![1, 2, 3].into_iter().partition(|x| *x < 0), (vec![], vec![1, 2, 3]));
+    assert_eq!([].into_iter().partition(|x: &i32| *x < 3), (vec![], vec![]));
+    assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 4), (vec![1, 2, 3], vec![]));
+    assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 2), (vec![1], vec![2, 3]));
+    assert_eq!([1, 2, 3].into_iter().partition(|x| *x < 0), (vec![], vec![1, 2, 3]));
 }
 
 #[test]
@@ -924,7 +924,7 @@ fn test_into_iter_debug() {
 
 #[test]
 fn test_into_iter_count() {
-    assert_eq!(vec![1, 2, 3].into_iter().count(), 3);
+    assert_eq!([1, 2, 3].into_iter().count(), 3);
 }
 
 #[test]
@@ -933,7 +933,7 @@ fn iter_equal<I: Iterator<Item = i32>>(it: I, slice: &[i32]) {
         let v: Vec<i32> = it.collect();
         assert_eq!(&v[..], slice);
     }
-    let mut it = vec![1, 2, 3].into_iter();
+    let mut it = [1, 2, 3].into_iter();
     iter_equal(it.clone(), &[1, 2, 3]);
     assert_eq!(it.next(), Some(1));
     let mut it = it.rev();
@@ -972,7 +972,7 @@ fn drop(&mut self) {
 
 #[test]
 fn test_into_iter_advance_by() {
-    let mut i = vec![1, 2, 3, 4, 5].into_iter();
+    let mut i = [1, 2, 3, 4, 5].into_iter();
     i.advance_by(0).unwrap();
     i.advance_back_by(0).unwrap();
     assert_eq!(i.as_slice(), [1, 2, 3, 4, 5]);
@@ -1799,7 +1799,7 @@ fn next_then_drop<I: Iterator>(mut i: I) {
     assert_eq!(*v0, 13);
     next_then_drop(v.splice(5..8, vec![1])); // replacement is smaller than original range
     assert_eq!(*v0, 13);
-    next_then_drop(v.splice(5..6, vec![1; 10].into_iter().filter(|_| true))); // lower bound not exact
+    next_then_drop(v.splice(5..6, [1; 10].into_iter().filter(|_| true))); // lower bound not exact
     assert_eq!(*v0, 13);
 
     // spare_capacity_mut
index ddfb4c00c2698fdc635219a2be033073264007a6..18954f094c671c2633d7dadbd080589500179ff3 100644 (file)
@@ -927,8 +927,8 @@ fn test_as_mut_slices() {
 
 #[test]
 fn test_append() {
-    let mut a: VecDeque<_> = vec![1, 2, 3].into_iter().collect();
-    let mut b: VecDeque<_> = vec![4, 5, 6].into_iter().collect();
+    let mut a: VecDeque<_> = [1, 2, 3].into_iter().collect();
+    let mut b: VecDeque<_> = [4, 5, 6].into_iter().collect();
 
     // normal append
     a.append(&mut b);
@@ -1209,7 +1209,7 @@ fn test_try_reserve() {
 
     {
         // Same basic idea, but with non-zero len
-        let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+        let mut ten_bytes: VecDeque<u8> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
 
         if let Err(CapacityOverflow) = ten_bytes.try_reserve(MAX_CAP - 10).map_err(|e| e.kind()) {
             panic!("isize::MAX shouldn't trigger an overflow!");
@@ -1240,7 +1240,7 @@ fn test_try_reserve() {
 
     {
         // Same basic idea, but with interesting type size
-        let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+        let mut ten_u32s: VecDeque<u32> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
 
         if let Err(CapacityOverflow) = ten_u32s.try_reserve(MAX_CAP / 4 - 10).map_err(|e| e.kind())
         {
@@ -1322,7 +1322,7 @@ fn test_try_reserve_exact() {
     }
 
     {
-        let mut ten_bytes: VecDeque<u8> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+        let mut ten_bytes: VecDeque<u8> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
 
         if let Err(CapacityOverflow) =
             ten_bytes.try_reserve_exact(MAX_CAP - 10).map_err(|e| e.kind())
@@ -1355,7 +1355,7 @@ fn test_try_reserve_exact() {
     }
 
     {
-        let mut ten_u32s: VecDeque<u32> = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
+        let mut ten_u32s: VecDeque<u32> = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].into_iter().collect();
 
         if let Err(CapacityOverflow) =
             ten_u32s.try_reserve_exact(MAX_CAP / 4 - 10).map_err(|e| e.kind())
index 6f10b9e434290adfc2134accb47efd947c03e1ba..6bc4ba3cc0edf24dd75e18062d636c6debb1315b 100644 (file)
@@ -6,7 +6,7 @@ repository = "https://github.com/rust-lang/rust.git"
 description = "The Rust Core Library"
 autotests = false
 autobenches = false
-edition = "2018"
+edition = "2021"
 
 [lib]
 test = false
index 37292bf8e26243b279a626c7c2c9d13b6b3ebd64..121aa634deb330988fb3c4ad224e11e619677d1b 100644 (file)
@@ -66,8 +66,6 @@
 ///
 /// ```rust
 /// #![feature(array_from_fn)]
-/// # // Apparently these doc tests are still on edition2018
-/// # use std::convert::TryInto;
 ///
 /// let array: Result<[u8; 5], _> = std::array::try_from_fn(|i| i.try_into());
 /// assert_eq!(array, Ok([0, 1, 2, 3, 4]));
index c4046d7496f71b3238a1f83a2a7f879e734ecd6d..1774ddd7cbb2cde9e61ff732a8f25860b798c0f9 100644 (file)
@@ -1,5 +1,6 @@
 //! Character conversions.
 
+use crate::char::TryFromCharError;
 use crate::convert::TryFrom;
 use crate::fmt;
 use crate::mem::transmute;
@@ -166,6 +167,20 @@ fn from(c: char) -> Self {
     }
 }
 
+/// Map `char` with code point in U+0000..=U+00FF to byte in 0x00..=0xFF with same value, failing
+/// if the code point is greater than U+00FF.
+///
+/// See [`impl From<u8> for char`](char#impl-From<u8>) for details on the encoding.
+#[stable(feature = "u8_from_char", since = "1.59.0")]
+impl TryFrom<char> for u8 {
+    type Error = TryFromCharError;
+
+    #[inline]
+    fn try_from(c: char) -> Result<u8, Self::Error> {
+        u8::try_from(u32::from(c)).map_err(|_| TryFromCharError(()))
+    }
+}
+
 /// Maps a byte in 0x00..=0xFF to a `char` whose code point has the same value, in U+0000..=U+00FF.
 ///
 /// Unicode is designed such that this effectively decodes bytes
index 5f30d5790a04ff8a771206a0afe30f541afdb5d8..f65f84e93aebe6a369fa9c7d27d6d405ba49903e 100644 (file)
@@ -544,3 +544,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Display::fmt(&self.0, f)
     }
 }
+
+/// The error type returned when a checked char conversion fails.
+#[stable(feature = "u8_from_char", since = "1.59.0")]
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+pub struct TryFromCharError(pub(crate) ());
+
+#[stable(feature = "u8_from_char", since = "1.59.0")]
+impl fmt::Display for TryFromCharError {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "unicode code point out of range".fmt(fmt)
+    }
+}
index 1c2e673d6049329cabc9dfb8a55d2372a891c4de..5566c2ffe87deeed0a75bb26e745f2527cd5e079 100644 (file)
@@ -91,7 +91,7 @@
 /// ```rust
 /// use std::convert::identity;
 ///
-/// let iter = vec![Some(1), None, Some(3)].into_iter();
+/// let iter = [Some(1), None, Some(3)].into_iter();
 /// let filtered = iter.filter_map(identity).collect::<Vec<_>>();
 /// assert_eq!(vec![1, 3], filtered);
 /// ```
@@ -426,8 +426,6 @@ pub trait TryInto<T>: Sized {
 /// `TryFrom<T>` can be implemented as follows:
 ///
 /// ```
-/// use std::convert::TryFrom;
-///
 /// struct GreaterThanZero(i32);
 ///
 /// impl TryFrom<i32> for GreaterThanZero {
@@ -448,8 +446,6 @@ pub trait TryInto<T>: Sized {
 /// As described, [`i32`] implements `TryFrom<`[`i64`]`>`:
 ///
 /// ```
-/// use std::convert::TryFrom;
-///
 /// let big_number = 1_000_000_000_000i64;
 /// // Silently truncates `big_number`, requires detecting
 /// // and handling the truncation after the fact.
@@ -485,9 +481,10 @@ pub trait TryFrom<T>: Sized {
 
 // As lifts over &
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsRef<U> for &T
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized, U: ?Sized> const AsRef<U> for &T
 where
-    T: AsRef<U>,
+    T: ~const AsRef<U>,
 {
     fn as_ref(&self) -> &U {
         <T as AsRef<U>>::as_ref(*self)
@@ -496,9 +493,10 @@ fn as_ref(&self) -> &U {
 
 // As lifts over &mut
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsRef<U> for &mut T
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized, U: ?Sized> const AsRef<U> for &mut T
 where
-    T: AsRef<U>,
+    T: ~const AsRef<U>,
 {
     fn as_ref(&self) -> &U {
         <T as AsRef<U>>::as_ref(*self)
@@ -515,9 +513,10 @@ fn as_ref(&self) -> &U {
 
 // AsMut lifts over &mut
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsMut<U> for &mut T
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T: ?Sized, U: ?Sized> const AsMut<U> for &mut T
 where
-    T: AsMut<U>,
+    T: ~const AsMut<U>,
 {
     fn as_mut(&mut self) -> &mut U {
         (*self).as_mut()
@@ -571,9 +570,10 @@ fn from(t: !) -> T {
 
 // TryFrom implies TryInto
 #[stable(feature = "try_from", since = "1.34.0")]
-impl<T, U> TryInto<U> for T
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T, U> const TryInto<U> for T
 where
-    U: TryFrom<T>,
+    U: ~const TryFrom<T>,
 {
     type Error = U::Error;
 
@@ -585,9 +585,10 @@ fn try_into(self) -> Result<U, U::Error> {
 // Infallible conversions are semantically equivalent to fallible conversions
 // with an uninhabited error type.
 #[stable(feature = "try_from", since = "1.34.0")]
-impl<T, U> TryFrom<U> for T
+#[rustc_const_unstable(feature = "const_convert", issue = "88674")]
+impl<T, U> const TryFrom<U> for T
 where
-    U: Into<T>,
+    U: ~const Into<T>,
 {
     type Error = Infallible;
 
index 6fc3cd0b7c4adcf2abe72f363c745c08a02b1c92..8a2a64f8dc97f44e361abfde4d2e00a0c7a2ac44 100644 (file)
@@ -570,11 +570,30 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> Result {
 /// There are a number of helper methods on the [`Formatter`] struct to help you with manual
 /// implementations, such as [`debug_struct`].
 ///
+/// [`debug_struct`]: Formatter::debug_struct
+///
+/// Types that do not wish to use the standard suite of debug representations
+/// provided by the `Formatter` trait (`debug_struct`, `debug_tuple`,
+/// `debut_list`, `debug_set`, `debug_map`) can do something totally custom by
+/// manually writing an arbitrary representation to the `Formatter`.
+///
+/// ```
+/// # use std::fmt;
+/// # struct Point {
+/// #     x: i32,
+/// #     y: i32,
+/// # }
+/// #
+/// impl fmt::Debug for Point {
+///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+///         write!(f, "Point [{} {}]", self.x, self.y)
+///     }
+/// }
+/// ```
+///
 /// `Debug` implementations using either `derive` or the debug builder API
 /// on [`Formatter`] support pretty-printing using the alternate flag: `{:#?}`.
 ///
-/// [`debug_struct`]: Formatter::debug_struct
-///
 /// Pretty-printing with `#?`:
 ///
 /// ```
index 003391e52be6b93aae3c7004beb8981def8142c1..330c43d2948357f3951c7a4e3cdd69407499f3f9 100644 (file)
@@ -123,6 +123,21 @@ pub fn spin_loop() {
         }
     }
 
+    // RISC-V platform spin loop hint implementation
+    {
+        // RISC-V RV32 and RV64 share the same PAUSE instruction, but they are located in different
+        // modules in `core::arch`.
+        // In this case, here we call `pause` function in each core arch module.
+        #[cfg(target_arch = "riscv32")]
+        {
+            crate::arch::riscv32::pause();
+        }
+        #[cfg(target_arch = "riscv64")]
+        {
+            crate::arch::riscv64::pause();
+        }
+    }
+
     #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
     {
         #[cfg(target_arch = "aarch64")]
@@ -137,11 +152,6 @@ pub fn spin_loop() {
             unsafe { crate::arch::arm::__yield() };
         }
     }
-
-    #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
-    {
-        crate::arch::riscv::pause();
-    }
 }
 
 /// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
index 4ecc3b0c7f8e1ad4b174dd261adf93b6ed801eff..acbb612352b3659b1b8f65de385ddd9778ad56db 100644 (file)
@@ -961,7 +961,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     /// Below are common applications of `transmute` which can be replaced with safer
     /// constructs.
     ///
-    /// Turning raw bytes(`&[u8]`) to `u32`, `f64`, etc.:
+    /// Turning raw bytes (`&[u8]`) into `u32`, `f64`, etc.:
     ///
     /// ```
     /// let raw_bytes = [0x78, 0x56, 0x34, 0x12];
index 449650a22f4353b0981e1d82cc9f069db0ed36c4..b2ed82508dd297afb69dad6a258eebbb08f6e523 100644 (file)
@@ -19,7 +19,7 @@
 /// you can also [`map`] backwards:
 ///
 /// ```rust
-/// let v: Vec<i32> = vec![1, 2, 3].into_iter().map(|x| x + 1).rev().collect();
+/// let v: Vec<i32> = [1, 2, 3].into_iter().map(|x| x + 1).rev().collect();
 ///
 /// assert_eq!(v, [4, 3, 2]);
 /// ```
@@ -32,7 +32,7 @@
 /// ```rust
 /// let mut c = 0;
 ///
-/// for pair in vec!['a', 'b', 'c'].into_iter()
+/// for pair in ['a', 'b', 'c'].into_iter()
 ///                                .map(|letter| { c += 1; (letter, c) }) {
 ///     println!("{:?}", pair);
 /// }
@@ -49,7 +49,7 @@
 /// ```rust
 /// let mut c = 0;
 ///
-/// for pair in vec!['a', 'b', 'c'].into_iter()
+/// for pair in ['a', 'b', 'c'].into_iter()
 ///                                .map(|letter| { c += 1; (letter, c) })
 ///                                .rev() {
 ///     println!("{:?}", pair);
index b1b917775c3fa3072274aa3541e918e7d3b3d655..db8776ac7418d9aa2a79be51282e657ec7573426 100644 (file)
@@ -24,6 +24,7 @@
 mod take_while;
 mod zip;
 
+#[stable(feature = "rust1", since = "1.0.0")]
 pub use self::{
     chain::Chain, cycle::Cycle, enumerate::Enumerate, filter::Filter, filter_map::FilterMap,
     flatten::FlatMap, fuse::Fuse, inspect::Inspect, map::Map, peekable::Peekable, rev::Rev,
index de0663141e25274cb5e95d1039047e58297c60a7..37b6f2e2565b2fe613f3386c2f6f75af658756d2 100644 (file)
@@ -6,6 +6,7 @@
 mod repeat_with;
 mod successors;
 
+#[stable(feature = "rust1", since = "1.0.0")]
 pub use self::repeat::{repeat, Repeat};
 
 #[stable(feature = "iter_empty", since = "1.2.0")]
index 56fad602cf9c8e6b374e2994010b04fe662681e0..fc14620a2df84b752686aa0daa4d47318079489b 100644 (file)
@@ -15,8 +15,6 @@
 /// Basic usage:
 ///
 /// ```
-/// use std::iter::FromIterator;
-///
 /// let five_fives = std::iter::repeat(5).take(5);
 ///
 /// let v = Vec::from_iter(five_fives);
@@ -37,8 +35,6 @@
 /// Implementing `FromIterator` for your type:
 ///
 /// ```
-/// use std::iter::FromIterator;
-///
 /// // A sample collection, that's just a wrapper over Vec<T>
 /// #[derive(Debug)]
 /// struct MyCollection(Vec<i32>);
@@ -102,8 +98,6 @@ pub trait FromIterator<A>: Sized {
     /// Basic usage:
     ///
     /// ```
-    /// use std::iter::FromIterator;
-    ///
     /// let five_fives = std::iter::repeat(5).take(5);
     ///
     /// let v = Vec::from_iter(five_fives);
@@ -130,7 +124,7 @@ pub trait FromIterator<A>: Sized {
 /// Basic usage:
 ///
 /// ```
-/// let v = vec![1, 2, 3];
+/// let v = [1, 2, 3];
 /// let mut iter = v.into_iter();
 ///
 /// assert_eq!(Some(1), iter.next());
@@ -221,7 +215,7 @@ pub trait IntoIterator {
     /// Basic usage:
     ///
     /// ```
-    /// let v = vec![1, 2, 3];
+    /// let v = [1, 2, 3];
     /// let mut iter = v.into_iter();
     ///
     /// assert_eq!(Some(1), iter.next());
index 9a9a844f41bb44cecf96fd29cb5364ab1b3f7058..1d947297463d921d5191b0a34a81ac92856475ea 100644 (file)
@@ -590,7 +590,7 @@ fn intersperse(self, separator: Self::Item) -> Intersperse<Self>
     /// #[derive(PartialEq, Debug)]
     /// struct NotClone(usize);
     ///
-    /// let v = vec![NotClone(0), NotClone(1), NotClone(2)];
+    /// let v = [NotClone(0), NotClone(1), NotClone(2)];
     /// let mut it = v.into_iter().intersperse_with(|| NotClone(99));
     ///
     /// assert_eq!(it.next(), Some(NotClone(0)));  // The first element from `v`.
@@ -1155,8 +1155,6 @@ fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
     /// Stopping after an initial [`None`]:
     ///
     /// ```
-    /// use std::convert::TryFrom;
-    ///
     /// let a = [0, 1, 2, -3, 4, 5, -6];
     ///
     /// let iter = a.iter().map_while(|x| u32::try_from(*x).ok());
@@ -1172,8 +1170,6 @@ fn take_while<P>(self, predicate: P) -> TakeWhile<Self, P>
     /// removed:
     ///
     /// ```
-    /// use std::convert::TryFrom;
-    ///
     /// let a = [1, 2, -3, 4];
     /// let mut iter = a.iter();
     ///
@@ -1274,7 +1270,7 @@ fn skip(self, n: usize) -> Skip<Self>
     /// `take` will limit itself to the size of the underlying iterator:
     ///
     /// ```
-    /// let v = vec![1, 2];
+    /// let v = [1, 2];
     /// let mut iter = v.into_iter().take(5);
     /// assert_eq!(iter.next(), Some(1));
     /// assert_eq!(iter.next(), Some(2));
@@ -1608,7 +1604,7 @@ fn inspect<F>(self, f: F) -> Inspect<Self, F>
     /// Basic usage:
     ///
     /// ```
-    /// let mut words = vec!["hello", "world", "of", "Rust"].into_iter();
+    /// let mut words = ["hello", "world", "of", "Rust"].into_iter();
     ///
     /// // Take the first two words.
     /// let hello_world: Vec<_> = words.by_ref().take(2).collect();
@@ -2704,7 +2700,7 @@ fn check<T>(
     /// incomparable. You can work around this by using [`Iterator::reduce`]:
     /// ```
     /// assert_eq!(
-    ///     vec![2.4, f32::NAN, 1.3]
+    ///     [2.4, f32::NAN, 1.3]
     ///         .into_iter()
     ///         .reduce(f32::max)
     ///         .unwrap(),
@@ -2742,7 +2738,7 @@ fn max(self) -> Option<Self::Item>
     /// incomparable. You can work around this by using [`Iterator::reduce`]:
     /// ```
     /// assert_eq!(
-    ///     vec![2.4, f32::NAN, 1.3]
+    ///     [2.4, f32::NAN, 1.3]
     ///         .into_iter()
     ///         .reduce(f32::min)
     ///         .unwrap(),
index ffd745a46b12c0e1091bb423ae4265f33e66380d..ed0fb634dbf05043c0712d30900a790ade5d208d 100644 (file)
@@ -5,15 +5,17 @@
 mod iterator;
 mod marker;
 
-pub use self::accum::{Product, Sum};
-pub use self::collect::{Extend, FromIterator, IntoIterator};
-pub use self::double_ended::DoubleEndedIterator;
-pub use self::exact_size::ExactSizeIterator;
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use self::iterator::Iterator;
+pub use self::{
+    accum::{Product, Sum},
+    collect::{Extend, FromIterator, IntoIterator},
+    double_ended::DoubleEndedIterator,
+    exact_size::ExactSizeIterator,
+    iterator::Iterator,
+    marker::{FusedIterator, TrustedLen},
+};
+
 #[unstable(issue = "none", feature = "inplace_iteration")]
 pub use self::marker::InPlaceIterable;
 #[unstable(feature = "trusted_step", issue = "85731")]
 pub use self::marker::TrustedStep;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::marker::{FusedIterator, TrustedLen};
index d9389892c0cd6b18fe7c96696f064be4e44e0396..d8f6c85e428cdf054e78afcdfa0f6cd1c7d66630 100644 (file)
@@ -866,7 +866,6 @@ macro_rules! const_format_args {
                   language use and is subject to change"
     )]
     #[allow_internal_unstable(fmt_internals)]
-    #[doc(hidden)]
     #[rustc_builtin_macro]
     #[macro_export]
     macro_rules! format_args_nl {
@@ -1428,6 +1427,10 @@ macro_rules! trace_macros {
     }
 
     /// Attribute macro used to apply derive macros.
+    ///
+    /// See [the reference] for more info.
+    ///
+    /// [the reference]: ../../../reference/attributes/derive.html
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     pub macro derive($item:item) {
@@ -1435,6 +1438,10 @@ macro_rules! trace_macros {
     }
 
     /// Attribute macro applied to a function to turn it into a unit test.
+    ///
+    /// See [the reference] for more info.
+    ///
+    /// [the reference]: ../../../reference/attributes/testing.html#the-test-attribute
     #[stable(feature = "rust1", since = "1.0.0")]
     #[allow_internal_unstable(test, rustc_attrs)]
     #[rustc_builtin_macro]
@@ -1469,7 +1476,7 @@ macro_rules! trace_macros {
 
     /// Attribute macro applied to a static to register it as a global allocator.
     ///
-    /// See also [`std::alloc::GlobalAlloc`](../std/alloc/trait.GlobalAlloc.html).
+    /// See also [`std::alloc::GlobalAlloc`](../../../std/alloc/trait.GlobalAlloc.html).
     #[stable(feature = "global_allocator", since = "1.28.0")]
     #[allow_internal_unstable(rustc_attrs)]
     #[rustc_builtin_macro]
@@ -1507,6 +1514,7 @@ macro_rules! trace_macros {
         since = "1.52.0",
         reason = "rustc-serialize is deprecated and no longer supported"
     )]
+    #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
     pub macro RustcDecodable($item:item) {
         /* compiler built-in */
     }
@@ -1519,6 +1527,7 @@ macro_rules! trace_macros {
         since = "1.52.0",
         reason = "rustc-serialize is deprecated and no longer supported"
     )]
+    #[doc(hidden)] // While technically stable, using it is unstable, and deprecated. Hide it.
     pub macro RustcEncodable($item:item) {
         /* compiler built-in */
     }
index 3b0e4a31db1c8ce894f05b0fb770915efc23dd0d..dd2f73063566ecac13c38b560751772e447e3cde 100644 (file)
@@ -330,7 +330,7 @@ pub const fn uninit() -> MaybeUninit<T> {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice)]
+    /// #![feature(maybe_uninit_uninit_array, maybe_uninit_slice)]
     ///
     /// use std::mem::MaybeUninit;
     ///
@@ -662,7 +662,6 @@ pub const fn as_mut_ptr(&mut self) -> *mut T {
     /// Correct usage of this method:
     ///
     /// ```rust
-    /// #![feature(maybe_uninit_extra)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<u32>::uninit();
@@ -683,7 +682,6 @@ pub const fn as_mut_ptr(&mut self) -> *mut T {
     /// *Incorrect* usage of this method:
     ///
     /// ```rust,no_run
-    /// #![feature(maybe_uninit_extra)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut x = MaybeUninit::<Option<Vec<u32>>>::uninit();
@@ -693,8 +691,8 @@ pub const fn as_mut_ptr(&mut self) -> *mut T {
     /// // We now created two copies of the same vector, leading to a double-free ⚠️ when
     /// // they both get dropped!
     /// ```
-    #[unstable(feature = "maybe_uninit_extra", issue = "63567")]
-    #[rustc_const_unstable(feature = "maybe_uninit_extra", issue = "63567")]
+    #[stable(feature = "maybe_uninit_extra", since = "1.60.0")]
+    #[rustc_const_unstable(feature = "const_maybe_uninit_assume_init_read", issue = "63567")]
     #[inline(always)]
     #[track_caller]
     pub const unsafe fn assume_init_read(&self) -> T {
@@ -728,7 +726,7 @@ pub const fn as_mut_ptr(&mut self) -> *mut T {
     ///
     /// [`assume_init`]: MaybeUninit::assume_init
     /// [`Vec<T>`]: ../../std/vec/struct.Vec.html
-    #[unstable(feature = "maybe_uninit_extra", issue = "63567")]
+    #[stable(feature = "maybe_uninit_extra", since = "1.60.0")]
     pub unsafe fn assume_init_drop(&mut self) {
         // SAFETY: the caller must guarantee that `self` is initialized and
         // satisfies all invariants of `T`.
index 7d005666a74a6514e32bd7b55e15e00f87236c74..989ec0639cd6b37ac89b0a8922f1472e828600ef 100644 (file)
@@ -1045,6 +1045,10 @@ pub const fn discriminant<T>(v: &T) -> Discriminant<T> {
 /// return value is unspecified. Equally, if `T` is an enum with more variants than `usize::MAX`
 /// the return value is unspecified. Uninhabited variants will be counted.
 ///
+/// Note that an enum may be expanded with additional variants in the future
+/// as a non-breaking change, for example if it is marked `#[non_exhaustive]`,
+/// which will change the result of this function.
+///
 /// # Examples
 ///
 /// ```
index 8a06a0988829b646d871433c1986291875abfe55..98d8a8a1d74aebd822326df20390147d4e099d47 100644 (file)
@@ -158,24 +158,15 @@ pub fn is_zero(&self) -> bool {
             /// Returns the number of bits necessary to represent this value. Note that zero
             /// is considered to need 0 bits.
             pub fn bit_length(&self) -> usize {
-                // Skip over the most significant digits which are zero.
+                let digitbits = <$ty>::BITS as usize;
                 let digits = self.digits();
-                let zeros = digits.iter().rev().take_while(|&&x| x == 0).count();
-                let end = digits.len() - zeros;
-                let nonzero = &digits[..end];
-
-                if nonzero.is_empty() {
+                // Find the most significant non-zero digit.
+                let msd = digits.iter().rposition(|&x| x != 0);
+                match msd {
+                    Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1,
                     // There are no non-zero digits, i.e., the number is zero.
-                    return 0;
-                }
-                // This could be optimized with leading_zeros() and bit shifts, but that's
-                // probably not worth the hassle.
-                let digitbits = <$ty>::BITS as usize;
-                let mut i = nonzero.len() * digitbits - 1;
-                while self.get_bit(i) == 0 {
-                    i -= 1;
+                    _ => 0,
                 }
-                i + 1
             }
 
             /// Adds `other` to itself and returns its own mutable reference.
index c4a232ef36c615c5010557afefa93358552a8adf..85ceede5b9e3a1b227888b4fa1044d7a01111f67 100644 (file)
@@ -628,6 +628,7 @@ pub const fn is_sign_negative(self) -> bool {
     ///
     /// assert!(abs_difference <= f32::EPSILON);
     /// ```
+    #[must_use = "this returns the result of the operation, without modifying the original"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn recip(self) -> f32 {
@@ -684,6 +685,7 @@ pub fn to_radians(self) -> f32 {
     /// ```
     ///
     /// If one of the arguments is NaN, then the other argument is returned.
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn max(self, other: f32) -> f32 {
@@ -703,6 +705,7 @@ pub fn max(self, other: f32) -> f32 {
     /// ```
     ///
     /// If one of the arguments is NaN, then the other argument is returned.
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn min(self, other: f32) -> f32 {
@@ -726,6 +729,7 @@ pub fn min(self, other: f32) -> f32 {
     /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
     /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
     /// Note that this follows the semantics specified in IEEE 754-2019.
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub fn maximum(self, other: f32) -> f32 {
@@ -757,6 +761,7 @@ pub fn maximum(self, other: f32) -> f32 {
     /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
     /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
     /// Note that this follows the semantics specified in IEEE 754-2019.
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub fn minimum(self, other: f32) -> f32 {
index 85ee6aa2cb8c3399f6bd2787ad9696d72fbe5b82..4049c95b130f2a6bdc771a61ed13739ba240e647 100644 (file)
@@ -643,6 +643,7 @@ pub fn is_negative(self) -> bool {
     ///
     /// assert!(abs_difference < 1e-10);
     /// ```
+    #[must_use = "this returns the result of the operation, without modifying the original"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn recip(self) -> f64 {
@@ -700,6 +701,7 @@ pub fn to_radians(self) -> f64 {
     /// ```
     ///
     /// If one of the arguments is NaN, then the other argument is returned.
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn max(self, other: f64) -> f64 {
@@ -719,6 +721,7 @@ pub fn max(self, other: f64) -> f64 {
     /// ```
     ///
     /// If one of the arguments is NaN, then the other argument is returned.
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub fn min(self, other: f64) -> f64 {
@@ -742,6 +745,7 @@ pub fn min(self, other: f64) -> f64 {
     /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
     /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
     /// Note that this follows the semantics specified in IEEE 754-2019.
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub fn maximum(self, other: f64) -> f64 {
@@ -773,6 +777,7 @@ pub fn maximum(self, other: f64) -> f64 {
     /// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
     /// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
     /// Note that this follows the semantics specified in IEEE 754-2019.
+    #[must_use = "this returns the result of the comparison, without modifying either input"]
     #[unstable(feature = "float_minimum_maximum", issue = "91079")]
     #[inline]
     pub fn minimum(self, other: f64) -> f64 {
index e6ae4afd7c192b7aa111d32983e2aac24821b3e5..6f7c5a6d119945fe5acc75bf55d09b2a90b0e694 100644 (file)
@@ -2602,8 +2602,6 @@ pub const fn is_negative(self) -> bool { self < 0 }
         /// When starting from a slice rather than an array, fallible conversion APIs can be used:
         ///
         /// ```
-        /// use std::convert::TryInto;
-        ///
         #[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
         #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
@@ -2633,8 +2631,6 @@ pub const fn is_negative(self) -> bool { self < 0 }
         /// When starting from a slice rather than an array, fallible conversion APIs can be used:
         ///
         /// ```
-        /// use std::convert::TryInto;
-        ///
         #[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
         #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
@@ -2675,8 +2671,6 @@ pub const fn is_negative(self) -> bool { self < 0 }
         /// When starting from a slice rather than an array, fallible conversion APIs can be used:
         ///
         /// ```
-        /// use std::convert::TryInto;
-        ///
         #[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
         #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
index d9b14c82e96ba49a60a7ebf7b01d5fbeb20649f0..317555034756d8be6b9b0825c9ef19c84f056d85 100644 (file)
@@ -217,6 +217,18 @@ fn add(self, other: Saturating<$t>) -> Saturating<$t> {
         forward_ref_binop! { impl Add, add for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl Add<$t> for Saturating<$t> {
+            type Output = Saturating<$t>;
+
+            #[inline]
+            fn add(self, other: $t) -> Saturating<$t> {
+                Saturating(self.0.saturating_add(other))
+            }
+        }
+        forward_ref_binop! { impl Add, add for Saturating<$t>, $t,
+                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl AddAssign for Saturating<$t> {
             #[inline]
@@ -226,6 +238,15 @@ fn add_assign(&mut self, other: Saturating<$t>) {
         }
         forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, Saturating<$t> }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl AddAssign<$t> for Saturating<$t> {
+            #[inline]
+            fn add_assign(&mut self, other: $t) {
+                *self = *self + other;
+            }
+        }
+        forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, $t }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl Sub for Saturating<$t> {
             type Output = Saturating<$t>;
@@ -238,6 +259,18 @@ fn sub(self, other: Saturating<$t>) -> Saturating<$t> {
         forward_ref_binop! { impl Sub, sub for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl Sub<$t> for Saturating<$t> {
+            type Output = Saturating<$t>;
+
+            #[inline]
+            fn sub(self, other: $t) -> Saturating<$t> {
+                Saturating(self.0.saturating_sub(other))
+            }
+        }
+        forward_ref_binop! { impl Sub, sub for Saturating<$t>, $t,
+                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl SubAssign for Saturating<$t> {
             #[inline]
@@ -247,6 +280,15 @@ fn sub_assign(&mut self, other: Saturating<$t>) {
         }
         forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, Saturating<$t> }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl SubAssign<$t> for Saturating<$t> {
+            #[inline]
+            fn sub_assign(&mut self, other: $t) {
+                *self = *self - other;
+            }
+        }
+        forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, $t }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl Mul for Saturating<$t> {
             type Output = Saturating<$t>;
@@ -259,6 +301,18 @@ fn mul(self, other: Saturating<$t>) -> Saturating<$t> {
         forward_ref_binop! { impl Mul, mul for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl Mul<$t> for Saturating<$t> {
+            type Output = Saturating<$t>;
+
+            #[inline]
+            fn mul(self, other: $t) -> Saturating<$t> {
+                Saturating(self.0.saturating_mul(other))
+            }
+        }
+        forward_ref_binop! { impl Mul, mul for Saturating<$t>, $t,
+                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl MulAssign for Saturating<$t> {
             #[inline]
@@ -268,6 +322,15 @@ fn mul_assign(&mut self, other: Saturating<$t>) {
         }
         forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, Saturating<$t> }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl MulAssign<$t> for Saturating<$t> {
+            #[inline]
+            fn mul_assign(&mut self, other: $t) {
+                *self = *self * other;
+            }
+        }
+        forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, $t }
+
         /// # Examples
         ///
         /// Basic usage:
@@ -299,6 +362,37 @@ fn div(self, other: Saturating<$t>) -> Saturating<$t> {
         forward_ref_binop! { impl Div, div for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(saturating_int_impl, saturating_int_assign_impl)]
+        /// use std::num::Saturating;
+        ///
+        #[doc = concat!("assert_eq!(Saturating(2", stringify!($t), "), Saturating(5", stringify!($t), ") / 2);")]
+        #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MAX), Saturating(", stringify!($t), "::MAX) / 1);")]
+        #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MIN), Saturating(", stringify!($t), "::MIN) / 1);")]
+        /// ```
+        ///
+        /// ```should_panic
+        /// #![feature(saturating_int_impl, saturating_int_assign_impl)]
+        /// use std::num::Saturating;
+        ///
+        #[doc = concat!("let _ = Saturating(0", stringify!($t), ") / 0;")]
+        /// ```
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl Div<$t> for Saturating<$t> {
+            type Output = Saturating<$t>;
+
+            #[inline]
+            fn div(self, other: $t) -> Saturating<$t> {
+                Saturating(self.0.saturating_div(other))
+            }
+        }
+        forward_ref_binop! { impl Div, div for Saturating<$t>, $t,
+                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl DivAssign for Saturating<$t> {
             #[inline]
@@ -308,6 +402,15 @@ fn div_assign(&mut self, other: Saturating<$t>) {
         }
         forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, Saturating<$t> }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl DivAssign<$t> for Saturating<$t> {
+            #[inline]
+            fn div_assign(&mut self, other: $t) {
+                *self = *self / other;
+            }
+        }
+        forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, $t }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl Rem for Saturating<$t> {
             type Output = Saturating<$t>;
@@ -320,6 +423,18 @@ fn rem(self, other: Saturating<$t>) -> Saturating<$t> {
         forward_ref_binop! { impl Rem, rem for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl Rem<$t> for Saturating<$t> {
+            type Output = Saturating<$t>;
+
+            #[inline]
+            fn rem(self, other: $t) -> Saturating<$t> {
+                Saturating(self.0.rem(other))
+            }
+        }
+        forward_ref_binop! { impl Rem, rem for Saturating<$t>, $t,
+                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl RemAssign for Saturating<$t> {
             #[inline]
@@ -329,6 +444,15 @@ fn rem_assign(&mut self, other: Saturating<$t>) {
         }
         forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, Saturating<$t> }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl RemAssign<$t> for Saturating<$t> {
+            #[inline]
+            fn rem_assign(&mut self, other: $t) {
+                *self = *self % other;
+            }
+        }
+        forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, $t }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl Not for Saturating<$t> {
             type Output = Saturating<$t>;
@@ -353,6 +477,18 @@ fn bitxor(self, other: Saturating<$t>) -> Saturating<$t> {
         forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl BitXor<$t> for Saturating<$t> {
+            type Output = Saturating<$t>;
+
+            #[inline]
+            fn bitxor(self, other: $t) -> Saturating<$t> {
+                Saturating(self.0 ^ other)
+            }
+        }
+        forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, $t,
+                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl BitXorAssign for Saturating<$t> {
             #[inline]
@@ -362,6 +498,15 @@ fn bitxor_assign(&mut self, other: Saturating<$t>) {
         }
         forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, Saturating<$t> }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl BitXorAssign<$t> for Saturating<$t> {
+            #[inline]
+            fn bitxor_assign(&mut self, other: $t) {
+                *self = *self ^ other;
+            }
+        }
+        forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, $t }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl BitOr for Saturating<$t> {
             type Output = Saturating<$t>;
@@ -374,6 +519,18 @@ fn bitor(self, other: Saturating<$t>) -> Saturating<$t> {
         forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl BitOr<$t> for Saturating<$t> {
+            type Output = Saturating<$t>;
+
+            #[inline]
+            fn bitor(self, other: $t) -> Saturating<$t> {
+                Saturating(self.0 | other)
+            }
+        }
+        forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, $t,
+                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl BitOrAssign for Saturating<$t> {
             #[inline]
@@ -383,6 +540,15 @@ fn bitor_assign(&mut self, other: Saturating<$t>) {
         }
         forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, Saturating<$t> }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl BitOrAssign<$t> for Saturating<$t> {
+            #[inline]
+            fn bitor_assign(&mut self, other: $t) {
+                *self = *self | other;
+            }
+        }
+        forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, $t }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl BitAnd for Saturating<$t> {
             type Output = Saturating<$t>;
@@ -395,6 +561,18 @@ fn bitand(self, other: Saturating<$t>) -> Saturating<$t> {
         forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl BitAnd<$t> for Saturating<$t> {
+            type Output = Saturating<$t>;
+
+            #[inline]
+            fn bitand(self, other: $t) -> Saturating<$t> {
+                Saturating(self.0 & other)
+            }
+        }
+        forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, $t,
+                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
+
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl BitAndAssign for Saturating<$t> {
             #[inline]
@@ -404,6 +582,15 @@ fn bitand_assign(&mut self, other: Saturating<$t>) {
         }
         forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, Saturating<$t> }
 
+        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
+        impl BitAndAssign<$t> for Saturating<$t> {
+            #[inline]
+            fn bitand_assign(&mut self, other: $t) {
+                *self = *self & other;
+            }
+        }
+        forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, $t }
+
     )*)
 }
 
index 3cc454baf35d79aea0994510008064099600a74a..1dd8b0a18ab1bd5e81a9f16b872161994d758914 100644 (file)
@@ -2323,8 +2323,6 @@ pub const fn wrapping_next_power_of_two(self) -> Self {
         /// When starting from a slice rather than an array, fallible conversion APIs can be used:
         ///
         /// ```
-        /// use std::convert::TryInto;
-        ///
         #[doc = concat!("fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
         #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
@@ -2354,8 +2352,6 @@ pub const fn wrapping_next_power_of_two(self) -> Self {
         /// When starting from a slice rather than an array, fallible conversion APIs can be used:
         ///
         /// ```
-        /// use std::convert::TryInto;
-        ///
         #[doc = concat!("fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
         #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
@@ -2396,8 +2392,6 @@ pub const fn wrapping_next_power_of_two(self) -> Self {
         /// When starting from a slice rather than an array, fallible conversion APIs can be used:
         ///
         /// ```
-        /// use std::convert::TryInto;
-        ///
         #[doc = concat!("fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " {")]
         #[doc = concat!("    let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">());")]
         ///     *input = rest;
index 483362023b22c77bc5f340260804f825c2766080..a920b9165c18e2dc86bf1af173cb9746d79881a8 100644 (file)
@@ -68,7 +68,38 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
 #[unstable(feature = "coerce_unsized", issue = "27732")]
 impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
 
-/// This is used for object safety, to check that a method's receiver type can be dispatched on.
+/// `DispatchFromDyn` is used in the implementation of object safety checks (specifically allowing
+/// arbitrary self types), to guarantee that a method's receiver type can be dispatched on.
+///
+/// Note: `DispatchFromDyn` was briefly named `CoerceSized` (and had a slightly different
+/// interpretation).
+///
+/// Imagine we have a trait object `t` with type `&dyn Tr`, where `Tr` is some trait with a method
+/// `m` defined as `fn m(&self);`. When calling `t.m()`, the receiver `t` is a wide pointer, but an
+/// implementation of `m` will expect a narrow pointer as `&self` (a reference to the concrete
+/// type). The compiler must generate an implicit conversion from the trait object/wide pointer to
+/// the concrete reference/narrow pointer. Implementing `DispatchFromDyn` indicates that that
+/// conversion is allowed and thus that the type implementing `DispatchFromDyn` is safe to use as
+/// the self type in an object-safe method. (in the above example, the compiler will require
+/// `DispatchFromDyn` is implemented for `&'a U`).
+///
+/// `DispatchFromDyn` does not specify the conversion from wide pointer to narrow pointer; the
+/// conversion is hard-wired into the compiler. For the conversion to work, the following
+/// properties must hold (i.e., it is only safe to implement `DispatchFromDyn` for types which have
+/// these properties, these are also checked by the compiler):
+///
+/// * EITHER `Self` and `T` are either both references or both raw pointers; in either case, with
+///   the same mutability.
+/// * OR, all of the following hold
+///   - `Self` and `T` must have the same type constructor, and only vary in a single type parameter
+///     formal (the *coerced type*, e.g., `impl DispatchFromDyn<Rc<T>> for Rc<U>` is ok and the
+///     single type parameter (instantiated with `T` or `U`) is the coerced type,
+///     `impl DispatchFromDyn<Arc<T>> for Rc<U>` is not ok).
+///   - The definition for `Self` must be a struct.
+///   - The definition for `Self` must not be `#[repr(packed)]` or `#[repr(C)]`.
+///   - Other than one-aligned, zero-sized fields, the definition for `Self` must have exactly one
+///     field and that field's type must be the coerced type. Furthermore, `Self`'s field type must
+///     implement `DispatchFromDyn<F>` where `F` is the type of `T`'s field type.
 ///
 /// An example implementation of the trait:
 ///
index e6312b8b2d9479ca257f12f94173a78a91bf2833..8adfb6f4bcf5221d4f8325e59e65fa12e696f5f3 100644 (file)
 //! let mut bt = BTreeMap::new();
 //! bt.insert(20u8, "foo");
 //! bt.insert(42u8, "bar");
-//! let res = vec![0u8, 1, 11, 200, 22]
+//! let res = [0u8, 1, 11, 200, 22]
 //!     .into_iter()
 //!     .map(|x| {
 //!         // `checked_sub()` returns `None` on error
 //! [impl-FromIterator]: Option#impl-FromIterator%3COption%3CA%3E%3E
 //!
 //! ```
-//! let v = vec![Some(2), Some(4), None, Some(8)];
+//! let v = [Some(2), Some(4), None, Some(8)];
 //! let res: Option<Vec<_>> = v.into_iter().collect();
 //! assert_eq!(res, None);
-//! let v = vec![Some(2), Some(4), Some(8)];
+//! let v = [Some(2), Some(4), Some(8)];
 //! let res: Option<Vec<_>> = v.into_iter().collect();
 //! assert_eq!(res, Some(vec![2, 4, 8]));
 //! ```
 //! [impl-Sum]: Option#impl-Sum%3COption%3CU%3E%3E
 //!
 //! ```
-//! let v = vec![None, Some(1), Some(2), Some(3)];
+//! let v = [None, Some(1), Some(2), Some(3)];
 //! let res: Option<i32> = v.into_iter().sum();
 //! assert_eq!(res, None);
-//! let v = vec![Some(1), Some(2), Some(21)];
+//! let v = [Some(1), Some(2), Some(21)];
 //! let res: Option<i32> = v.into_iter().product();
 //! assert_eq!(res, Some(42));
 //! ```
@@ -571,36 +571,6 @@ pub const fn is_none(&self) -> bool {
         !self.is_some()
     }
 
-    /// Returns `true` if the option is a [`Some`] value containing the given value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(option_result_contains)]
-    ///
-    /// let x: Option<u32> = Some(2);
-    /// assert_eq!(x.contains(&2), true);
-    ///
-    /// let x: Option<u32> = Some(3);
-    /// assert_eq!(x.contains(&2), false);
-    ///
-    /// let x: Option<u32> = None;
-    /// assert_eq!(x.contains(&2), false);
-    /// ```
-    #[must_use]
-    #[inline]
-    #[unstable(feature = "option_result_contains", issue = "62358")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
-    pub const fn contains<U>(&self, x: &U) -> bool
-    where
-        U: ~const PartialEq<T>,
-    {
-        match self {
-            Some(y) => x.eq(y),
-            None => false,
-        }
-    }
-
     /////////////////////////////////////////////////////////////////////////
     // Adapter for working with references
     /////////////////////////////////////////////////////////////////////////
@@ -810,6 +780,45 @@ pub const fn unwrap_or_else<F>(self, f: F) -> T
         }
     }
 
+    /// Returns the contained [`Some`] value or a default.
+    ///
+    /// Consumes the `self` argument then, if [`Some`], returns the contained
+    /// value, otherwise if [`None`], returns the [default value] for that
+    /// type.
+    ///
+    /// # Examples
+    ///
+    /// Converts a string to an integer, turning poorly-formed strings
+    /// into 0 (the default value for integers). [`parse`] converts
+    /// a string to any other type that implements [`FromStr`], returning
+    /// [`None`] on error.
+    ///
+    /// ```
+    /// let good_year_from_input = "1909";
+    /// let bad_year_from_input = "190blarg";
+    /// let good_year = good_year_from_input.parse().ok().unwrap_or_default();
+    /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default();
+    ///
+    /// assert_eq!(1909, good_year);
+    /// assert_eq!(0, bad_year);
+    /// ```
+    ///
+    /// [default value]: Default::default
+    /// [`parse`]: str::parse
+    /// [`FromStr`]: crate::str::FromStr
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+    pub const fn unwrap_or_default(self) -> T
+    where
+        T: ~const Default,
+    {
+        match self {
+            Some(x) => x,
+            None => Default::default(),
+        }
+    }
+
     /// Returns the contained [`Some`] value, consuming the `self` value,
     /// without checking that the value is not [`None`].
     ///
@@ -1033,6 +1042,58 @@ pub const fn ok_or_else<E, F>(self, err: F) -> Result<T, E>
         }
     }
 
+    /// Converts from `Option<T>` (or `&Option<T>`) to `Option<&T::Target>`.
+    ///
+    /// Leaves the original Option in-place, creating a new one with a reference
+    /// to the original one, additionally coercing the contents via [`Deref`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let x: Option<String> = Some("hey".to_owned());
+    /// assert_eq!(x.as_deref(), Some("hey"));
+    ///
+    /// let x: Option<String> = None;
+    /// assert_eq!(x.as_deref(), None);
+    /// ```
+    #[stable(feature = "option_deref", since = "1.40.0")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+    pub const fn as_deref(&self) -> Option<&T::Target>
+    where
+        T: ~const Deref,
+    {
+        match self.as_ref() {
+            Some(t) => Some(t.deref()),
+            None => None,
+        }
+    }
+
+    /// Converts from `Option<T>` (or `&mut Option<T>`) to `Option<&mut T::Target>`.
+    ///
+    /// Leaves the original `Option` in-place, creating a new one containing a mutable reference to
+    /// the inner type's [`Deref::Target`] type.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut x: Option<String> = Some("hey".to_owned());
+    /// assert_eq!(x.as_deref_mut().map(|x| {
+    ///     x.make_ascii_uppercase();
+    ///     x
+    /// }), Some("HEY".to_owned().as_mut_str()));
+    /// ```
+    #[stable(feature = "option_deref", since = "1.40.0")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+    pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target>
+    where
+        T: ~const DerefMut,
+    {
+        match self.as_mut() {
+            Some(t) => Some(t.deref_mut()),
+            None => None,
+        }
+    }
+
     /////////////////////////////////////////////////////////////////////////
     // Iterator constructors
     /////////////////////////////////////////////////////////////////////////
@@ -1482,6 +1543,36 @@ pub const fn replace(&mut self, value: T) -> Option<T> {
         mem::replace(self, Some(value))
     }
 
+    /// Returns `true` if the option is a [`Some`] value containing the given value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(option_result_contains)]
+    ///
+    /// let x: Option<u32> = Some(2);
+    /// assert_eq!(x.contains(&2), true);
+    ///
+    /// let x: Option<u32> = Some(3);
+    /// assert_eq!(x.contains(&2), false);
+    ///
+    /// let x: Option<u32> = None;
+    /// assert_eq!(x.contains(&2), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "option_result_contains", issue = "62358")]
+    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
+    pub const fn contains<U>(&self, x: &U) -> bool
+    where
+        U: ~const PartialEq<T>,
+    {
+        match self {
+            Some(y) => x.eq(y),
+            None => false,
+        }
+    }
+
     /// Zips `self` with another `Option`.
     ///
     /// If `self` is `Some(s)` and `other` is `Some(o)`, this method returns `Some((s, o))`.
@@ -1581,7 +1672,7 @@ pub const fn unzip(self) -> (Option<T>, Option<U>) {
     }
 }
 
-impl<T: Copy> Option<&T> {
+impl<T> Option<&T> {
     /// Maps an `Option<&T>` to an `Option<T>` by copying the contents of the
     /// option.
     ///
@@ -1597,7 +1688,10 @@ impl<T: Copy> Option<&T> {
     #[must_use = "`self` will be dropped if the result is not used"]
     #[stable(feature = "copied", since = "1.35.0")]
     #[rustc_const_unstable(feature = "const_option", issue = "67441")]
-    pub const fn copied(self) -> Option<T> {
+    pub const fn copied(self) -> Option<T>
+    where
+        T: Copy,
+    {
         // FIXME: this implementation, which sidesteps using `Option::map` since it's not const
         // ready yet, should be reverted when possible to avoid code repetition
         match self {
@@ -1605,33 +1699,7 @@ pub const fn copied(self) -> Option<T> {
             None => None,
         }
     }
-}
-
-impl<T: Copy> Option<&mut T> {
-    /// Maps an `Option<&mut T>` to an `Option<T>` by copying the contents of the
-    /// option.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let mut x = 12;
-    /// let opt_x = Some(&mut x);
-    /// assert_eq!(opt_x, Some(&mut 12));
-    /// let copied = opt_x.copied();
-    /// assert_eq!(copied, Some(12));
-    /// ```
-    #[must_use = "`self` will be dropped if the result is not used"]
-    #[stable(feature = "copied", since = "1.35.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
-    pub const fn copied(self) -> Option<T> {
-        match self {
-            Some(&mut t) => Some(t),
-            None => None,
-        }
-    }
-}
 
-impl<T: Clone> Option<&T> {
     /// Maps an `Option<&T>` to an `Option<T>` by cloning the contents of the
     /// option.
     ///
@@ -1658,8 +1726,8 @@ pub const fn cloned(self) -> Option<T>
     }
 }
 
-impl<T: Clone> Option<&mut T> {
-    /// Maps an `Option<&mut T>` to an `Option<T>` by cloning the contents of the
+impl<T> Option<&mut T> {
+    /// Maps an `Option<&mut T>` to an `Option<T>` by copying the contents of the
     /// option.
     ///
     /// # Examples
@@ -1668,115 +1736,43 @@ impl<T: Clone> Option<&mut T> {
     /// let mut x = 12;
     /// let opt_x = Some(&mut x);
     /// assert_eq!(opt_x, Some(&mut 12));
-    /// let cloned = opt_x.cloned();
-    /// assert_eq!(cloned, Some(12));
+    /// let copied = opt_x.copied();
+    /// assert_eq!(copied, Some(12));
     /// ```
     #[must_use = "`self` will be dropped if the result is not used"]
-    #[stable(since = "1.26.0", feature = "option_ref_mut_cloned")]
-    #[rustc_const_unstable(feature = "const_option_cloned", issue = "91582")]
-    pub const fn cloned(self) -> Option<T>
-    where
-        T: ~const Clone,
-    {
-        match self {
-            Some(t) => Some(t.clone()),
-            None => None,
-        }
-    }
-}
-
-impl<T: Default> Option<T> {
-    /// Returns the contained [`Some`] value or a default.
-    ///
-    /// Consumes the `self` argument then, if [`Some`], returns the contained
-    /// value, otherwise if [`None`], returns the [default value] for that
-    /// type.
-    ///
-    /// # Examples
-    ///
-    /// Converts a string to an integer, turning poorly-formed strings
-    /// into 0 (the default value for integers). [`parse`] converts
-    /// a string to any other type that implements [`FromStr`], returning
-    /// [`None`] on error.
-    ///
-    /// ```
-    /// let good_year_from_input = "1909";
-    /// let bad_year_from_input = "190blarg";
-    /// let good_year = good_year_from_input.parse().ok().unwrap_or_default();
-    /// let bad_year = bad_year_from_input.parse().ok().unwrap_or_default();
-    ///
-    /// assert_eq!(1909, good_year);
-    /// assert_eq!(0, bad_year);
-    /// ```
-    ///
-    /// [default value]: Default::default
-    /// [`parse`]: str::parse
-    /// [`FromStr`]: crate::str::FromStr
-    #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
+    #[stable(feature = "copied", since = "1.35.0")]
     #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
-    pub const fn unwrap_or_default(self) -> T
+    pub const fn copied(self) -> Option<T>
     where
-        T: ~const Default,
+        T: Copy,
     {
         match self {
-            Some(x) => x,
-            None => Default::default(),
-        }
-    }
-}
-
-impl<T: Deref> Option<T> {
-    /// Converts from `Option<T>` (or `&Option<T>`) to `Option<&T::Target>`.
-    ///
-    /// Leaves the original Option in-place, creating a new one with a reference
-    /// to the original one, additionally coercing the contents via [`Deref`].
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// let x: Option<String> = Some("hey".to_owned());
-    /// assert_eq!(x.as_deref(), Some("hey"));
-    ///
-    /// let x: Option<String> = None;
-    /// assert_eq!(x.as_deref(), None);
-    /// ```
-    #[stable(feature = "option_deref", since = "1.40.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
-    pub const fn as_deref(&self) -> Option<&T::Target>
-    where
-        T: ~const Deref,
-    {
-        match self.as_ref() {
-            Some(t) => Some(t.deref()),
+            Some(&mut t) => Some(t),
             None => None,
         }
     }
-}
 
-impl<T: DerefMut> Option<T> {
-    /// Converts from `Option<T>` (or `&mut Option<T>`) to `Option<&mut T::Target>`.
-    ///
-    /// Leaves the original `Option` in-place, creating a new one containing a mutable reference to
-    /// the inner type's [`Deref::Target`] type.
+    /// Maps an `Option<&mut T>` to an `Option<T>` by cloning the contents of the
+    /// option.
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut x: Option<String> = Some("hey".to_owned());
-    /// assert_eq!(x.as_deref_mut().map(|x| {
-    ///     x.make_ascii_uppercase();
-    ///     x
-    /// }), Some("HEY".to_owned().as_mut_str()));
+    /// let mut x = 12;
+    /// let opt_x = Some(&mut x);
+    /// assert_eq!(opt_x, Some(&mut 12));
+    /// let cloned = opt_x.cloned();
+    /// assert_eq!(cloned, Some(12));
     /// ```
-    #[stable(feature = "option_deref", since = "1.40.0")]
-    #[rustc_const_unstable(feature = "const_option_ext", issue = "91930")]
-    pub const fn as_deref_mut(&mut self) -> Option<&mut T::Target>
+    #[must_use = "`self` will be dropped if the result is not used"]
+    #[stable(since = "1.26.0", feature = "option_ref_mut_cloned")]
+    #[rustc_const_unstable(feature = "const_option_cloned", issue = "91582")]
+    pub const fn cloned(self) -> Option<T>
     where
-        T: ~const DerefMut,
+        T: ~const Clone,
     {
-        match self.as_mut() {
-            Some(t) => Some(t.deref_mut()),
+        match self {
+            Some(t) => Some(t.clone()),
             None => None,
         }
     }
index eedea6562bd4db2ca8d42c8dbd71354c10b10813..ccb82cda54ef7499845877cbd8a0f6a2a665cc74 100644 (file)
@@ -51,6 +51,7 @@ pub const fn panic(expr: &'static str) -> ! {
 #[inline]
 #[track_caller]
 #[lang = "panic_str"] // needed for `non-fmt-panics` lint
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
 pub const fn panic_str(expr: &str) -> ! {
     panic_display(&expr);
 }
@@ -59,6 +60,7 @@ pub const fn panic_str(expr: &str) -> ! {
 #[track_caller]
 #[lang = "panic_display"] // needed for const-evaluated panics
 #[rustc_do_not_const_check] // hooked by const-eval
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
 pub const fn panic_display<T: fmt::Display>(x: &T) -> ! {
     panic_fmt(format_args!("{}", *x));
 }
@@ -89,6 +91,7 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
 #[track_caller]
 #[lang = "panic_fmt"] // needed for const-evaluated panics
 #[rustc_do_not_const_check] // hooked by const-eval
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
 pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
     if cfg!(feature = "panic_immediate_abort") {
         super::intrinsics::abort()
@@ -109,6 +112,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
 
 /// This function is used instead of panic_fmt in const eval.
 #[lang = "const_panic_fmt"]
+#[rustc_const_unstable(feature = "core_panic", issue = "none")]
 pub const fn const_panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
     if let Some(msg) = fmt.as_str() {
         panic_str(msg);
index 54f498d1dc15e2a83f8493914adbc11d139bdd2b..0fb8846288bee7835f415a159ff0c369dbd017a8 100644 (file)
 #[doc(no_inline)]
 pub use crate::concat_bytes;
 
+// Do not `doc(inline)` these `doc(hidden)` items.
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated, deprecated_in_future)]
-#[doc(no_inline)]
-pub use crate::macros::builtin::{
-    bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
-};
+#[allow(deprecated)]
+pub use crate::macros::builtin::{RustcDecodable, RustcEncodable};
 
+// Do not `doc(no_inline)` so that they become doc items on their own
+// (no public module for them to be re-exported from).
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[doc(no_inline)]
-pub use crate::macros::builtin::derive;
+pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case};
 
 #[unstable(
     feature = "cfg_accessible",
     issue = "64797",
     reason = "`cfg_accessible` is not fully implemented"
 )]
-#[doc(no_inline)]
 pub use crate::macros::builtin::cfg_accessible;
 
 #[unstable(
@@ -93,5 +91,4 @@
     issue = "82679",
     reason = "`cfg_eval` is a recently implemented feature"
 )]
-#[doc(no_inline)]
 pub use crate::macros::builtin::cfg_eval;
index a93327a0132edcf5cb9c8f27932c0f8811e3d0c5..7b826f921ca87b1eef0a8a7a8a3683e3b944baec 100644 (file)
@@ -48,6 +48,16 @@ pub const fn cast<U>(self) -> *const U {
         self as _
     }
 
+    /// Changes constness without changing the type.
+    ///
+    /// This is a bit safer than `as` because it wouldn't silently change the type if the code is
+    /// refactored.
+    #[unstable(feature = "ptr_const_cast", issue = "92675")]
+    #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+    pub const fn as_mut(self) -> *mut T {
+        self as _
+    }
+
     /// Casts a pointer to its raw bits.
     ///
     /// This is equivalent to `as usize`, but is more specific to enhance readability.
index 5fd3b2ebc60989567e2a7e8a80452a6ef90d4d49..6c50d4052976f01e8672a943e56562eddffe75ef 100644 (file)
@@ -47,6 +47,20 @@ pub const fn cast<U>(self) -> *mut U {
         self as _
     }
 
+    /// Changes constness without changing the type.
+    ///
+    /// This is a bit safer than `as` because it wouldn't silently change the type if the code is
+    /// refactored.
+    ///
+    /// While not strictly required (`*mut T` coerces to `*const T`), this is provided for symmetry
+    /// with `as_mut()` on `*const T` and may have documentation value if used instead of implicit
+    /// coercion.
+    #[unstable(feature = "ptr_const_cast", issue = "92675")]
+    #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+    pub const fn as_const(self) -> *const T {
+        self as _
+    }
+
     /// Casts a pointer to its raw bits.
     ///
     /// This is equivalent to `as usize`, but is more specific to enhance readability.
index 3cde63493d32286e6a769debd172875b7fac482b..b8f0d84746ccea04d17e7fb737fceef19e1fdd15 100644 (file)
 //! # use std::str::FromStr;
 //! let mut results = vec![];
 //! let mut errs = vec![];
-//! let nums: Vec<_> = vec!["17", "not a number", "99", "-27", "768"]
+//! let nums: Vec<_> = ["17", "not a number", "99", "-27", "768"]
 //!    .into_iter()
 //!    .map(u8::from_str)
 //!    // Save clones of the raw `Result` values to inspect
 //! [impl-FromIterator]: Result#impl-FromIterator%3CResult%3CA%2C%20E%3E%3E
 //!
 //! ```
-//! let v = vec![Ok(2), Ok(4), Err("err!"), Ok(8)];
+//! let v = [Ok(2), Ok(4), Err("err!"), Ok(8)];
 //! let res: Result<Vec<_>, &str> = v.into_iter().collect();
 //! assert_eq!(res, Err("err!"));
-//! let v = vec![Ok(2), Ok(4), Ok(8)];
+//! let v = [Ok(2), Ok(4), Ok(8)];
 //! let res: Result<Vec<_>, &str> = v.into_iter().collect();
 //! assert_eq!(res, Ok(vec![2, 4, 8]));
 //! ```
 //! [impl-Sum]: Result#impl-Sum%3CResult%3CU%2C%20E%3E%3E
 //!
 //! ```
-//! let v = vec![Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")];
+//! let v = [Err("error!"), Ok(1), Ok(2), Ok(3), Err("foo")];
 //! let res: Result<i32, &str> = v.into_iter().sum();
 //! assert_eq!(res, Err("error!"));
-//! let v: Vec<Result<i32, &str>> = vec![Ok(1), Ok(2), Ok(21)];
+//! let v = [Ok(1), Ok(2), Ok(21)];
 //! let res: Result<i32, &str> = v.into_iter().product();
 //! assert_eq!(res, Ok(42));
 //! ```
@@ -563,64 +563,6 @@ pub const fn is_err(&self) -> bool {
         !self.is_ok()
     }
 
-    /// Returns `true` if the result is an [`Ok`] value containing the given value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(option_result_contains)]
-    ///
-    /// let x: Result<u32, &str> = Ok(2);
-    /// assert_eq!(x.contains(&2), true);
-    ///
-    /// let x: Result<u32, &str> = Ok(3);
-    /// assert_eq!(x.contains(&2), false);
-    ///
-    /// let x: Result<u32, &str> = Err("Some error message");
-    /// assert_eq!(x.contains(&2), false);
-    /// ```
-    #[must_use]
-    #[inline]
-    #[unstable(feature = "option_result_contains", issue = "62358")]
-    pub fn contains<U>(&self, x: &U) -> bool
-    where
-        U: PartialEq<T>,
-    {
-        match self {
-            Ok(y) => x == y,
-            Err(_) => false,
-        }
-    }
-
-    /// Returns `true` if the result is an [`Err`] value containing the given value.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(result_contains_err)]
-    ///
-    /// let x: Result<u32, &str> = Ok(2);
-    /// assert_eq!(x.contains_err(&"Some error message"), false);
-    ///
-    /// let x: Result<u32, &str> = Err("Some error message");
-    /// assert_eq!(x.contains_err(&"Some error message"), true);
-    ///
-    /// let x: Result<u32, &str> = Err("Some other error message");
-    /// assert_eq!(x.contains_err(&"Some error message"), false);
-    /// ```
-    #[must_use]
-    #[inline]
-    #[unstable(feature = "result_contains_err", issue = "62358")]
-    pub fn contains_err<F>(&self, f: &F) -> bool
-    where
-        F: PartialEq<E>,
-    {
-        match self {
-            Ok(_) => false,
-            Err(e) => f == e,
-        }
-    }
-
     /////////////////////////////////////////////////////////////////////////
     // Adapter for each variant
     /////////////////////////////////////////////////////////////////////////
@@ -901,6 +843,56 @@ pub fn inspect_err<F: FnOnce(&E)>(self, f: F) -> Self {
         self
     }
 
+    /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&<T as Deref>::Target, &E>`.
+    ///
+    /// Coerces the [`Ok`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref)
+    /// and returns the new [`Result`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let x: Result<String, u32> = Ok("hello".to_string());
+    /// let y: Result<&str, &u32> = Ok("hello");
+    /// assert_eq!(x.as_deref(), y);
+    ///
+    /// let x: Result<String, u32> = Err(42);
+    /// let y: Result<&str, &u32> = Err(&42);
+    /// assert_eq!(x.as_deref(), y);
+    /// ```
+    #[stable(feature = "inner_deref", since = "1.47.0")]
+    pub fn as_deref(&self) -> Result<&T::Target, &E>
+    where
+        T: Deref,
+    {
+        self.as_ref().map(|t| t.deref())
+    }
+
+    /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut <T as DerefMut>::Target, &mut E>`.
+    ///
+    /// Coerces the [`Ok`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut)
+    /// and returns the new [`Result`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut s = "HELLO".to_string();
+    /// let mut x: Result<String, u32> = Ok("hello".to_string());
+    /// let y: Result<&mut str, &mut u32> = Ok(&mut s);
+    /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
+    ///
+    /// let mut i = 42;
+    /// let mut x: Result<String, u32> = Err(42);
+    /// let y: Result<&mut str, &mut u32> = Err(&mut i);
+    /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
+    /// ```
+    #[stable(feature = "inner_deref", since = "1.47.0")]
+    pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E>
+    where
+        T: DerefMut,
+    {
+        self.as_mut().map(|t| t.deref_mut())
+    }
+
     /////////////////////////////////////////////////////////////////////////
     // Iterator constructors
     /////////////////////////////////////////////////////////////////////////
@@ -951,136 +943,383 @@ pub fn iter_mut(&mut self) -> IterMut<'_, T> {
         IterMut { inner: self.as_mut().ok() }
     }
 
-    ////////////////////////////////////////////////////////////////////////
-    // Boolean operations on the values, eager and lazy
+    /////////////////////////////////////////////////////////////////////////
+    // Extract a value
     /////////////////////////////////////////////////////////////////////////
 
-    /// Returns `res` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`.
-    ///
+    /// Returns the contained [`Ok`] value, consuming the `self` value.
     ///
-    /// # Examples
+    /// # Panics
     ///
-    /// Basic usage:
+    /// Panics if the value is an [`Err`], with a panic message including the
+    /// passed message, and the content of the [`Err`].
     ///
-    /// ```
-    /// let x: Result<u32, &str> = Ok(2);
-    /// let y: Result<&str, &str> = Err("late error");
-    /// assert_eq!(x.and(y), Err("late error"));
     ///
-    /// let x: Result<u32, &str> = Err("early error");
-    /// let y: Result<&str, &str> = Ok("foo");
-    /// assert_eq!(x.and(y), Err("early error"));
+    /// # Examples
     ///
-    /// let x: Result<u32, &str> = Err("not a 2");
-    /// let y: Result<&str, &str> = Err("late error");
-    /// assert_eq!(x.and(y), Err("not a 2"));
+    /// Basic usage:
     ///
-    /// let x: Result<u32, &str> = Ok(2);
-    /// let y: Result<&str, &str> = Ok("different result type");
-    /// assert_eq!(x.and(y), Ok("different result type"));
+    /// ```should_panic
+    /// let x: Result<u32, &str> = Err("emergency failure");
+    /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure`
     /// ```
     #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> {
+    #[track_caller]
+    #[stable(feature = "result_expect", since = "1.4.0")]
+    pub fn expect(self, msg: &str) -> T
+    where
+        E: fmt::Debug,
+    {
         match self {
-            Ok(_) => res,
-            Err(e) => Err(e),
+            Ok(t) => t,
+            Err(e) => unwrap_failed(msg, &e),
         }
     }
 
-    /// Calls `op` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`.
+    /// Returns the contained [`Ok`] value, consuming the `self` value.
     ///
+    /// Because this function may panic, its use is generally discouraged.
+    /// Instead, prefer to use pattern matching and handle the [`Err`]
+    /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or
+    /// [`unwrap_or_default`].
+    ///
+    /// [`unwrap_or`]: Result::unwrap_or
+    /// [`unwrap_or_else`]: Result::unwrap_or_else
+    /// [`unwrap_or_default`]: Result::unwrap_or_default
+    ///
+    /// # Panics
+    ///
+    /// Panics if the value is an [`Err`], with a panic message provided by the
+    /// [`Err`]'s value.
     ///
-    /// This function can be used for control flow based on `Result` values.
     ///
     /// # Examples
     ///
     /// Basic usage:
     ///
     /// ```
-    /// fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
-    /// fn err(x: u32) -> Result<u32, u32> { Err(x) }
+    /// let x: Result<u32, &str> = Ok(2);
+    /// assert_eq!(x.unwrap(), 2);
+    /// ```
     ///
-    /// 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));
+    /// ```should_panic
+    /// let x: Result<u32, &str> = Err("emergency failure");
+    /// x.unwrap(); // panics with `emergency failure`
     /// ```
     #[inline]
+    #[track_caller]
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E> {
+    pub fn unwrap(self) -> T
+    where
+        E: fmt::Debug,
+    {
         match self {
-            Ok(t) => op(t),
-            Err(e) => Err(e),
+            Ok(t) => t,
+            Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e),
         }
     }
 
-    /// Returns `res` if the result is [`Err`], otherwise returns the [`Ok`] value of `self`.
-    ///
-    /// Arguments passed to `or` are eagerly evaluated; if you are passing the
-    /// result of a function call, it is recommended to use [`or_else`], which is
-    /// lazily evaluated.
+    /// Returns the contained [`Ok`] value or a default
     ///
-    /// [`or_else`]: Result::or_else
+    /// Consumes the `self` argument then, if [`Ok`], returns the contained
+    /// value, otherwise if [`Err`], returns the default value for that
+    /// type.
     ///
     /// # Examples
     ///
-    /// Basic usage:
+    /// Converts a string to an integer, turning poorly-formed strings
+    /// into 0 (the default value for integers). [`parse`] converts
+    /// a string to any other type that implements [`FromStr`], returning an
+    /// [`Err`] on error.
     ///
     /// ```
-    /// let x: Result<u32, &str> = Ok(2);
-    /// let y: Result<u32, &str> = Err("late error");
-    /// assert_eq!(x.or(y), Ok(2));
-    ///
-    /// let x: Result<u32, &str> = Err("early error");
-    /// let y: Result<u32, &str> = Ok(2);
-    /// assert_eq!(x.or(y), Ok(2));
-    ///
-    /// let x: Result<u32, &str> = Err("not a 2");
-    /// let y: Result<u32, &str> = Err("late error");
-    /// assert_eq!(x.or(y), Err("late error"));
+    /// let good_year_from_input = "1909";
+    /// let bad_year_from_input = "190blarg";
+    /// let good_year = good_year_from_input.parse().unwrap_or_default();
+    /// let bad_year = bad_year_from_input.parse().unwrap_or_default();
     ///
-    /// let x: Result<u32, &str> = Ok(2);
-    /// let y: Result<u32, &str> = Ok(100);
-    /// assert_eq!(x.or(y), Ok(2));
+    /// assert_eq!(1909, good_year);
+    /// assert_eq!(0, bad_year);
     /// ```
+    ///
+    /// [`parse`]: str::parse
+    /// [`FromStr`]: crate::str::FromStr
     #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
+    #[stable(feature = "result_unwrap_or_default", since = "1.16.0")]
+    pub fn unwrap_or_default(self) -> T
+    where
+        T: Default,
+    {
         match self {
-            Ok(v) => Ok(v),
-            Err(_) => res,
+            Ok(x) => x,
+            Err(_) => Default::default(),
         }
     }
 
-    /// Calls `op` if the result is [`Err`], otherwise returns the [`Ok`] value of `self`.
+    /// Returns the contained [`Err`] value, consuming the `self` value.
     ///
-    /// This function can be used for control flow based on result values.
+    /// # Panics
+    ///
+    /// Panics if the value is an [`Ok`], with a panic message including the
+    /// passed message, and the content of the [`Ok`].
     ///
     ///
     /// # Examples
     ///
     /// Basic usage:
     ///
-    /// ```
-    /// fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
-    /// fn err(x: u32) -> Result<u32, u32> { Err(x) }
-    ///
-    /// assert_eq!(Ok(2).or_else(sq).or_else(sq), Ok(2));
-    /// assert_eq!(Ok(2).or_else(err).or_else(sq), Ok(2));
-    /// assert_eq!(Err(3).or_else(sq).or_else(err), Ok(9));
-    /// assert_eq!(Err(3).or_else(err).or_else(err), Err(3));
+    /// ```should_panic
+    /// let x: Result<u32, &str> = Ok(10);
+    /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10`
     /// ```
     #[inline]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> {
+    #[track_caller]
+    #[stable(feature = "result_expect_err", since = "1.17.0")]
+    pub fn expect_err(self, msg: &str) -> E
+    where
+        T: fmt::Debug,
+    {
         match self {
-            Ok(t) => Ok(t),
-            Err(e) => op(e),
+            Ok(t) => unwrap_failed(msg, &t),
+            Err(e) => e,
         }
     }
 
-    /// Returns the contained [`Ok`] value or a provided default.
+    /// Returns the contained [`Err`] value, consuming the `self` value.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the value is an [`Ok`], with a custom panic message provided
+    /// by the [`Ok`]'s value.
+    ///
+    /// # Examples
+    ///
+    /// ```should_panic
+    /// let x: Result<u32, &str> = Ok(2);
+    /// x.unwrap_err(); // panics with `2`
+    /// ```
+    ///
+    /// ```
+    /// let x: Result<u32, &str> = Err("emergency failure");
+    /// assert_eq!(x.unwrap_err(), "emergency failure");
+    /// ```
+    #[inline]
+    #[track_caller]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn unwrap_err(self) -> E
+    where
+        T: fmt::Debug,
+    {
+        match self {
+            Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", &t),
+            Err(e) => e,
+        }
+    }
+
+    /// Returns the contained [`Ok`] value, but never panics.
+    ///
+    /// Unlike [`unwrap`], this method is known to never panic on the
+    /// result types it is implemented for. Therefore, it can be used
+    /// instead of `unwrap` as a maintainability safeguard that will fail
+    /// to compile if the error type of the `Result` is later changed
+    /// to an error that can actually occur.
+    ///
+    /// [`unwrap`]: Result::unwrap
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # #![feature(never_type)]
+    /// # #![feature(unwrap_infallible)]
+    ///
+    /// fn only_good_news() -> Result<String, !> {
+    ///     Ok("this is fine".into())
+    /// }
+    ///
+    /// let s: String = only_good_news().into_ok();
+    /// println!("{}", s);
+    /// ```
+    #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
+    #[inline]
+    pub fn into_ok(self) -> T
+    where
+        E: Into<!>,
+    {
+        match self {
+            Ok(x) => x,
+            Err(e) => e.into(),
+        }
+    }
+
+    /// Returns the contained [`Err`] value, but never panics.
+    ///
+    /// Unlike [`unwrap_err`], this method is known to never panic on the
+    /// result types it is implemented for. Therefore, it can be used
+    /// instead of `unwrap_err` as a maintainability safeguard that will fail
+    /// to compile if the ok type of the `Result` is later changed
+    /// to a type that can actually occur.
+    ///
+    /// [`unwrap_err`]: Result::unwrap_err
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// # #![feature(never_type)]
+    /// # #![feature(unwrap_infallible)]
+    ///
+    /// fn only_bad_news() -> Result<!, String> {
+    ///     Err("Oops, it failed".into())
+    /// }
+    ///
+    /// let error: String = only_bad_news().into_err();
+    /// println!("{}", error);
+    /// ```
+    #[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
+    #[inline]
+    pub fn into_err(self) -> E
+    where
+        T: Into<!>,
+    {
+        match self {
+            Ok(x) => x.into(),
+            Err(e) => e,
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////////////
+    // Boolean operations on the values, eager and lazy
+    /////////////////////////////////////////////////////////////////////////
+
+    /// Returns `res` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`.
+    ///
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// let x: Result<u32, &str> = Ok(2);
+    /// let y: Result<&str, &str> = Err("late error");
+    /// assert_eq!(x.and(y), Err("late error"));
+    ///
+    /// let x: Result<u32, &str> = Err("early error");
+    /// let y: Result<&str, &str> = Ok("foo");
+    /// assert_eq!(x.and(y), Err("early error"));
+    ///
+    /// let x: Result<u32, &str> = Err("not a 2");
+    /// let y: Result<&str, &str> = Err("late error");
+    /// assert_eq!(x.and(y), Err("not a 2"));
+    ///
+    /// let x: Result<u32, &str> = Ok(2);
+    /// let y: Result<&str, &str> = Ok("different result type");
+    /// assert_eq!(x.and(y), Ok("different result type"));
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn and<U>(self, res: Result<U, E>) -> Result<U, E> {
+        match self {
+            Ok(_) => res,
+            Err(e) => Err(e),
+        }
+    }
+
+    /// Calls `op` if the result is [`Ok`], otherwise returns the [`Err`] value of `self`.
+    ///
+    ///
+    /// This function can be used for control flow based on `Result` values.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// 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));
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E> {
+        match self {
+            Ok(t) => op(t),
+            Err(e) => Err(e),
+        }
+    }
+
+    /// Returns `res` if the result is [`Err`], otherwise returns the [`Ok`] value of `self`.
+    ///
+    /// Arguments passed to `or` are eagerly evaluated; if you are passing the
+    /// result of a function call, it is recommended to use [`or_else`], which is
+    /// lazily evaluated.
+    ///
+    /// [`or_else`]: Result::or_else
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// let x: Result<u32, &str> = Ok(2);
+    /// let y: Result<u32, &str> = Err("late error");
+    /// assert_eq!(x.or(y), Ok(2));
+    ///
+    /// let x: Result<u32, &str> = Err("early error");
+    /// let y: Result<u32, &str> = Ok(2);
+    /// assert_eq!(x.or(y), Ok(2));
+    ///
+    /// let x: Result<u32, &str> = Err("not a 2");
+    /// let y: Result<u32, &str> = Err("late error");
+    /// assert_eq!(x.or(y), Err("late error"));
+    ///
+    /// let x: Result<u32, &str> = Ok(2);
+    /// let y: Result<u32, &str> = Ok(100);
+    /// assert_eq!(x.or(y), Ok(2));
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn or<F>(self, res: Result<T, F>) -> Result<T, F> {
+        match self {
+            Ok(v) => Ok(v),
+            Err(_) => res,
+        }
+    }
+
+    /// Calls `op` if the result is [`Err`], otherwise returns the [`Ok`] value of `self`.
+    ///
+    /// This function can be used for control flow based on result values.
+    ///
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// fn sq(x: u32) -> Result<u32, u32> { Ok(x * x) }
+    /// fn err(x: u32) -> Result<u32, u32> { Err(x) }
+    ///
+    /// assert_eq!(Ok(2).or_else(sq).or_else(sq), Ok(2));
+    /// assert_eq!(Ok(2).or_else(err).or_else(sq), Ok(2));
+    /// assert_eq!(Err(3).or_else(sq).or_else(err), Ok(9));
+    /// assert_eq!(Err(3).or_else(err).or_else(err), Err(3));
+    /// ```
+    #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F> {
+        match self {
+            Ok(t) => Ok(t),
+            Err(e) => op(e),
+        }
+    }
+
+    /// Returns the contained [`Ok`] value or a provided default.
     ///
     /// Arguments passed to `unwrap_or` are eagerly evaluated; if you are passing
     /// the result of a function call, it is recommended to use [`unwrap_or_else`],
@@ -1194,365 +1433,155 @@ pub unsafe fn unwrap_err_unchecked(self) -> E {
             Err(e) => e,
         }
     }
-}
 
-impl<T: Copy, E> Result<&T, E> {
-    /// Maps a `Result<&T, E>` to a `Result<T, E>` by copying the contents of the
-    /// `Ok` part.
+    /////////////////////////////////////////////////////////////////////////
+    // Misc or niche
+    /////////////////////////////////////////////////////////////////////////
+
+    /// Returns `true` if the result is an [`Ok`] value containing the given value.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(result_copied)]
-    /// let val = 12;
-    /// let x: Result<&i32, i32> = Ok(&val);
-    /// assert_eq!(x, Ok(&12));
-    /// let copied = x.copied();
-    /// assert_eq!(copied, Ok(12));
-    /// ```
-    #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")]
-    pub fn copied(self) -> Result<T, E> {
-        self.map(|&t| t)
-    }
-}
-
-impl<T: Copy, E> Result<&mut T, E> {
-    /// Maps a `Result<&mut T, E>` to a `Result<T, E>` by copying the contents of the
-    /// `Ok` part.
+    /// #![feature(option_result_contains)]
     ///
-    /// # Examples
+    /// let x: Result<u32, &str> = Ok(2);
+    /// assert_eq!(x.contains(&2), true);
+    ///
+    /// let x: Result<u32, &str> = Ok(3);
+    /// assert_eq!(x.contains(&2), false);
     ///
+    /// let x: Result<u32, &str> = Err("Some error message");
+    /// assert_eq!(x.contains(&2), false);
     /// ```
-    /// #![feature(result_copied)]
-    /// let mut val = 12;
-    /// let x: Result<&mut i32, i32> = Ok(&mut val);
-    /// assert_eq!(x, Ok(&mut 12));
-    /// let copied = x.copied();
-    /// assert_eq!(copied, Ok(12));
-    /// ```
-    #[unstable(feature = "result_copied", reason = "newly added", issue = "63168")]
-    pub fn copied(self) -> Result<T, E> {
-        self.map(|&mut t| t)
-    }
-}
-
-impl<T: Clone, E> Result<&T, E> {
-    /// Maps a `Result<&T, E>` to a `Result<T, E>` by cloning the contents of the
-    /// `Ok` part.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(result_cloned)]
-    /// let val = 12;
-    /// let x: Result<&i32, i32> = Ok(&val);
-    /// assert_eq!(x, Ok(&12));
-    /// let cloned = x.cloned();
-    /// assert_eq!(cloned, Ok(12));
-    /// ```
-    #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")]
-    pub fn cloned(self) -> Result<T, E> {
-        self.map(|t| t.clone())
-    }
-}
-
-impl<T: Clone, E> Result<&mut T, E> {
-    /// Maps a `Result<&mut T, E>` to a `Result<T, E>` by cloning the contents of the
-    /// `Ok` part.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(result_cloned)]
-    /// let mut val = 12;
-    /// let x: Result<&mut i32, i32> = Ok(&mut val);
-    /// assert_eq!(x, Ok(&mut 12));
-    /// let cloned = x.cloned();
-    /// assert_eq!(cloned, Ok(12));
-    /// ```
-    #[unstable(feature = "result_cloned", reason = "newly added", issue = "63168")]
-    pub fn cloned(self) -> Result<T, E> {
-        self.map(|t| t.clone())
-    }
-}
-
-impl<T, E: fmt::Debug> Result<T, E> {
-    /// Returns the contained [`Ok`] value, consuming the `self` value.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the value is an [`Err`], with a panic message including the
-    /// passed message, and the content of the [`Err`].
-    ///
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```should_panic
-    /// let x: Result<u32, &str> = Err("emergency failure");
-    /// x.expect("Testing expect"); // panics with `Testing expect: emergency failure`
-    /// ```
-    #[inline]
-    #[track_caller]
-    #[stable(feature = "result_expect", since = "1.4.0")]
-    pub fn expect(self, msg: &str) -> T {
-        match self {
-            Ok(t) => t,
-            Err(e) => unwrap_failed(msg, &e),
-        }
-    }
-
-    /// Returns the contained [`Ok`] value, consuming the `self` value.
-    ///
-    /// Because this function may panic, its use is generally discouraged.
-    /// Instead, prefer to use pattern matching and handle the [`Err`]
-    /// case explicitly, or call [`unwrap_or`], [`unwrap_or_else`], or
-    /// [`unwrap_or_default`].
-    ///
-    /// [`unwrap_or`]: Result::unwrap_or
-    /// [`unwrap_or_else`]: Result::unwrap_or_else
-    /// [`unwrap_or_default`]: Result::unwrap_or_default
-    ///
-    /// # Panics
-    ///
-    /// Panics if the value is an [`Err`], with a panic message provided by the
-    /// [`Err`]'s value.
-    ///
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// let x: Result<u32, &str> = Ok(2);
-    /// assert_eq!(x.unwrap(), 2);
-    /// ```
-    ///
-    /// ```should_panic
-    /// let x: Result<u32, &str> = Err("emergency failure");
-    /// x.unwrap(); // panics with `emergency failure`
-    /// ```
+    #[must_use]
     #[inline]
-    #[track_caller]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap(self) -> T {
+    #[unstable(feature = "option_result_contains", issue = "62358")]
+    pub fn contains<U>(&self, x: &U) -> bool
+    where
+        U: PartialEq<T>,
+    {
         match self {
-            Ok(t) => t,
-            Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e),
+            Ok(y) => x == y,
+            Err(_) => false,
         }
     }
-}
 
-impl<T: fmt::Debug, E> Result<T, E> {
-    /// Returns the contained [`Err`] value, consuming the `self` value.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the value is an [`Ok`], with a panic message including the
-    /// passed message, and the content of the [`Ok`].
-    ///
+    /// Returns `true` if the result is an [`Err`] value containing the given value.
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
-    /// ```should_panic
-    /// let x: Result<u32, &str> = Ok(10);
-    /// x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10`
     /// ```
-    #[inline]
-    #[track_caller]
-    #[stable(feature = "result_expect_err", since = "1.17.0")]
-    pub fn expect_err(self, msg: &str) -> E {
-        match self {
-            Ok(t) => unwrap_failed(msg, &t),
-            Err(e) => e,
-        }
-    }
-
-    /// Returns the contained [`Err`] value, consuming the `self` value.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the value is an [`Ok`], with a custom panic message provided
-    /// by the [`Ok`]'s value.
-    ///
-    /// # Examples
+    /// #![feature(result_contains_err)]
     ///
-    /// ```should_panic
     /// let x: Result<u32, &str> = Ok(2);
-    /// x.unwrap_err(); // panics with `2`
-    /// ```
-    ///
-    /// ```
-    /// let x: Result<u32, &str> = Err("emergency failure");
-    /// assert_eq!(x.unwrap_err(), "emergency failure");
-    /// ```
-    #[inline]
-    #[track_caller]
-    #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn unwrap_err(self) -> E {
-        match self {
-            Ok(t) => unwrap_failed("called `Result::unwrap_err()` on an `Ok` value", &t),
-            Err(e) => e,
-        }
-    }
-}
-
-impl<T: Default, E> Result<T, E> {
-    /// Returns the contained [`Ok`] value or a default
-    ///
-    /// Consumes the `self` argument then, if [`Ok`], returns the contained
-    /// value, otherwise if [`Err`], returns the default value for that
-    /// type.
-    ///
-    /// # Examples
-    ///
-    /// Converts a string to an integer, turning poorly-formed strings
-    /// into 0 (the default value for integers). [`parse`] converts
-    /// a string to any other type that implements [`FromStr`], returning an
-    /// [`Err`] on error.
+    /// assert_eq!(x.contains_err(&"Some error message"), false);
     ///
-    /// ```
-    /// let good_year_from_input = "1909";
-    /// let bad_year_from_input = "190blarg";
-    /// let good_year = good_year_from_input.parse().unwrap_or_default();
-    /// let bad_year = bad_year_from_input.parse().unwrap_or_default();
+    /// let x: Result<u32, &str> = Err("Some error message");
+    /// assert_eq!(x.contains_err(&"Some error message"), true);
     ///
-    /// assert_eq!(1909, good_year);
-    /// assert_eq!(0, bad_year);
+    /// let x: Result<u32, &str> = Err("Some other error message");
+    /// assert_eq!(x.contains_err(&"Some error message"), false);
     /// ```
-    ///
-    /// [`parse`]: str::parse
-    /// [`FromStr`]: crate::str::FromStr
+    #[must_use]
     #[inline]
-    #[stable(feature = "result_unwrap_or_default", since = "1.16.0")]
-    pub fn unwrap_or_default(self) -> T {
+    #[unstable(feature = "result_contains_err", issue = "62358")]
+    pub fn contains_err<F>(&self, f: &F) -> bool
+    where
+        F: PartialEq<E>,
+    {
         match self {
-            Ok(x) => x,
-            Err(_) => Default::default(),
+            Ok(_) => false,
+            Err(e) => f == e,
         }
     }
 }
 
-#[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
-impl<T, E: Into<!>> Result<T, E> {
-    /// Returns the contained [`Ok`] value, but never panics.
-    ///
-    /// Unlike [`unwrap`], this method is known to never panic on the
-    /// result types it is implemented for. Therefore, it can be used
-    /// instead of `unwrap` as a maintainability safeguard that will fail
-    /// to compile if the error type of the `Result` is later changed
-    /// to an error that can actually occur.
-    ///
-    /// [`unwrap`]: Result::unwrap
+impl<T, E> Result<&T, E> {
+    /// Maps a `Result<&T, E>` to a `Result<T, E>` by copying the contents of the
+    /// `Ok` part.
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
-    /// # #![feature(never_type)]
-    /// # #![feature(unwrap_infallible)]
-    ///
-    /// fn only_good_news() -> Result<String, !> {
-    ///     Ok("this is fine".into())
-    /// }
-    ///
-    /// let s: String = only_good_news().into_ok();
-    /// println!("{}", s);
+    /// let val = 12;
+    /// let x: Result<&i32, i32> = Ok(&val);
+    /// assert_eq!(x, Ok(&12));
+    /// let copied = x.copied();
+    /// assert_eq!(copied, Ok(12));
     /// ```
     #[inline]
-    pub fn into_ok(self) -> T {
-        match self {
-            Ok(x) => x,
-            Err(e) => e.into(),
-        }
+    #[stable(feature = "result_copied", since = "1.59.0")]
+    pub fn copied(self) -> Result<T, E>
+    where
+        T: Copy,
+    {
+        self.map(|&t| t)
     }
-}
 
-#[unstable(feature = "unwrap_infallible", reason = "newly added", issue = "61695")]
-impl<T: Into<!>, E> Result<T, E> {
-    /// Returns the contained [`Err`] value, but never panics.
-    ///
-    /// Unlike [`unwrap_err`], this method is known to never panic on the
-    /// result types it is implemented for. Therefore, it can be used
-    /// instead of `unwrap_err` as a maintainability safeguard that will fail
-    /// to compile if the ok type of the `Result` is later changed
-    /// to a type that can actually occur.
-    ///
-    /// [`unwrap_err`]: Result::unwrap_err
+    /// Maps a `Result<&T, E>` to a `Result<T, E>` by cloning the contents of the
+    /// `Ok` part.
     ///
     /// # Examples
     ///
-    /// Basic usage:
-    ///
     /// ```
-    /// # #![feature(never_type)]
-    /// # #![feature(unwrap_infallible)]
-    ///
-    /// fn only_bad_news() -> Result<!, String> {
-    ///     Err("Oops, it failed".into())
-    /// }
-    ///
-    /// let error: String = only_bad_news().into_err();
-    /// println!("{}", error);
+    /// let val = 12;
+    /// let x: Result<&i32, i32> = Ok(&val);
+    /// assert_eq!(x, Ok(&12));
+    /// let cloned = x.cloned();
+    /// assert_eq!(cloned, Ok(12));
     /// ```
     #[inline]
-    pub fn into_err(self) -> E {
-        match self {
-            Ok(x) => x.into(),
-            Err(e) => e,
-        }
+    #[stable(feature = "result_cloned", since = "1.59.0")]
+    pub fn cloned(self) -> Result<T, E>
+    where
+        T: Clone,
+    {
+        self.map(|t| t.clone())
     }
 }
 
-impl<T: Deref, E> Result<T, E> {
-    /// Converts from `Result<T, E>` (or `&Result<T, E>`) to `Result<&<T as Deref>::Target, &E>`.
-    ///
-    /// Coerces the [`Ok`] variant of the original [`Result`] via [`Deref`](crate::ops::Deref)
-    /// and returns the new [`Result`].
+impl<T, E> Result<&mut T, E> {
+    /// Maps a `Result<&mut T, E>` to a `Result<T, E>` by copying the contents of the
+    /// `Ok` part.
     ///
     /// # Examples
     ///
     /// ```
-    /// let x: Result<String, u32> = Ok("hello".to_string());
-    /// let y: Result<&str, &u32> = Ok("hello");
-    /// assert_eq!(x.as_deref(), y);
-    ///
-    /// let x: Result<String, u32> = Err(42);
-    /// let y: Result<&str, &u32> = Err(&42);
-    /// assert_eq!(x.as_deref(), y);
+    /// let mut val = 12;
+    /// let x: Result<&mut i32, i32> = Ok(&mut val);
+    /// assert_eq!(x, Ok(&mut 12));
+    /// let copied = x.copied();
+    /// assert_eq!(copied, Ok(12));
     /// ```
-    #[stable(feature = "inner_deref", since = "1.47.0")]
-    pub fn as_deref(&self) -> Result<&T::Target, &E> {
-        self.as_ref().map(|t| t.deref())
+    #[inline]
+    #[stable(feature = "result_copied", since = "1.59.0")]
+    pub fn copied(self) -> Result<T, E>
+    where
+        T: Copy,
+    {
+        self.map(|&mut t| t)
     }
-}
 
-impl<T: DerefMut, E> Result<T, E> {
-    /// Converts from `Result<T, E>` (or `&mut Result<T, E>`) to `Result<&mut <T as DerefMut>::Target, &mut E>`.
-    ///
-    /// Coerces the [`Ok`] variant of the original [`Result`] via [`DerefMut`](crate::ops::DerefMut)
-    /// and returns the new [`Result`].
+    /// Maps a `Result<&mut T, E>` to a `Result<T, E>` by cloning the contents of the
+    /// `Ok` part.
     ///
     /// # Examples
     ///
     /// ```
-    /// let mut s = "HELLO".to_string();
-    /// let mut x: Result<String, u32> = Ok("hello".to_string());
-    /// let y: Result<&mut str, &mut u32> = Ok(&mut s);
-    /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
-    ///
-    /// let mut i = 42;
-    /// let mut x: Result<String, u32> = Err(42);
-    /// let y: Result<&mut str, &mut u32> = Err(&mut i);
-    /// assert_eq!(x.as_deref_mut().map(|x| { x.make_ascii_uppercase(); x }), y);
+    /// let mut val = 12;
+    /// let x: Result<&mut i32, i32> = Ok(&mut val);
+    /// assert_eq!(x, Ok(&mut 12));
+    /// let cloned = x.cloned();
+    /// assert_eq!(cloned, Ok(12));
     /// ```
-    #[stable(feature = "inner_deref", since = "1.47.0")]
-    pub fn as_deref_mut(&mut self) -> Result<&mut T::Target, &mut E> {
-        self.as_mut().map(|t| t.deref_mut())
+    #[inline]
+    #[stable(feature = "result_cloned", since = "1.59.0")]
+    pub fn cloned(self) -> Result<T, E>
+    where
+        T: Clone,
+    {
+        self.map(|t| t.clone())
     }
 }
 
index 49dce89a494c862eda3347db08ac852ad779c41e..0599f2740139410d67f745078e91393c4fbdbaa0 100644 (file)
@@ -585,6 +585,7 @@ pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_swap", issue = "83163")]
     #[inline]
+    #[track_caller]
     pub const fn swap(&mut self, a: usize, b: usize) {
         let _ = &self[a];
         let _ = &self[b];
@@ -1501,6 +1502,7 @@ pub fn group_by_mut<F>(&mut self, pred: F) -> GroupByMut<'_, T, F>
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[track_caller]
     pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
         assert!(mid <= self.len());
         // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
@@ -1531,6 +1533,7 @@ pub fn split_at(&self, mid: usize) -> (&[T], &[T]) {
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
+    #[track_caller]
     pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) {
         assert!(mid <= self.len());
         // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which
@@ -1670,6 +1673,7 @@ pub unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [
     /// ```
     #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
     #[inline]
+    #[track_caller]
     pub fn split_array_ref<const N: usize>(&self) -> (&[T; N], &[T]) {
         let (a, b) = self.split_at(N);
         // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at)
@@ -1701,6 +1705,7 @@ pub unsafe fn split_at_mut_unchecked(&mut self, mid: usize) -> (&mut [T], &mut [
     /// ```
     #[unstable(feature = "split_array", reason = "new API", issue = "90091")]
     #[inline]
+    #[track_caller]
     pub fn split_array_mut<const N: usize>(&mut self) -> (&mut [T; N], &mut [T]) {
         let (a, b) = self.split_at_mut(N);
         // SAFETY: a points to [T; N]? Yes it's [T] of length N (checked by split_at_mut)
index b5e6083c663518e43eac88ec9c81fd5a9877a0a3..8f58e8897b34bc493ce01a38fbda4d0ad838d0e5 100644 (file)
@@ -12,7 +12,7 @@
 
 /// When dropped, copies from `src` into `dest`.
 struct CopyOnDrop<T> {
-    src: *mut T,
+    src: *const T,
     dest: *mut T,
 }
 
@@ -54,9 +54,9 @@ fn shift_head<T, F>(v: &mut [T], is_less: &mut F)
             // Read the first element into a stack-allocated variable. If a following comparison
             // operation panics, `hole` will get dropped and automatically write the element back
             // into the slice.
-            let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
+            let tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(0)));
             let v = v.as_mut_ptr();
-            let mut hole = CopyOnDrop { src: &mut *tmp, dest: v.add(1) };
+            let mut hole = CopyOnDrop { src: &*tmp, dest: v.add(1) };
             ptr::copy_nonoverlapping(v.add(1), v.add(0), 1);
 
             for i in 2..len {
@@ -100,9 +100,9 @@ fn shift_tail<T, F>(v: &mut [T], is_less: &mut F)
             // Read the last element into a stack-allocated variable. If a following comparison
             // operation panics, `hole` will get dropped and automatically write the element back
             // into the slice.
-            let mut tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
+            let tmp = mem::ManuallyDrop::new(ptr::read(v.get_unchecked(len - 1)));
             let v = v.as_mut_ptr();
-            let mut hole = CopyOnDrop { src: &mut *tmp, dest: v.add(len - 2) };
+            let mut hole = CopyOnDrop { src: &*tmp, dest: v.add(len - 2) };
             ptr::copy_nonoverlapping(v.add(len - 2), v.add(len - 1), 1);
 
             for i in (0..len - 2).rev() {
@@ -498,8 +498,8 @@ fn partition<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> (usize, bool)
         // operation panics, the pivot will be automatically written back into the slice.
 
         // SAFETY: `pivot` is a reference to the first element of `v`, so `ptr::read` is safe.
-        let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
-        let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot };
+        let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
+        let _pivot_guard = CopyOnDrop { src: &*tmp, dest: pivot };
         let pivot = &*tmp;
 
         // Find the first pair of out-of-order elements.
@@ -551,8 +551,8 @@ fn partition_equal<T, F>(v: &mut [T], pivot: usize, is_less: &mut F) -> usize
     // Read the pivot into a stack-allocated variable for efficiency. If a following comparison
     // operation panics, the pivot will be automatically written back into the slice.
     // SAFETY: The pointer here is valid because it is obtained from a reference to a slice.
-    let mut tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
-    let _pivot_guard = CopyOnDrop { src: &mut *tmp, dest: pivot };
+    let tmp = mem::ManuallyDrop::new(unsafe { ptr::read(pivot) });
+    let _pivot_guard = CopyOnDrop { src: &*tmp, dest: pivot };
     let pivot = &*tmp;
 
     // Now partition the slice.
index 1dd3b2d8e3c8d8c2ae4a0202aa090e64c96a16de..27243d8ca703060aea8362fd75fc301a02150200 100644 (file)
@@ -333,10 +333,10 @@ pub fn get_mut(&mut self) -> &mut bool {
     #[inline]
     #[cfg(target_has_atomic_equal_alignment = "8")]
     #[unstable(feature = "atomic_from_mut", issue = "76314")]
-    pub fn from_mut(v: &mut bool) -> &Self {
+    pub fn from_mut(v: &mut bool) -> &mut Self {
         // SAFETY: the mutable reference guarantees unique ownership, and
         // alignment of both `bool` and `Self` is 1.
-        unsafe { &*(v as *mut bool as *mut Self) }
+        unsafe { &mut *(v as *mut bool as *mut Self) }
     }
 
     /// Consumes the atomic and returns the contained value.
@@ -934,14 +934,14 @@ pub fn get_mut(&mut self) -> &mut *mut T {
     #[inline]
     #[cfg(target_has_atomic_equal_alignment = "ptr")]
     #[unstable(feature = "atomic_from_mut", issue = "76314")]
-    pub fn from_mut(v: &mut *mut T) -> &Self {
+    pub fn from_mut(v: &mut *mut T) -> &mut Self {
         use crate::mem::align_of;
         let [] = [(); align_of::<AtomicPtr<()>>() - align_of::<*mut ()>()];
         // SAFETY:
         //  - the mutable reference guarantees unique ownership.
         //  - the alignment of `*mut T` and `Self` is the same on all platforms
         //    supported by rust, as verified above.
-        unsafe { &*(v as *mut *mut T as *mut Self) }
+        unsafe { &mut *(v as *mut *mut T as *mut Self) }
     }
 
     /// Consumes the atomic and returns the contained value.
@@ -1447,14 +1447,14 @@ pub fn get_mut(&mut self) -> &mut $int_type {
             #[inline]
             #[$cfg_align]
             #[unstable(feature = "atomic_from_mut", issue = "76314")]
-            pub fn from_mut(v: &mut $int_type) -> &Self {
+            pub fn from_mut(v: &mut $int_type) -> &mut Self {
                 use crate::mem::align_of;
                 let [] = [(); align_of::<Self>() - align_of::<$int_type>()];
                 // SAFETY:
                 //  - the mutable reference guarantees unique ownership.
                 //  - the alignment of `$int_type` and `Self` is the
                 //    same, as promised by $cfg_align and verified above.
-                unsafe { &*(v as *mut $int_type as *mut Self) }
+                unsafe { &mut *(v as *mut $int_type as *mut Self) }
             }
 
             /// Consumes the atomic and returns the contained value.
index b336c03b5adbe04464d72376f78e9bb122d34fbf..72ae59b6b2f5feaf14a60a12345bef968c4a4133 100644 (file)
@@ -74,7 +74,7 @@ fn test_intersperse_with() {
     struct NotClone {
         u: u32,
     }
-    let r = vec![NotClone { u: 0 }, NotClone { u: 1 }]
+    let r = [NotClone { u: 0 }, NotClone { u: 1 }]
         .into_iter()
         .intersperse_with(|| NotClone { u: 2 })
         .collect::<Vec<_>>();
@@ -120,7 +120,7 @@ fn next(&mut self) -> Option<i32> {
 
 #[test]
 fn test_intersperse_collect_string() {
-    let contents = vec![1, 2, 3];
+    let contents = [1, 2, 3];
 
     let contents_string = contents
         .into_iter()
index 390414d4aa213b14f489d82de0acb84d01ebd89b..c1a1c29b609b7077342ac32b4842403baa038da7 100644 (file)
@@ -144,7 +144,7 @@ fn test_iterator_peekable_rfold() {
 #[test]
 fn test_iterator_peekable_next_if_eq() {
     // first, try on references
-    let xs = vec!["Heart", "of", "Gold"];
+    let xs = ["Heart", "of", "Gold"];
     let mut it = xs.into_iter().peekable();
     // try before `peek()`
     assert_eq!(it.next_if_eq(&"trillian"), None);
@@ -157,7 +157,7 @@ fn test_iterator_peekable_next_if_eq() {
     assert_eq!(it.next(), Some("Gold"));
 
     // make sure comparison works for owned values
-    let xs = vec![String::from("Ludicrous"), "speed".into()];
+    let xs = [String::from("Ludicrous"), "speed".into()];
     let mut it = xs.into_iter().peekable();
     // make sure basic functionality works
     assert_eq!(it.next_if_eq("Ludicrous"), Some("Ludicrous".into()));
@@ -167,7 +167,7 @@ fn test_iterator_peekable_next_if_eq() {
 
 #[test]
 fn test_iterator_peekable_mut() {
-    let mut it = vec![1, 2, 3].into_iter().peekable();
+    let mut it = [1, 2, 3].into_iter().peekable();
     if let Some(p) = it.peek_mut() {
         if *p == 1 {
             *p = 5;
index d38bca1e3b3ea9265ad1c410c3d6704e5d08bcf9..bb4da831412770386744bc4cdc73cbe3d4a080b0 100644 (file)
@@ -456,25 +456,25 @@ fn half_if_even(x: &isize) -> Option<isize> {
 
 #[test]
 fn test_try_reduce() {
-    let v: Vec<usize> = vec![1, 2, 3, 4, 5];
+    let v = [1usize, 2, 3, 4, 5];
     let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
     assert_eq!(sum, Some(Some(15)));
 
-    let v: Vec<usize> = vec![1, 2, 3, 4, 5, usize::MAX];
+    let v = [1, 2, 3, 4, 5, usize::MAX];
     let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
     assert_eq!(sum, None);
 
-    let v: Vec<usize> = Vec::new();
+    let v: [usize; 0] = [];
     let sum = v.into_iter().try_reduce(|x, y| x.checked_add(y));
     assert_eq!(sum, Some(None));
 
-    let v = vec!["1", "2", "3", "4", "5"];
+    let v = ["1", "2", "3", "4", "5"];
     let max = v.into_iter().try_reduce(|x, y| {
         if x.parse::<usize>().ok()? > y.parse::<usize>().ok()? { Some(x) } else { Some(y) }
     });
     assert_eq!(max, Some(Some("5")));
 
-    let v = vec!["1", "2", "3", "4", "5"];
+    let v = ["1", "2", "3", "4", "5"];
     let max: Result<Option<_>, <usize as std::str::FromStr>::Err> =
         v.into_iter().try_reduce(|x, y| {
             if x.parse::<usize>()? > y.parse::<usize>()? { Ok(x) } else { Ok(y) }
index ec700346ac91d2f6e2433e8ce620b78868b01f18..841c114063dc1de7c783a6222dec1452fa512105 100644 (file)
@@ -15,6 +15,7 @@
 #![feature(const_convert)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_maybe_uninit_assume_init)]
+#![feature(const_maybe_uninit_assume_init_read)]
 #![feature(const_num_from_num)]
 #![feature(const_ptr_read)]
 #![feature(const_ptr_write)]
@@ -46,7 +47,6 @@
 #![feature(slice_take)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_array_assume_init)]
-#![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_write_slice)]
 #![feature(min_specialization)]
 #![feature(numfmt)]
index 1457064cc8d572028374f5e95fda860a605dce53..416e7cea7a67bcf040206dbcc777f1d6a6838aeb 100644 (file)
@@ -1,4 +1,5 @@
 use core::num::bignum::tests::Big8x3 as Big;
+use core::num::bignum::Big32x40;
 
 #[test]
 #[should_panic]
@@ -215,6 +216,16 @@ fn test_get_bit_out_of_range() {
 
 #[test]
 fn test_bit_length() {
+    for i in 0..8 * 3 {
+        // 010000...000
+        assert_eq!(Big::from_small(1).mul_pow2(i).bit_length(), i + 1);
+    }
+    for i in 1..8 * 3 - 1 {
+        // 010000...001
+        assert_eq!(Big::from_small(1).mul_pow2(i).add(&Big::from_small(1)).bit_length(), i + 1);
+        // 110000...000
+        assert_eq!(Big::from_small(3).mul_pow2(i).bit_length(), i + 2);
+    }
     assert_eq!(Big::from_small(0).bit_length(), 0);
     assert_eq!(Big::from_small(1).bit_length(), 1);
     assert_eq!(Big::from_small(5).bit_length(), 3);
@@ -223,6 +234,30 @@ fn test_bit_length() {
     assert_eq!(Big::from_u64(0xffffff).bit_length(), 24);
 }
 
+#[test]
+fn test_bit_length_32x40() {
+    for i in 0..32 * 40 {
+        // 010000...000
+        assert_eq!(Big32x40::from_small(1).mul_pow2(i).bit_length(), i + 1);
+    }
+    for i in 1..32 * 40 - 1 {
+        // 010000...001
+        assert_eq!(
+            Big32x40::from_small(1).mul_pow2(i).add(&Big32x40::from_small(1)).bit_length(),
+            i + 1
+        );
+        // 110000...000
+        assert_eq!(Big32x40::from_small(3).mul_pow2(i).bit_length(), i + 2);
+    }
+    assert_eq!(Big32x40::from_small(0).bit_length(), 0);
+    assert_eq!(Big32x40::from_small(1).bit_length(), 1);
+    assert_eq!(Big32x40::from_small(5).bit_length(), 3);
+    assert_eq!(Big32x40::from_small(0x18).bit_length(), 5);
+    assert_eq!(Big32x40::from_u64(0x4073).bit_length(), 15);
+    assert_eq!(Big32x40::from_u64(0xffffff).bit_length(), 24);
+    assert_eq!(Big32x40::from_u64(0xffffffffffffffff).bit_length(), 64);
+}
+
 #[test]
 fn test_ord() {
     assert!(Big::from_u64(0) < Big::from_u64(0xffffff));
index 6dec0e674975c0b1962c04d9844068349bdbf4db..46183d1ad00665fdf6da15728ec3cb3c13591b9f 100644 (file)
@@ -4,7 +4,7 @@ version = "0.0.0"
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust.git"
 description = "Implementation of Rust panics via process aborts"
-edition = "2018"
+edition = "2021"
 
 [lib]
 test = false
index 67405463aa66ab06528edd45953f5ffb50083392..d720cc7bcbdf1c3c0067b3232dc4fcd7c1d6e51a 100644 (file)
@@ -4,7 +4,7 @@ version = "0.0.0"
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust.git"
 description = "Implementation of Rust panics via stack unwinding"
-edition = "2018"
+edition = "2021"
 
 [lib]
 test = false
index faf460e32bd871c0c66de779d4d6ea66c6214a6b..db5e2e4e245ea59f84c5828116a313d543f29c4c 100644 (file)
@@ -1,7 +1,7 @@
 [package]
 name = "proc_macro"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 std = { path = "../std" }
index 83a2ac6f0d4f14e77b1de2aae54f059addf166a4..9e9750eb8de4031dddb7facb7fb9ec35efa75b19 100644 (file)
@@ -310,8 +310,7 @@ fn enter<R>(self, f: impl FnOnce() -> R) -> R {
         // NB. the server can't do this because it may use a different libstd.
         static HIDE_PANICS_DURING_EXPANSION: Once = Once::new();
         HIDE_PANICS_DURING_EXPANSION.call_once(|| {
-            let prev = panic::take_hook();
-            panic::set_hook(Box::new(move |info| {
+            panic::update_hook(move |prev, info| {
                 let show = BridgeState::with(|state| match state {
                     BridgeState::NotConnected => true,
                     BridgeState::Connected(_) | BridgeState::InUse => force_show_panics,
@@ -319,7 +318,7 @@ fn enter<R>(self, f: impl FnOnce() -> R) -> R {
                 if show {
                     prev(info)
                 }
-            }));
+            });
         });
 
         BRIDGE_STATE.with(|state| state.set(BridgeState::Connected(self), f))
index 69af598f91e1cfda3ec49ede77e45fc701517e5a..c5afca6d56a2d29a33255a1330dc74b579541284 100644 (file)
@@ -30,6 +30,7 @@
 #![feature(restricted_std)]
 #![feature(rustc_attrs)]
 #![feature(min_specialization)]
+#![feature(panic_update_hook)]
 #![recursion_limit = "256"]
 
 #[unstable(feature = "proc_macro_internals", issue = "27812")]
index 0f7f0067652f6ed230dfcfe563a8654ff5e424da..3371dfa124253ee29c4971be8544a5030fc95ba4 100644 (file)
@@ -1,7 +1,7 @@
 [package]
 name = "profiler_builtins"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 test = false
index 1ea421834a7d572e6d4a578243ab22f8ab6e8a98..049ca3e46b57d784c045f5e1ad7d19afa57c779b 100644 (file)
@@ -5,7 +5,7 @@ license = 'MIT OR Apache-2.0'
 description = """
 Hack for the compiler's own build system
 """
-edition = "2018"
+edition = "2021"
 
 [lib]
 path = "lib.rs"
index 01e8b92e14941492e4943bb4d3eee2c69fbd2d8c..ff5cfcbd641443fc1dd91cec70c6308c476eaaae 100644 (file)
@@ -5,7 +5,7 @@ license = 'MIT OR Apache-2.0'
 description = """
 Hack for the compiler's own build system
 """
-edition = "2018"
+edition = "2021"
 
 [lib]
 path = "lib.rs"
index 811bc78d21016ec6ae756f8f2582228d3a470166..3a1dc2a02b557abf7b16cf2400084542432e4c0a 100644 (file)
@@ -5,7 +5,7 @@ license = 'MIT OR Apache-2.0'
 description = """
 Hack for the compiler's own build system
 """
-edition = "2018"
+edition = "2021"
 
 [lib]
 path = "lib.rs"
index 5ef23871e8b5f37f9c4d369e07fe30b161cc5ee2..c64377dfbc8acd9a8383e4ea9f84c31c01c39c63 100644 (file)
@@ -349,6 +349,33 @@ pub fn keys(&self) -> Keys<'_, K, V> {
         Keys { inner: self.iter() }
     }
 
+    /// Creates a consuming iterator visiting all the keys in arbitrary order.
+    /// The map cannot be used after calling this.
+    /// The iterator element type is `K`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
+    ///
+    /// let mut vec: Vec<&str> = map.into_keys().collect();
+    /// // The `IntoKeys` iterator produces keys in arbitrary order, so the
+    /// // keys must be sorted to test them against a sorted array.
+    /// vec.sort_unstable();
+    /// assert_eq!(vec, ["a", "b", "c"]);
+    /// ```
+    #[inline]
+    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
+    pub fn into_keys(self) -> IntoKeys<K, V> {
+        IntoKeys { inner: self.into_iter() }
+    }
+
     /// An iterator visiting all values in arbitrary order.
     /// The iterator element type is `&'a V`.
     ///
@@ -399,6 +426,33 @@ pub fn values_mut(&mut self) -> ValuesMut<'_, K, V> {
         ValuesMut { inner: self.iter_mut() }
     }
 
+    /// Creates a consuming iterator visiting all the values in arbitrary order.
+    /// The map cannot be used after calling this.
+    /// The iterator element type is `V`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let map = HashMap::from([
+    ///     ("a", 1),
+    ///     ("b", 2),
+    ///     ("c", 3),
+    /// ]);
+    ///
+    /// let mut vec: Vec<i32> = map.into_values().collect();
+    /// // The `IntoValues` iterator produces values in arbitrary order, so
+    /// // the values must be sorted to test them against a sorted array.
+    /// vec.sort_unstable();
+    /// assert_eq!(vec, [1, 2, 3]);
+    /// ```
+    #[inline]
+    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
+    pub fn into_values(self) -> IntoValues<K, V> {
+        IntoValues { inner: self.into_iter() }
+    }
+
     /// An iterator visiting all key-value pairs in arbitrary order.
     /// The iterator element type is `(&'a K, &'a V)`.
     ///
@@ -555,6 +609,29 @@ pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
         DrainFilter { base: self.base.drain_filter(pred) }
     }
 
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
+    /// The elements are visited in unsorted (and unspecified) order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashMap;
+    ///
+    /// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x*10)).collect();
+    /// map.retain(|&k, _| k % 2 == 0);
+    /// assert_eq!(map.len(), 4);
+    /// ```
+    #[inline]
+    #[stable(feature = "retain_hash_collection", since = "1.18.0")]
+    pub fn retain<F>(&mut self, f: F)
+    where
+        F: FnMut(&K, &mut V) -> bool,
+    {
+        self.base.retain(f)
+    }
+
     /// Clears the map, removing all key-value pairs. Keeps the allocated memory
     /// for reuse.
     ///
@@ -937,83 +1014,6 @@ pub fn remove_entry<Q: ?Sized>(&mut self, k: &Q) -> Option<(K, V)>
     {
         self.base.remove_entry(k)
     }
-
-    /// Retains only the elements specified by the predicate.
-    ///
-    /// In other words, remove all pairs `(k, v)` such that `f(&k, &mut v)` returns `false`.
-    /// The elements are visited in unsorted (and unspecified) order.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::HashMap;
-    ///
-    /// let mut map: HashMap<i32, i32> = (0..8).map(|x| (x, x*10)).collect();
-    /// map.retain(|&k, _| k % 2 == 0);
-    /// assert_eq!(map.len(), 4);
-    /// ```
-    #[inline]
-    #[stable(feature = "retain_hash_collection", since = "1.18.0")]
-    pub fn retain<F>(&mut self, f: F)
-    where
-        F: FnMut(&K, &mut V) -> bool,
-    {
-        self.base.retain(f)
-    }
-
-    /// Creates a consuming iterator visiting all the keys in arbitrary order.
-    /// The map cannot be used after calling this.
-    /// The iterator element type is `K`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::HashMap;
-    ///
-    /// let map = HashMap::from([
-    ///     ("a", 1),
-    ///     ("b", 2),
-    ///     ("c", 3),
-    /// ]);
-    ///
-    /// let mut vec: Vec<&str> = map.into_keys().collect();
-    /// // The `IntoKeys` iterator produces keys in arbitrary order, so the
-    /// // keys must be sorted to test them against a sorted array.
-    /// vec.sort_unstable();
-    /// assert_eq!(vec, ["a", "b", "c"]);
-    /// ```
-    #[inline]
-    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
-    pub fn into_keys(self) -> IntoKeys<K, V> {
-        IntoKeys { inner: self.into_iter() }
-    }
-
-    /// Creates a consuming iterator visiting all the values in arbitrary order.
-    /// The map cannot be used after calling this.
-    /// The iterator element type is `V`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::HashMap;
-    ///
-    /// let map = HashMap::from([
-    ///     ("a", 1),
-    ///     ("b", 2),
-    ///     ("c", 3),
-    /// ]);
-    ///
-    /// let mut vec: Vec<i32> = map.into_values().collect();
-    /// // The `IntoValues` iterator produces values in arbitrary order, so
-    /// // the values must be sorted to test them against a sorted array.
-    /// vec.sort_unstable();
-    /// assert_eq!(vec, [1, 2, 3]);
-    /// ```
-    #[inline]
-    #[stable(feature = "map_into_keys_values", since = "1.54.0")]
-    pub fn into_values(self) -> IntoValues<K, V> {
-        IntoValues { inner: self.into_iter() }
-    }
 }
 
 impl<K, V, S> HashMap<K, V, S>
index d9b20aee2d27f1e1b6fd7951976766db317ac6bc..eac884bfe0f3788268202c22a7cd4e51fb34bedd 100644 (file)
@@ -420,8 +420,8 @@ fn test_iterate() {
 
 #[test]
 fn test_keys() {
-    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
-    let map: HashMap<_, _> = vec.into_iter().collect();
+    let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+    let map: HashMap<_, _> = pairs.into_iter().collect();
     let keys: Vec<_> = map.keys().cloned().collect();
     assert_eq!(keys.len(), 3);
     assert!(keys.contains(&1));
@@ -431,8 +431,8 @@ fn test_keys() {
 
 #[test]
 fn test_values() {
-    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
-    let map: HashMap<_, _> = vec.into_iter().collect();
+    let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+    let map: HashMap<_, _> = pairs.into_iter().collect();
     let values: Vec<_> = map.values().cloned().collect();
     assert_eq!(values.len(), 3);
     assert!(values.contains(&'a'));
@@ -442,8 +442,8 @@ fn test_values() {
 
 #[test]
 fn test_values_mut() {
-    let vec = vec![(1, 1), (2, 2), (3, 3)];
-    let mut map: HashMap<_, _> = vec.into_iter().collect();
+    let pairs = [(1, 1), (2, 2), (3, 3)];
+    let mut map: HashMap<_, _> = pairs.into_iter().collect();
     for value in map.values_mut() {
         *value = (*value) * 2
     }
@@ -456,8 +456,8 @@ fn test_values_mut() {
 
 #[test]
 fn test_into_keys() {
-    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
-    let map: HashMap<_, _> = vec.into_iter().collect();
+    let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+    let map: HashMap<_, _> = pairs.into_iter().collect();
     let keys: Vec<_> = map.into_keys().collect();
 
     assert_eq!(keys.len(), 3);
@@ -468,8 +468,8 @@ fn test_into_keys() {
 
 #[test]
 fn test_into_values() {
-    let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
-    let map: HashMap<_, _> = vec.into_iter().collect();
+    let pairs = [(1, 'a'), (2, 'b'), (3, 'c')];
+    let map: HashMap<_, _> = pairs.into_iter().collect();
     let values: Vec<_> = map.into_values().collect();
 
     assert_eq!(values.len(), 3);
index a1e28c0b0a695acba54719d5dee8187918124421..0d087772bf931053a54660844e15e6f7997e189a 100644 (file)
@@ -290,6 +290,28 @@ pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, T, F>
         DrainFilter { base: self.base.drain_filter(pred) }
     }
 
+    /// Retains only the elements specified by the predicate.
+    ///
+    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
+    /// The elements are visited in unsorted (and unspecified) order.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::HashSet;
+    ///
+    /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]);
+    /// set.retain(|&k| k % 2 == 0);
+    /// assert_eq!(set.len(), 3);
+    /// ```
+    #[stable(feature = "retain_hash_collection", since = "1.18.0")]
+    pub fn retain<F>(&mut self, f: F)
+    where
+        F: FnMut(&T) -> bool,
+    {
+        self.base.retain(f)
+    }
+
     /// Clears the set, removing all values.
     ///
     /// # Examples
@@ -906,28 +928,6 @@ pub fn take<Q: ?Sized>(&mut self, value: &Q) -> Option<T>
     {
         self.base.take(value)
     }
-
-    /// Retains only the elements specified by the predicate.
-    ///
-    /// In other words, remove all elements `e` such that `f(&e)` returns `false`.
-    /// The elements are visited in unsorted (and unspecified) order.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// use std::collections::HashSet;
-    ///
-    /// let mut set = HashSet::from([1, 2, 3, 4, 5, 6]);
-    /// set.retain(|&k| k % 2 == 0);
-    /// assert_eq!(set.len(), 3);
-    /// ```
-    #[stable(feature = "retain_hash_collection", since = "1.18.0")]
-    pub fn retain<F>(&mut self, f: F)
-    where
-        F: FnMut(&T) -> bool,
-    {
-        self.base.retain(f)
-    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
index 8b004525b469796203b3e6b6fb8a5e39eb7eaf89..b5e81deb4808007b4082c80e241789cf19da2102 100644 (file)
 //! ```
 //! use std::collections::VecDeque;
 //!
-//! let vec = vec![1, 2, 3, 4];
+//! let vec = [1, 2, 3, 4];
 //! let buf: VecDeque<_> = vec.into_iter().collect();
 //! ```
 //!
index 6ae0bc47a9462ef3bf9812b9b7908b71c5ac850d..643108b88bf79da58131bacff61a3a67e616285b 100644 (file)
@@ -25,7 +25,7 @@
 use crate::borrow::Cow;
 use crate::cell;
 use crate::char;
-use crate::fmt::{self, Debug, Display};
+use crate::fmt::{self, Debug, Display, Write};
 use crate::mem::transmute;
 use crate::num;
 use crate::str;
@@ -63,7 +63,7 @@ pub trait Error: Debug + Display {
     ///
     /// #[derive(Debug)]
     /// struct SuperError {
-    ///     side: SuperErrorSideKick,
+    ///     source: SuperErrorSideKick,
     /// }
     ///
     /// impl fmt::Display for SuperError {
@@ -74,7 +74,7 @@ pub trait Error: Debug + Display {
     ///
     /// impl Error for SuperError {
     ///     fn source(&self) -> Option<&(dyn Error + 'static)> {
-    ///         Some(&self.side)
+    ///         Some(&self.source)
     ///     }
     /// }
     ///
@@ -90,7 +90,7 @@ pub trait Error: Debug + Display {
     /// impl Error for SuperErrorSideKick {}
     ///
     /// fn get_super_error() -> Result<(), SuperError> {
-    ///     Err(SuperError { side: SuperErrorSideKick })
+    ///     Err(SuperError { source: SuperErrorSideKick })
     /// }
     ///
     /// fn main() {
@@ -478,6 +478,9 @@ fn description(&self) -> &str {
     }
 }
 
+#[stable(feature = "u8_from_char", since = "1.59.0")]
+impl Error for char::TryFromCharError {}
+
 #[unstable(feature = "map_try_insert", issue = "82766")]
 impl<'a, K: Debug + Ord, V: Debug> Error
     for crate::collections::btree_map::OccupiedError<'a, K, V>
@@ -603,21 +606,21 @@ impl Error for time::FromSecsError {}
 
 // Copied from `any.rs`.
 impl dyn Error + 'static {
-    /// Returns `true` if the boxed type is the same as `T`
+    /// Returns `true` if the inner type is the same as `T`.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
     pub fn is<T: Error + 'static>(&self) -> bool {
         // Get `TypeId` of the type this function is instantiated with.
         let t = TypeId::of::<T>();
 
-        // Get `TypeId` of the type in the trait object.
-        let boxed = self.type_id(private::Internal);
+        // Get `TypeId` of the type in the trait object (`self`).
+        let concrete = self.type_id(private::Internal);
 
         // Compare both `TypeId`s on equality.
-        t == boxed
+        t == concrete
     }
 
-    /// Returns some reference to the boxed value if it is of type `T`, or
+    /// Returns some reference to the inner value if it is of type `T`, or
     /// `None` if it isn't.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
@@ -629,7 +632,7 @@ pub fn downcast_ref<T: Error + 'static>(&self) -> Option<&T> {
         }
     }
 
-    /// Returns some mutable reference to the boxed value if it is of type `T`, or
+    /// Returns some mutable reference to the inner value if it is of type `T`, or
     /// `None` if it isn't.
     #[stable(feature = "error_downcast", since = "1.3.0")]
     #[inline]
@@ -807,3 +810,642 @@ pub fn downcast<T: Error + 'static>(self: Box<Self>) -> Result<Box<T>, Box<Self>
         })
     }
 }
+
+/// An error reporter that print's an error and its sources.
+///
+/// Report also exposes configuration options for formatting the error chain, either entirely on a
+/// single line, or in multi-line format with each cause in the error chain on a new line.
+///
+/// `Report` only requires that the wrapped error implements `Error`. It doesn't require that the
+/// wrapped error be `Send`, `Sync`, or `'static`.
+///
+/// # Examples
+///
+/// ```rust
+/// #![feature(error_reporter)]
+/// use std::error::{Error, Report};
+/// use std::fmt;
+///
+/// #[derive(Debug)]
+/// struct SuperError {
+///     source: SuperErrorSideKick,
+/// }
+///
+/// impl fmt::Display for SuperError {
+///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+///         write!(f, "SuperError is here!")
+///     }
+/// }
+///
+/// impl Error for SuperError {
+///     fn source(&self) -> Option<&(dyn Error + 'static)> {
+///         Some(&self.source)
+///     }
+/// }
+///
+/// #[derive(Debug)]
+/// struct SuperErrorSideKick;
+///
+/// impl fmt::Display for SuperErrorSideKick {
+///     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+///         write!(f, "SuperErrorSideKick is here!")
+///     }
+/// }
+///
+/// impl Error for SuperErrorSideKick {}
+///
+/// fn get_super_error() -> Result<(), SuperError> {
+///     Err(SuperError { source: SuperErrorSideKick })
+/// }
+///
+/// fn main() {
+///     match get_super_error() {
+///         Err(e) => println!("Error: {}", Report::new(e)),
+///         _ => println!("No error"),
+///     }
+/// }
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// Error: SuperError is here!: SuperErrorSideKick is here!
+/// ```
+///
+/// ## Output consistency
+///
+/// Report prints the same output via `Display` and `Debug`, so it works well with
+/// [`Result::unwrap`]/[`Result::expect`] which print their `Err` variant via `Debug`:
+///
+/// ```should_panic
+/// #![feature(error_reporter)]
+/// use std::error::Report;
+/// # use std::error::Error;
+/// # use std::fmt;
+/// # #[derive(Debug)]
+/// # struct SuperError {
+/// #     source: SuperErrorSideKick,
+/// # }
+/// # impl fmt::Display for SuperError {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperError is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperError {
+/// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+/// #         Some(&self.source)
+/// #     }
+/// # }
+/// # #[derive(Debug)]
+/// # struct SuperErrorSideKick;
+/// # impl fmt::Display for SuperErrorSideKick {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperErrorSideKick is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperErrorSideKick {}
+/// # fn get_super_error() -> Result<(), SuperError> {
+/// #     Err(SuperError { source: SuperErrorSideKick })
+/// # }
+///
+/// get_super_error().map_err(Report::new).unwrap();
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: SuperError is here!: SuperErrorSideKick is here!', src/error.rs:34:40
+/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+/// ```
+///
+/// ## Return from `main`
+///
+/// `Report` also implements `From` for all types that implement [`Error`], this when combined with
+/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned
+/// from `main`.
+///
+/// ```should_panic
+/// #![feature(error_reporter)]
+/// use std::error::Report;
+/// # use std::error::Error;
+/// # use std::fmt;
+/// # #[derive(Debug)]
+/// # struct SuperError {
+/// #     source: SuperErrorSideKick,
+/// # }
+/// # impl fmt::Display for SuperError {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperError is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperError {
+/// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+/// #         Some(&self.source)
+/// #     }
+/// # }
+/// # #[derive(Debug)]
+/// # struct SuperErrorSideKick;
+/// # impl fmt::Display for SuperErrorSideKick {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperErrorSideKick is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperErrorSideKick {}
+/// # fn get_super_error() -> Result<(), SuperError> {
+/// #     Err(SuperError { source: SuperErrorSideKick })
+/// # }
+///
+/// fn main() -> Result<(), Report> {
+///     get_super_error()?;
+///     Ok(())
+/// }
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// Error: SuperError is here!: SuperErrorSideKick is here!
+/// ```
+///
+/// **Note**: `Report`s constructed via `?` and `From` will be configured to use the single line
+/// output format, if you want to make sure your `Report`s are pretty printed and include backtrace
+/// you will need to manually convert and enable those flags.
+///
+/// ```should_panic
+/// #![feature(error_reporter)]
+/// use std::error::Report;
+/// # use std::error::Error;
+/// # use std::fmt;
+/// # #[derive(Debug)]
+/// # struct SuperError {
+/// #     source: SuperErrorSideKick,
+/// # }
+/// # impl fmt::Display for SuperError {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperError is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperError {
+/// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+/// #         Some(&self.source)
+/// #     }
+/// # }
+/// # #[derive(Debug)]
+/// # struct SuperErrorSideKick;
+/// # impl fmt::Display for SuperErrorSideKick {
+/// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+/// #         write!(f, "SuperErrorSideKick is here!")
+/// #     }
+/// # }
+/// # impl Error for SuperErrorSideKick {}
+/// # fn get_super_error() -> Result<(), SuperError> {
+/// #     Err(SuperError { source: SuperErrorSideKick })
+/// # }
+///
+/// fn main() -> Result<(), Report> {
+///     get_super_error()
+///         .map_err(Report::from)
+///         .map_err(|r| r.pretty(true).show_backtrace(true))?;
+///     Ok(())
+/// }
+/// ```
+///
+/// This example produces the following output:
+///
+/// ```console
+/// Error: SuperError is here!
+///
+/// Caused by:
+///       SuperErrorSideKick is here!
+/// ```
+#[unstable(feature = "error_reporter", issue = "90172")]
+pub struct Report<E = Box<dyn Error>> {
+    /// The error being reported.
+    error: E,
+    /// Whether a backtrace should be included as part of the report.
+    show_backtrace: bool,
+    /// Whether the report should be pretty-printed.
+    pretty: bool,
+}
+
+impl<E> Report<E>
+where
+    Report<E>: From<E>,
+{
+    /// Create a new `Report` from an input error.
+    #[unstable(feature = "error_reporter", issue = "90172")]
+    pub fn new(error: E) -> Report<E> {
+        Self::from(error)
+    }
+}
+
+impl<E> Report<E> {
+    /// Enable pretty-printing the report across multiple lines.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// #![feature(error_reporter)]
+    /// use std::error::Report;
+    /// # use std::error::Error;
+    /// # use std::fmt;
+    /// # #[derive(Debug)]
+    /// # struct SuperError {
+    /// #     source: SuperErrorSideKick,
+    /// # }
+    /// # impl fmt::Display for SuperError {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperError is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperError {
+    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+    /// #         Some(&self.source)
+    /// #     }
+    /// # }
+    /// # #[derive(Debug)]
+    /// # struct SuperErrorSideKick;
+    /// # impl fmt::Display for SuperErrorSideKick {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperErrorSideKick is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperErrorSideKick {}
+    ///
+    /// let error = SuperError { source: SuperErrorSideKick };
+    /// let report = Report::new(error).pretty(true);
+    /// eprintln!("Error: {:?}", report);
+    /// ```
+    ///
+    /// This example produces the following output:
+    ///
+    /// ```console
+    /// Error: SuperError is here!
+    ///
+    /// Caused by:
+    ///       SuperErrorSideKick is here!
+    /// ```
+    ///
+    /// When there are multiple source errors the causes will be numbered in order of iteration
+    /// starting from the outermost error.
+    ///
+    /// ```rust
+    /// #![feature(error_reporter)]
+    /// use std::error::Report;
+    /// # use std::error::Error;
+    /// # use std::fmt;
+    /// # #[derive(Debug)]
+    /// # struct SuperError {
+    /// #     source: SuperErrorSideKick,
+    /// # }
+    /// # impl fmt::Display for SuperError {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperError is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperError {
+    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+    /// #         Some(&self.source)
+    /// #     }
+    /// # }
+    /// # #[derive(Debug)]
+    /// # struct SuperErrorSideKick {
+    /// #     source: SuperErrorSideKickSideKick,
+    /// # }
+    /// # impl fmt::Display for SuperErrorSideKick {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperErrorSideKick is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperErrorSideKick {
+    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+    /// #         Some(&self.source)
+    /// #     }
+    /// # }
+    /// # #[derive(Debug)]
+    /// # struct SuperErrorSideKickSideKick;
+    /// # impl fmt::Display for SuperErrorSideKickSideKick {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperErrorSideKickSideKick is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperErrorSideKickSideKick { }
+    ///
+    /// let source = SuperErrorSideKickSideKick;
+    /// let source = SuperErrorSideKick { source };
+    /// let error = SuperError { source };
+    /// let report = Report::new(error).pretty(true);
+    /// eprintln!("Error: {:?}", report);
+    /// ```
+    ///
+    /// This example produces the following output:
+    ///
+    /// ```console
+    /// Error: SuperError is here!
+    ///
+    /// Caused by:
+    ///    0: SuperErrorSideKick is here!
+    ///    1: SuperErrorSideKickSideKick is here!
+    /// ```
+    #[unstable(feature = "error_reporter", issue = "90172")]
+    pub fn pretty(mut self, pretty: bool) -> Self {
+        self.pretty = pretty;
+        self
+    }
+
+    /// Display backtrace if available when using pretty output format.
+    ///
+    /// # Examples
+    ///
+    /// **Note**: Report will search for the first `Backtrace` it can find starting from the
+    /// outermost error. In this example it will display the backtrace from the second error in the
+    /// chain, `SuperErrorSideKick`.
+    ///
+    /// ```rust
+    /// #![feature(error_reporter)]
+    /// #![feature(backtrace)]
+    /// # use std::error::Error;
+    /// # use std::fmt;
+    /// use std::error::Report;
+    /// use std::backtrace::Backtrace;
+    ///
+    /// # #[derive(Debug)]
+    /// # struct SuperError {
+    /// #     source: SuperErrorSideKick,
+    /// # }
+    /// # impl fmt::Display for SuperError {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperError is here!")
+    /// #     }
+    /// # }
+    /// # impl Error for SuperError {
+    /// #     fn source(&self) -> Option<&(dyn Error + 'static)> {
+    /// #         Some(&self.source)
+    /// #     }
+    /// # }
+    /// #[derive(Debug)]
+    /// struct SuperErrorSideKick {
+    ///     backtrace: Backtrace,
+    /// }
+    ///
+    /// impl SuperErrorSideKick {
+    ///     fn new() -> SuperErrorSideKick {
+    ///         SuperErrorSideKick { backtrace: Backtrace::force_capture() }
+    ///     }
+    /// }
+    ///
+    /// impl Error for SuperErrorSideKick {
+    ///     fn backtrace(&self) -> Option<&Backtrace> {
+    ///         Some(&self.backtrace)
+    ///     }
+    /// }
+    ///
+    /// // The rest of the example is unchanged ...
+    /// # impl fmt::Display for SuperErrorSideKick {
+    /// #     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    /// #         write!(f, "SuperErrorSideKick is here!")
+    /// #     }
+    /// # }
+    ///
+    /// let source = SuperErrorSideKick::new();
+    /// let error = SuperError { source };
+    /// let report = Report::new(error).pretty(true).show_backtrace(true);
+    /// eprintln!("Error: {:?}", report);
+    /// ```
+    ///
+    /// This example produces something similar to the following output:
+    ///
+    /// ```console
+    /// Error: SuperError is here!
+    ///
+    /// Caused by:
+    ///       SuperErrorSideKick is here!
+    ///
+    /// Stack backtrace:
+    ///    0: rust_out::main::_doctest_main_src_error_rs_1158_0::SuperErrorSideKick::new
+    ///    1: rust_out::main::_doctest_main_src_error_rs_1158_0
+    ///    2: rust_out::main
+    ///    3: core::ops::function::FnOnce::call_once
+    ///    4: std::sys_common::backtrace::__rust_begin_short_backtrace
+    ///    5: std::rt::lang_start::{{closure}}
+    ///    6: std::panicking::try
+    ///    7: std::rt::lang_start_internal
+    ///    8: std::rt::lang_start
+    ///    9: main
+    ///   10: __libc_start_main
+    ///   11: _start
+    /// ```
+    #[unstable(feature = "error_reporter", issue = "90172")]
+    pub fn show_backtrace(mut self, show_backtrace: bool) -> Self {
+        self.show_backtrace = show_backtrace;
+        self
+    }
+}
+
+impl<E> Report<E>
+where
+    E: Error,
+{
+    fn backtrace(&self) -> Option<&Backtrace> {
+        // have to grab the backtrace on the first error directly since that error may not be
+        // 'static
+        let backtrace = self.error.backtrace();
+        let backtrace = backtrace.or_else(|| {
+            self.error
+                .source()
+                .map(|source| source.chain().find_map(|source| source.backtrace()))
+                .flatten()
+        });
+        backtrace
+    }
+
+    /// Format the report as a single line.
+    #[unstable(feature = "error_reporter", issue = "90172")]
+    fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.error)?;
+
+        let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
+
+        for cause in sources {
+            write!(f, ": {}", cause)?;
+        }
+
+        Ok(())
+    }
+
+    /// Format the report as multiple lines, with each error cause on its own line.
+    #[unstable(feature = "error_reporter", issue = "90172")]
+    fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let error = &self.error;
+
+        write!(f, "{}", error)?;
+
+        if let Some(cause) = error.source() {
+            write!(f, "\n\nCaused by:")?;
+
+            let multiple = cause.source().is_some();
+
+            for (ind, error) in cause.chain().enumerate() {
+                writeln!(f)?;
+                let mut indented = Indented { inner: f };
+                if multiple {
+                    write!(indented, "{: >4}: {}", ind, error)?;
+                } else {
+                    write!(indented, "      {}", error)?;
+                }
+            }
+        }
+
+        if self.show_backtrace {
+            let backtrace = self.backtrace();
+
+            if let Some(backtrace) = backtrace {
+                let backtrace = backtrace.to_string();
+
+                f.write_str("\n\nStack backtrace:\n")?;
+                f.write_str(backtrace.trim_end())?;
+            }
+        }
+
+        Ok(())
+    }
+}
+
+impl Report<Box<dyn Error>> {
+    fn backtrace(&self) -> Option<&Backtrace> {
+        // have to grab the backtrace on the first error directly since that error may not be
+        // 'static
+        let backtrace = self.error.backtrace();
+        let backtrace = backtrace.or_else(|| {
+            self.error
+                .source()
+                .map(|source| source.chain().find_map(|source| source.backtrace()))
+                .flatten()
+        });
+        backtrace
+    }
+
+    /// Format the report as a single line.
+    #[unstable(feature = "error_reporter", issue = "90172")]
+    fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.error)?;
+
+        let sources = self.error.source().into_iter().flat_map(<dyn Error>::chain);
+
+        for cause in sources {
+            write!(f, ": {}", cause)?;
+        }
+
+        Ok(())
+    }
+
+    /// Format the report as multiple lines, with each error cause on its own line.
+    #[unstable(feature = "error_reporter", issue = "90172")]
+    fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let error = &self.error;
+
+        write!(f, "{}", error)?;
+
+        if let Some(cause) = error.source() {
+            write!(f, "\n\nCaused by:")?;
+
+            let multiple = cause.source().is_some();
+
+            for (ind, error) in cause.chain().enumerate() {
+                writeln!(f)?;
+                let mut indented = Indented { inner: f };
+                if multiple {
+                    write!(indented, "{: >4}: {}", ind, error)?;
+                } else {
+                    write!(indented, "      {}", error)?;
+                }
+            }
+        }
+
+        if self.show_backtrace {
+            let backtrace = self.backtrace();
+
+            if let Some(backtrace) = backtrace {
+                let backtrace = backtrace.to_string();
+
+                f.write_str("\n\nStack backtrace:\n")?;
+                f.write_str(backtrace.trim_end())?;
+            }
+        }
+
+        Ok(())
+    }
+}
+
+#[unstable(feature = "error_reporter", issue = "90172")]
+impl<E> From<E> for Report<E>
+where
+    E: Error,
+{
+    fn from(error: E) -> Self {
+        Report { error, show_backtrace: false, pretty: false }
+    }
+}
+
+#[unstable(feature = "error_reporter", issue = "90172")]
+impl<'a, E> From<E> for Report<Box<dyn Error + 'a>>
+where
+    E: Error + 'a,
+{
+    fn from(error: E) -> Self {
+        let error = box error;
+        Report { error, show_backtrace: false, pretty: false }
+    }
+}
+
+#[unstable(feature = "error_reporter", issue = "90172")]
+impl<E> fmt::Display for Report<E>
+where
+    E: Error,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) }
+    }
+}
+
+#[unstable(feature = "error_reporter", issue = "90172")]
+impl fmt::Display for Report<Box<dyn Error>> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) }
+    }
+}
+
+// This type intentionally outputs the same format for `Display` and `Debug`for
+// situations where you unwrap a `Report` or return it from main.
+#[unstable(feature = "error_reporter", issue = "90172")]
+impl<E> fmt::Debug for Report<E>
+where
+    Report<E>: fmt::Display,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, f)
+    }
+}
+
+/// Wrapper type for indenting the inner source.
+struct Indented<'a, D> {
+    inner: &'a mut D,
+}
+
+impl<T> Write for Indented<'_, T>
+where
+    T: Write,
+{
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        for (i, line) in s.split('\n').enumerate() {
+            if i > 0 {
+                self.inner.write_char('\n')?;
+                self.inner.write_str("      ")?;
+            }
+
+            self.inner.write_str(line)?;
+        }
+
+        Ok(())
+    }
+}
index 66d6924f34d2b2dea3742bb02bdff131bf64872a..eae5f43ff3cfb060b424b6a59aa0d8e40e35b2ad 100644 (file)
@@ -35,3 +35,408 @@ fn downcasting() {
         Err(e) => assert_eq!(*e.downcast::<A>().unwrap(), A),
     }
 }
+
+use crate::backtrace::Backtrace;
+use crate::error::Report;
+
+#[derive(Debug)]
+struct SuperError {
+    source: SuperErrorSideKick,
+}
+
+impl fmt::Display for SuperError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "SuperError is here!")
+    }
+}
+
+impl Error for SuperError {
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
+        Some(&self.source)
+    }
+}
+
+#[derive(Debug)]
+struct SuperErrorSideKick;
+
+impl fmt::Display for SuperErrorSideKick {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "SuperErrorSideKick is here!")
+    }
+}
+
+impl Error for SuperErrorSideKick {}
+
+#[test]
+fn single_line_formatting() {
+    let error = SuperError { source: SuperErrorSideKick };
+    let report = Report::new(&error);
+    let actual = report.to_string();
+    let expected = String::from("SuperError is here!: SuperErrorSideKick is here!");
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn multi_line_formatting() {
+    let error = SuperError { source: SuperErrorSideKick };
+    let report = Report::new(&error).pretty(true);
+    let actual = report.to_string();
+    let expected = String::from(
+        "\
+SuperError is here!
+
+Caused by:
+      SuperErrorSideKick is here!",
+    );
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_with_no_sources_formats_single_line_correctly() {
+    let report = Report::new(SuperErrorSideKick);
+    let actual = report.to_string();
+    let expected = String::from("SuperErrorSideKick is here!");
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_with_no_sources_formats_multi_line_correctly() {
+    let report = Report::new(SuperErrorSideKick).pretty(true);
+    let actual = report.to_string();
+    let expected = String::from("SuperErrorSideKick is here!");
+
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_with_backtrace_outputs_correctly_with_one_source() {
+    let trace = Backtrace::force_capture();
+    let expected = format!(
+        "\
+The source of the error
+
+Caused by:
+      Error with backtrace
+
+Stack backtrace:
+{}",
+        trace
+    );
+    let error = GenericError::new("Error with backtrace");
+    let mut error = GenericError::new_with_source("The source of the error", error);
+    error.backtrace = Some(trace);
+    let report = Report::new(error).pretty(true).show_backtrace(true);
+
+    println!("Error: {}", report);
+    assert_eq!(expected.trim_end(), report.to_string());
+}
+
+#[test]
+fn error_with_backtrace_outputs_correctly_with_two_sources() {
+    let trace = Backtrace::force_capture();
+    let expected = format!(
+        "\
+Error with two sources
+
+Caused by:
+   0: The source of the error
+   1: Error with backtrace
+
+Stack backtrace:
+{}",
+        trace
+    );
+    let mut error = GenericError::new("Error with backtrace");
+    error.backtrace = Some(trace);
+    let error = GenericError::new_with_source("The source of the error", error);
+    let error = GenericError::new_with_source("Error with two sources", error);
+    let report = Report::new(error).pretty(true).show_backtrace(true);
+
+    println!("Error: {}", report);
+    assert_eq!(expected.trim_end(), report.to_string());
+}
+
+#[derive(Debug)]
+struct GenericError<D> {
+    message: D,
+    backtrace: Option<Backtrace>,
+    source: Option<Box<dyn Error + 'static>>,
+}
+
+impl<D> GenericError<D> {
+    fn new(message: D) -> GenericError<D> {
+        Self { message, backtrace: None, source: None }
+    }
+
+    fn new_with_source<E>(message: D, source: E) -> GenericError<D>
+    where
+        E: Error + 'static,
+    {
+        let source: Box<dyn Error + 'static> = Box::new(source);
+        let source = Some(source);
+        GenericError { message, backtrace: None, source }
+    }
+}
+
+impl<D> fmt::Display for GenericError<D>
+where
+    D: fmt::Display,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(&self.message, f)
+    }
+}
+
+impl<D> Error for GenericError<D>
+where
+    D: fmt::Debug + fmt::Display,
+{
+    fn source(&self) -> Option<&(dyn Error + 'static)> {
+        self.source.as_deref()
+    }
+
+    fn backtrace(&self) -> Option<&Backtrace> {
+        self.backtrace.as_ref()
+    }
+}
+
+#[test]
+fn error_formats_single_line_with_rude_display_impl() {
+    #[derive(Debug)]
+    struct MyMessage;
+
+    impl fmt::Display for MyMessage {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.write_str("line 1\nline 2")?;
+            f.write_str("\nline 3\nline 4\n")?;
+            f.write_str("line 5\nline 6")?;
+            Ok(())
+        }
+    }
+
+    let error = GenericError::new(MyMessage);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let report = Report::new(error);
+    let expected = "\
+line 1
+line 2
+line 3
+line 4
+line 5
+line 6: line 1
+line 2
+line 3
+line 4
+line 5
+line 6: line 1
+line 2
+line 3
+line 4
+line 5
+line 6: line 1
+line 2
+line 3
+line 4
+line 5
+line 6";
+
+    let actual = report.to_string();
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn error_formats_multi_line_with_rude_display_impl() {
+    #[derive(Debug)]
+    struct MyMessage;
+
+    impl fmt::Display for MyMessage {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.write_str("line 1\nline 2")?;
+            f.write_str("\nline 3\nline 4\n")?;
+            f.write_str("line 5\nline 6")?;
+            Ok(())
+        }
+    }
+
+    let error = GenericError::new(MyMessage);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let report = Report::new(error).pretty(true);
+    let expected = "line 1
+line 2
+line 3
+line 4
+line 5
+line 6
+
+Caused by:
+   0: line 1
+      line 2
+      line 3
+      line 4
+      line 5
+      line 6
+   1: line 1
+      line 2
+      line 3
+      line 4
+      line 5
+      line 6
+   2: line 1
+      line 2
+      line 3
+      line 4
+      line 5
+      line 6";
+
+    let actual = report.to_string();
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn errors_that_start_with_newline_formats_correctly() {
+    #[derive(Debug)]
+    struct MyMessage;
+
+    impl fmt::Display for MyMessage {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.write_str("\nThe message\n")
+        }
+    }
+
+    let error = GenericError::new(MyMessage);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let report = Report::new(error).pretty(true);
+    let expected = "
+The message
+
+
+Caused by:
+   0: \
+\n      The message
+      \
+\n   1: \
+\n      The message
+      ";
+
+    let actual = report.to_string();
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn errors_with_multiple_writes_on_same_line_dont_insert_erroneous_newlines() {
+    #[derive(Debug)]
+    struct MyMessage;
+
+    impl fmt::Display for MyMessage {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.write_str("The message")?;
+            f.write_str(" goes on")?;
+            f.write_str(" and on.")
+        }
+    }
+
+    let error = GenericError::new(MyMessage);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let report = Report::new(error).pretty(true);
+    let expected = "\
+The message goes on and on.
+
+Caused by:
+   0: The message goes on and on.
+   1: The message goes on and on.";
+
+    let actual = report.to_string();
+    println!("{}", actual);
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn errors_with_string_interpolation_formats_correctly() {
+    #[derive(Debug)]
+    struct MyMessage(usize);
+
+    impl fmt::Display for MyMessage {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            write!(f, "Got an error code: ({}). ", self.0)?;
+            write!(f, "What would you like to do in response?")
+        }
+    }
+
+    let error = GenericError::new(MyMessage(10));
+    let error = GenericError::new_with_source(MyMessage(20), error);
+    let report = Report::new(error).pretty(true);
+    let expected = "\
+Got an error code: (20). What would you like to do in response?
+
+Caused by:
+      Got an error code: (10). What would you like to do in response?";
+    let actual = report.to_string();
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn empty_lines_mid_message() {
+    #[derive(Debug)]
+    struct MyMessage;
+
+    impl fmt::Display for MyMessage {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.write_str("line 1\n\nline 2")
+        }
+    }
+
+    let error = GenericError::new(MyMessage);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let report = Report::new(error).pretty(true);
+    let expected = "\
+line 1
+
+line 2
+
+Caused by:
+   0: line 1
+      \
+\n      line 2
+   1: line 1
+      \
+\n      line 2";
+
+    let actual = report.to_string();
+    assert_eq!(expected, actual);
+}
+
+#[test]
+fn only_one_source() {
+    #[derive(Debug)]
+    struct MyMessage;
+
+    impl fmt::Display for MyMessage {
+        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+            f.write_str("line 1\nline 2")
+        }
+    }
+
+    let error = GenericError::new(MyMessage);
+    let error = GenericError::new_with_source(MyMessage, error);
+    let report = Report::new(error).pretty(true);
+    let expected = "\
+line 1
+line 2
+
+Caused by:
+      line 1
+      line 2";
+
+    let actual = report.to_string();
+    assert_eq!(expected, actual);
+}
index dae85027b6c2926d97de5179f08047107dae2494..a00b5e1232369fd284697cc14d9b3f6206519df1 100644 (file)
@@ -356,9 +356,10 @@ pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
     /// open or create a file with specific options if `open()` or `create()`
     /// are not appropriate.
     ///
-    /// It is equivalent to `OpenOptions::new()` but allows you to write more
-    /// readable code. Instead of `OpenOptions::new().read(true).open("foo.txt")`
-    /// you can write `File::options().read(true).open("foo.txt")`. This
+    /// It is equivalent to `OpenOptions::new()`, but allows you to write more
+    /// readable code. Instead of
+    /// `OpenOptions::new().append(true).open("example.log")`,
+    /// you can write `File::options().append(true).open("example.log")`. This
     /// also avoids the need to import `OpenOptions`.
     ///
     /// See the [`OpenOptions::new`] function for more details.
@@ -369,7 +370,7 @@ pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
     /// use std::fs::File;
     ///
     /// fn main() -> std::io::Result<()> {
-    ///     let mut f = File::options().read(true).open("foo.txt")?;
+    ///     let mut f = File::options().append(true).open("example.log")?;
     ///     Ok(())
     /// }
     /// ```
index 179bdf7fe553ace0281075792757ef91e7ddd7a8..100dab1e2493ca085418a7e46aab100df7ecea5e 100644 (file)
 use crate::fmt;
 use crate::io::Error;
 
-pub use bufreader::BufReader;
-pub use bufwriter::BufWriter;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::{bufreader::BufReader, bufwriter::BufWriter, linewriter::LineWriter};
+use linewritershim::LineWriterShim;
+
 #[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
 pub use bufwriter::WriterPanicked;
-pub use linewriter::LineWriter;
-use linewritershim::LineWriterShim;
 
 /// An error returned by [`BufWriter::into_inner`] which combines an error that
 /// happened while writing out the buffer, and the buffered writer object
index ecc9e91b6bdb2c106eb565a2788e6a9392b85576..824938ce38e68b430e5f45cd8ca53b62c2e35f27 100644 (file)
 use crate::sys;
 use crate::sys_common::memchr;
 
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::buffered::IntoInnerError;
 #[stable(feature = "bufwriter_into_parts", since = "1.56.0")]
 pub use self::buffered::WriterPanicked;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::buffered::{BufReader, BufWriter, LineWriter};
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::copy::copy;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::cursor::Cursor;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::error::{Error, ErrorKind, Result};
 #[unstable(feature = "internal_output_capture", issue = "none")]
 #[doc(no_inline, hidden)]
 pub use self::stdio::set_output_capture;
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::stdio::{stderr, stdin, stdout, Stderr, Stdin, Stdout};
-#[unstable(feature = "stdio_locked", issue = "86845")]
-pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked};
-#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::stdio::{StderrLock, StdinLock, StdoutLock};
 #[unstable(feature = "print_internals", issue = "none")]
 pub use self::stdio::{_eprint, _print};
+#[unstable(feature = "stdio_locked", issue = "86845")]
+pub use self::stdio::{stderr_locked, stdin_locked, stdout_locked};
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use self::util::{empty, repeat, sink, Empty, Repeat, Sink};
+pub use self::{
+    buffered::{BufReader, BufWriter, IntoInnerError, LineWriter},
+    copy::copy,
+    cursor::Cursor,
+    error::{Error, ErrorKind, Result},
+    stdio::{stderr, stdin, stdout, Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock},
+    util::{empty, repeat, sink, Empty, Repeat, Sink},
+};
 
 #[unstable(feature = "read_buf", issue = "78485")]
 pub use self::readbuf::ReadBuf;
@@ -1038,14 +1031,14 @@ fn take(self, limit: u64) -> Take<Self>
 ///
 /// # use std::io;
 /// fn main() -> io::Result<()> {
-///     let stdin = io::read_to_string(&mut io::stdin())?;
+///     let stdin = io::read_to_string(io::stdin())?;
 ///     println!("Stdin was:");
 ///     println!("{}", stdin);
 ///     Ok(())
 /// }
 /// ```
 #[unstable(feature = "io_read_to_string", issue = "80218")]
-pub fn read_to_string<R: Read>(reader: &mut R) -> Result<String> {
+pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
     let mut buf = String::new();
     reader.read_to_string(&mut buf)?;
     Ok(buf)
index a370485102e35a85cafaf6cd6b0f505016a2d072..35d230eee96275ac8fd277398c9bc294a7637849 100644 (file)
@@ -2172,7 +2172,7 @@ mod use_keyword {}
 ///     i.next().unwrap_or_else(I::Item::default)
 /// }
 ///
-/// assert_eq!(first_or_default(vec![1, 2, 3].into_iter()), 1);
+/// assert_eq!(first_or_default([1, 2, 3].into_iter()), 1);
 /// assert_eq!(first_or_default(Vec::<i32>::new().into_iter()), 0);
 /// ```
 ///
index 22e721d79bfed993ad69f085008b7c029583c200..1721e16f3a686300c72e181d0a2ad3fedb5df993 100644 (file)
@@ -35,8 +35,8 @@
 //! development you may want to press the `[-]` button near the top of the
 //! page to collapse it into a more skimmable view.
 //!
-//! While you are looking at that `[-]` button also notice the `[src]`
-//! button. Rust's API documentation comes with the source code and you are
+//! While you are looking at that `[-]` button also notice the `source`
+//! link. Rust's API documentation comes with the source code and you are
 //! encouraged to read it. The standard library source is generally high
 //! quality and a peek behind the curtains is often enlightening.
 //!
 #![feature(llvm_asm)]
 #![feature(log_syntax)]
 #![feature(map_try_insert)]
-#![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(maybe_uninit_write_slice)]
@@ -556,6 +555,7 @@ pub mod task {
 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,
 };
 
 // Re-export macros defined in libcore.
index 632d4683b41595e0fdb5c8216fb694d709ab96ca..7956c6a25e4959acf2e6f1802b01e8162ef7c0ca 100644 (file)
@@ -77,10 +77,10 @@ fn test_from_str_ipv4_in_ipv6() {
     let none: Option<Ipv4Addr> = "::127.0.0.1:".parse().ok();
     assert_eq!(None, none);
     // not enough groups
-    let none: Option<Ipv6Addr> = "1.2.3.4.5:127.0.0.1".parse().ok();
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:127.0.0.1".parse().ok();
     assert_eq!(None, none);
     // too many groups
-    let none: Option<Ipv6Addr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
+    let none: Option<Ipv6Addr> = "1:2:3:4:5:6:7:127.0.0.1".parse().ok();
     assert_eq!(None, none);
 }
 
index a0c77b648fe0511a8c56cabbf14e3a09707a9977..2669f4dbf3068b9603f58098dc7c07efedffccb1 100644 (file)
@@ -25,6 +25,8 @@
 pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::parser::AddrParseError;
+#[unstable(feature = "tcplistener_into_incoming", issue = "88339")]
+pub use self::tcp::IntoIncoming;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::tcp::{Incoming, TcpListener, TcpStream};
 #[stable(feature = "rust1", since = "1.0.0")]
index cd92dcabdf5209bd6e998a3c73d92d7aa475102f..d78049bce24c2dcd3baf624ad04466a64107a2f1 100644 (file)
@@ -239,6 +239,7 @@ pub struct stat {
     target_arch = "riscv32"
 ))]
 mod arch {
+    #[stable(feature = "raw_ext", since = "1.1.0")]
     pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t};
 }
 
index 54c9a9382f22fa3e37f5b36dc7d7e65a29f8dfaa..650f712bc6eef979f7170175eaa0b294d42c58b8 100644 (file)
@@ -28,9 +28,11 @@ pub trait OsStringExt: Sealed {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl OsStringExt for OsString {
+    #[inline]
     fn from_vec(vec: Vec<u8>) -> OsString {
         FromInner::from_inner(Buf { inner: vec })
     }
+    #[inline]
     fn into_vec(self) -> Vec<u8> {
         self.into_inner().inner
     }
index 6317e317471199a02794fe55fcb560ca8593f4f3..a4d2ba797d9c470362bb82916cdb52e333aac634 100644 (file)
@@ -2,4 +2,5 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+#[stable(feature = "rust1", since = "1.0.0")]
 pub use crate::os::fd::raw::*;
index c0605b2f4121c098244f40dfd1cb1282d9c17b20..02ecf2e3e822e091a041f4c6608e190323725b1e 100644 (file)
@@ -36,6 +36,9 @@
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub use crate::panicking::{set_hook, take_hook};
 
+#[unstable(feature = "panic_update_hook", issue = "92649")]
+pub use crate::panicking::update_hook;
+
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub use core::panic::{Location, PanicInfo};
 
index 87854fe4f297088d09e1081a9a37dd2bb0b78c9d..44f573297eed1ac2af92c473b2092a3c502cd08d 100644 (file)
@@ -76,6 +76,12 @@ enum Hook {
     Custom(*mut (dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send)),
 }
 
+impl Hook {
+    fn custom(f: impl Fn(&PanicInfo<'_>) + 'static + Sync + Send) -> Self {
+        Self::Custom(Box::into_raw(Box::new(f)))
+    }
+}
+
 static HOOK_LOCK: StaticRWLock = StaticRWLock::new();
 static mut HOOK: Hook = Hook::Default;
 
@@ -118,6 +124,11 @@ pub fn set_hook(hook: Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send>) {
         panic!("cannot modify the panic hook from a panicking thread");
     }
 
+    // SAFETY:
+    //
+    // - `HOOK` can only be modified while holding write access to `HOOK_LOCK`.
+    // - The argument of `Box::from_raw` is always a valid pointer that was created using
+    // `Box::into_raw`.
     unsafe {
         let guard = HOOK_LOCK.write();
         let old_hook = HOOK;
@@ -167,6 +178,11 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
         panic!("cannot modify the panic hook from a panicking thread");
     }
 
+    // SAFETY:
+    //
+    // - `HOOK` can only be modified while holding write access to `HOOK_LOCK`.
+    // - The argument of `Box::from_raw` is always a valid pointer that was created using
+    // `Box::into_raw`.
     unsafe {
         let guard = HOOK_LOCK.write();
         let hook = HOOK;
@@ -180,6 +196,69 @@ pub fn take_hook() -> Box<dyn Fn(&PanicInfo<'_>) + 'static + Sync + Send> {
     }
 }
 
+/// Atomic combination of [`take_hook`] and [`set_hook`]. Use this to replace the panic handler with
+/// a new panic handler that does something and then executes the old handler.
+///
+/// [`take_hook`]: ./fn.take_hook.html
+/// [`set_hook`]: ./fn.set_hook.html
+///
+/// # Panics
+///
+/// Panics if called from a panicking thread.
+///
+/// # Examples
+///
+/// The following will print the custom message, and then the normal output of panic.
+///
+/// ```should_panic
+/// #![feature(panic_update_hook)]
+/// use std::panic;
+///
+/// // Equivalent to
+/// // let prev = panic::take_hook();
+/// // panic::set_hook(move |info| {
+/// //     println!("...");
+/// //     prev(info);
+/// // );
+/// panic::update_hook(move |prev, info| {
+///     println!("Print custom message and execute panic handler as usual");
+///     prev(info);
+/// });
+///
+/// panic!("Custom and then normal");
+/// ```
+#[unstable(feature = "panic_update_hook", issue = "92649")]
+pub fn update_hook<F>(hook_fn: F)
+where
+    F: Fn(&(dyn Fn(&PanicInfo<'_>) + Send + Sync + 'static), &PanicInfo<'_>)
+        + Sync
+        + Send
+        + 'static,
+{
+    if thread::panicking() {
+        panic!("cannot modify the panic hook from a panicking thread");
+    }
+
+    // SAFETY:
+    //
+    // - `HOOK` can only be modified while holding write access to `HOOK_LOCK`.
+    // - The argument of `Box::from_raw` is always a valid pointer that was created using
+    // `Box::into_raw`.
+    unsafe {
+        let guard = HOOK_LOCK.write();
+        let old_hook = HOOK;
+        HOOK = Hook::Default;
+
+        let prev = match old_hook {
+            Hook::Default => Box::new(default_hook),
+            Hook::Custom(ptr) => Box::from_raw(ptr),
+        };
+
+        HOOK = Hook::custom(move |info| hook_fn(&prev, info));
+        drop(guard);
+    }
+}
+
 fn default_hook(info: &PanicInfo<'_>) {
     // If this is a double panic, make sure that we print a backtrace
     // for this panic. Otherwise only print it if logging is enabled.
index 743dd51333d18f9fc271dc90b14110b3ffa80770..b52bcdfca9e07152062fe44b3db98f7f6293c546 100644 (file)
 #[doc(no_inline)]
 pub use core::prelude::v1::concat_bytes;
 
-// FIXME: Attribute and internal derive macros are not documented because for them rustdoc generates
-// dead links which fail link checker testing.
+// Do not `doc(inline)` these `doc(hidden)` items.
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[allow(deprecated, deprecated_in_future)]
-#[doc(hidden)]
-pub use core::prelude::v1::{
-    bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
-};
+#[allow(deprecated)]
+pub use core::prelude::v1::{RustcDecodable, RustcEncodable};
 
+// Do not `doc(no_inline)` so that they become doc items on their own
+// (no public module for them to be re-exported from).
 #[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
-#[doc(hidden)]
-pub use core::prelude::v1::derive;
+pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
 
+// Do not `doc(no_inline)` either.
 #[unstable(
     feature = "cfg_accessible",
     issue = "64797",
     reason = "`cfg_accessible` is not fully implemented"
 )]
-#[doc(hidden)]
 pub use core::prelude::v1::cfg_accessible;
 
+// Do not `doc(no_inline)` either.
 #[unstable(
     feature = "cfg_eval",
     issue = "82679",
     reason = "`cfg_eval` is a recently implemented feature"
 )]
-#[doc(hidden)]
 pub use core::prelude::v1::cfg_eval;
 
 // The file so far is equivalent to src/libcore/prelude/v1.rs,
index 2cf678ef69b073677b32a32774ba686272a0e4e6..2e54321e127c0e3e882e048d3689c82774d08cbd 100644 (file)
@@ -429,12 +429,13 @@ pub struct TryIter<'a, T: 'a> {
 }
 
 /// An owning iterator over messages on a [`Receiver`],
-/// created by **Receiver::into_iter**.
+/// created by [`into_iter`].
 ///
 /// This iterator will block whenever [`next`]
 /// is called, waiting for a new message, and [`None`] will be
 /// returned if the corresponding channel has hung up.
 ///
+/// [`into_iter`]: Receiver::into_iter
 /// [`next`]: Iterator::next
 ///
 /// # Examples
index e84dfbce4a7540b97fc8e6b3d52fe0cc184bbe57..5ad570427978e5244b0d8d9f4af8c9ae3488d77b 100644 (file)
@@ -268,7 +268,7 @@ pub fn spawn(
         } else {
             None
         };
-        let program = resolve_exe(&self.program, child_paths)?;
+        let program = resolve_exe(&self.program, || env::var_os("PATH"), child_paths)?;
         let mut cmd_str =
             make_command_line(program.as_os_str(), &self.args, self.force_quotes_enabled)?;
         cmd_str.push(0); // add null terminator
@@ -362,7 +362,11 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 // Therefore this functions first assumes `.exe` was intended.
 // It falls back to the plain file name if a full path is given and the extension is omitted
 // or if only a file name is given and it already contains an extension.
-fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Result<PathBuf> {
+fn resolve_exe<'a>(
+    exe_path: &'a OsStr,
+    parent_paths: impl FnOnce() -> Option<OsString>,
+    child_paths: Option<&OsStr>,
+) -> 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(
@@ -406,7 +410,7 @@ fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Resu
         let has_extension = exe_path.bytes().contains(&b'.');
 
         // Search the directories given by `search_paths`.
-        let result = search_paths(child_paths, |mut path| {
+        let result = search_paths(parent_paths, child_paths, |mut path| {
             path.push(&exe_path);
             if !has_extension {
                 path.set_extension(EXE_EXTENSION);
@@ -423,15 +427,20 @@ fn resolve_exe<'a>(exe_path: &'a OsStr, child_paths: Option<&OsStr>) -> io::Resu
 
 // Calls `f` for every path that should be used to find an executable.
 // Returns once `f` returns the path to an executable or all paths have been searched.
-fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
+fn search_paths<Paths, Exists>(
+    parent_paths: Paths,
+    child_paths: Option<&OsStr>,
+    mut exists: Exists,
+) -> Option<PathBuf>
 where
-    F: FnMut(PathBuf) -> Option<PathBuf>,
+    Paths: FnOnce() -> Option<OsString>,
+    Exists: FnMut(PathBuf) -> Option<PathBuf>,
 {
     // 1. Child paths
     // This is for consistency with Rust's historic behaviour.
     if let Some(paths) = child_paths {
         for path in env::split_paths(paths).filter(|p| !p.as_os_str().is_empty()) {
-            if let Some(path) = f(path) {
+            if let Some(path) = exists(path) {
                 return Some(path);
             }
         }
@@ -440,7 +449,7 @@ fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
     // 2. Application path
     if let Ok(mut app_path) = env::current_exe() {
         app_path.pop();
-        if let Some(path) = f(app_path) {
+        if let Some(path) = exists(app_path) {
             return Some(path);
         }
     }
@@ -450,7 +459,7 @@ fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
     unsafe {
         if let Ok(Some(path)) = super::fill_utf16_buf(
             |buf, size| c::GetSystemDirectoryW(buf, size),
-            |buf| f(PathBuf::from(OsString::from_wide(buf))),
+            |buf| exists(PathBuf::from(OsString::from_wide(buf))),
         ) {
             return Some(path);
         }
@@ -458,7 +467,7 @@ fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
         {
             if let Ok(Some(path)) = super::fill_utf16_buf(
                 |buf, size| c::GetWindowsDirectoryW(buf, size),
-                |buf| f(PathBuf::from(OsString::from_wide(buf))),
+                |buf| exists(PathBuf::from(OsString::from_wide(buf))),
             ) {
                 return Some(path);
             }
@@ -466,9 +475,9 @@ fn search_paths<F>(child_paths: Option<&OsStr>, mut f: F) -> Option<PathBuf>
     }
 
     // 5. Parent paths
-    if let Some(parent_paths) = env::var_os("PATH") {
+    if let Some(parent_paths) = parent_paths() {
         for path in env::split_paths(&parent_paths).filter(|p| !p.as_os_str().is_empty()) {
-            if let Some(path) = f(path) {
+            if let Some(path) = exists(path) {
                 return Some(path);
             }
         }
index 6159a679c0e69a72e86ae2eb0e288ffa7b61e70c..f1221767af30e56d43581d5d48183b27d057e7d3 100644 (file)
@@ -136,51 +136,46 @@ fn windows_exe_resolver() {
     use super::resolve_exe;
     use crate::io;
 
+    let env_paths = || env::var_os("PATH");
+
     // Test a full path, with and without the `exe` extension.
     let mut current_exe = env::current_exe().unwrap();
-    assert!(resolve_exe(current_exe.as_ref(), None).is_ok());
+    assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
     current_exe.set_extension("");
-    assert!(resolve_exe(current_exe.as_ref(), None).is_ok());
+    assert!(resolve_exe(current_exe.as_ref(), env_paths, None).is_ok());
 
     // Test lone file names.
-    assert!(resolve_exe(OsStr::new("cmd"), None).is_ok());
-    assert!(resolve_exe(OsStr::new("cmd.exe"), None).is_ok());
-    assert!(resolve_exe(OsStr::new("cmd.EXE"), None).is_ok());
-    assert!(resolve_exe(OsStr::new("fc"), None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd"), env_paths, None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd.exe"), env_paths, None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd.EXE"), env_paths, None).is_ok());
+    assert!(resolve_exe(OsStr::new("fc"), env_paths, None).is_ok());
 
     // Invalid file names should return InvalidInput.
-    assert_eq!(resolve_exe(OsStr::new(""), None).unwrap_err().kind(), io::ErrorKind::InvalidInput);
     assert_eq!(
-        resolve_exe(OsStr::new("\0"), None).unwrap_err().kind(),
+        resolve_exe(OsStr::new(""), env_paths, None).unwrap_err().kind(),
+        io::ErrorKind::InvalidInput
+    );
+    assert_eq!(
+        resolve_exe(OsStr::new("\0"), env_paths, None).unwrap_err().kind(),
         io::ErrorKind::InvalidInput
     );
     // Trailing slash, therefore there's no file name component.
     assert_eq!(
-        resolve_exe(OsStr::new(r"C:\Path\to\"), None).unwrap_err().kind(),
+        resolve_exe(OsStr::new(r"C:\Path\to\"), env_paths, None).unwrap_err().kind(),
         io::ErrorKind::InvalidInput
     );
 
-    /* FIXME: fix and re-enable these tests before making changes to the resolver.
-
     /*
     Some of the following tests may need to be changed if you are deliberately
     changing the behaviour of `resolve_exe`.
     */
 
-    let paths = env::var_os("PATH").unwrap();
-    env::set_var("PATH", "");
-
-    assert_eq!(resolve_exe(OsStr::new("rustc"), None).unwrap_err().kind(), io::ErrorKind::NotFound);
-
-    let child_paths = Some(paths.as_os_str());
-    assert!(resolve_exe(OsStr::new("rustc"), child_paths).is_ok());
+    let empty_paths = || None;
 
     // The resolver looks in system directories even when `PATH` is empty.
-    assert!(resolve_exe(OsStr::new("cmd.exe"), None).is_ok());
+    assert!(resolve_exe(OsStr::new("cmd.exe"), empty_paths, None).is_ok());
 
     // The application's directory is also searched.
     let current_exe = env::current_exe().unwrap();
-    assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), None).is_ok());
-
-    */
+    assert!(resolve_exe(current_exe.file_name().unwrap().as_ref(), empty_paths, None).is_ok());
 }
index eb0925b3fda7d66a87f02c5df563fabd09d2269e..684b8e3155e84b1a6554424e5bf5afb45748373e 100644 (file)
@@ -15,7 +15,9 @@
 // the value over time (such as if a process calls `SetStdHandle` while it's running). See #40490.
 pub struct Stdin {
     surrogate: u16,
+    incomplete_utf8: IncompleteUtf8,
 }
+
 pub struct Stdout {
     incomplete_utf8: IncompleteUtf8,
 }
@@ -29,6 +31,25 @@ struct IncompleteUtf8 {
     len: u8,
 }
 
+impl IncompleteUtf8 {
+    // Implemented for use in Stdin::read.
+    fn read(&mut self, buf: &mut [u8]) -> usize {
+        // Write to buffer until the buffer is full or we run out of bytes.
+        let to_write = cmp::min(buf.len(), self.len as usize);
+        buf[..to_write].copy_from_slice(&self.bytes[..to_write]);
+
+        // Rotate the remaining bytes if not enough remaining space in buffer.
+        if usize::from(self.len) > buf.len() {
+            self.bytes.copy_within(to_write.., 0);
+            self.len -= to_write as u8;
+        } else {
+            self.len = 0;
+        }
+
+        to_write
+    }
+}
+
 // Apparently Windows doesn't handle large reads on stdin or writes to stdout/stderr well (see
 // #13304 for details).
 //
@@ -205,7 +226,7 @@ fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
 
 impl Stdin {
     pub const fn new() -> Stdin {
-        Stdin { surrogate: 0 }
+        Stdin { surrogate: 0, incomplete_utf8: IncompleteUtf8::new() }
     }
 }
 
@@ -221,24 +242,39 @@ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
             }
         }
 
-        if buf.len() == 0 {
-            return Ok(0);
-        } else if buf.len() < 4 {
-            return Err(io::Error::new_const(
-                io::ErrorKind::InvalidInput,
-                &"Windows stdin in console mode does not support a buffer too small to \
-                 guarantee holding one arbitrary UTF-8 character (4 bytes)",
-            ));
+        // If there are bytes in the incomplete utf-8, start with those.
+        // (No-op if there is nothing in the buffer.)
+        let mut bytes_copied = self.incomplete_utf8.read(buf);
+
+        if bytes_copied == buf.len() {
+            return Ok(bytes_copied);
+        } else if buf.len() - bytes_copied < 4 {
+            // Not enough space to get a UTF-8 byte. We will use the incomplete UTF8.
+            let mut utf16_buf = [0u16; 1];
+            // Read one u16 character.
+            let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, 1, &mut self.surrogate)?;
+            // Read bytes, using the (now-empty) self.incomplete_utf8 as extra space.
+            let read_bytes = utf16_to_utf8(&utf16_buf[..read], &mut self.incomplete_utf8.bytes)?;
+
+            // Read in the bytes from incomplete_utf8 until the buffer is full.
+            self.incomplete_utf8.len = read_bytes as u8;
+            // No-op if no bytes.
+            bytes_copied += self.incomplete_utf8.read(&mut buf[bytes_copied..]);
+            Ok(bytes_copied)
+        } else {
+            let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2];
+            // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So
+            // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
+            // lost.
+            let amount = cmp::min(buf.len() / 3, utf16_buf.len());
+            let read =
+                read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?;
+
+            match utf16_to_utf8(&utf16_buf[..read], buf) {
+                Ok(value) => return Ok(bytes_copied + value),
+                Err(e) => return Err(e),
+            }
         }
-
-        let mut utf16_buf = [0u16; MAX_BUFFER_SIZE / 2];
-        // In the worst case, a UTF-8 string can take 3 bytes for every `u16` of a UTF-16. So
-        // we can read at most a third of `buf.len()` chars and uphold the guarantee no data gets
-        // lost.
-        let amount = cmp::min(buf.len() / 3, utf16_buf.len());
-        let read = read_u16s_fixup_surrogates(handle, &mut utf16_buf, amount, &mut self.surrogate)?;
-
-        utf16_to_utf8(&utf16_buf[..read], buf)
     }
 }
 
index bcf2ec06022d9a0d7d4f8f170f7ef0b12fee83c0..546f8a15b706e1e05972916fe0f5224cdca1995a 100644 (file)
@@ -498,12 +498,12 @@ pub unsafe fn spawn_unchecked<'a, F, T>(self, f: F) -> io::Result<JoinHandle<T>>
             // exist after the thread has terminated, which is signaled by `Thread::join`
             // returning.
             native: unsafe {
-                Some(imp::Thread::new(
+                imp::Thread::new(
                     stack_size,
                     mem::transmute::<Box<dyn FnOnce() + 'a>, Box<dyn FnOnce() + 'static>>(
                         Box::new(main),
                     ),
-                )?)
+                )?
             },
             thread: my_thread,
             packet: Packet(my_packet),
@@ -972,10 +972,13 @@ pub fn park_timeout(dur: Duration) {
 
 /// A unique identifier for a running thread.
 ///
-/// A `ThreadId` is an opaque object that has a unique value for each thread
-/// that creates one. `ThreadId`s are not guaranteed to correspond to a thread's
-/// system-designated identifier. A `ThreadId` can be retrieved from the [`id`]
-/// method on a [`Thread`].
+/// A `ThreadId` is an opaque object that uniquely identifies each thread
+/// created during the lifetime of a process. `ThreadId`s are guaranteed not to
+/// be reused, even when a thread terminates. `ThreadId`s are under the control
+/// of Rust's standard library and there may not be any relationship between
+/// `ThreadId` and the underlying platform's notion of a thread identifier --
+/// the two concepts cannot, therefore, be used interchangeably. A `ThreadId`
+/// can be retrieved from the [`id`] method on a [`Thread`].
 ///
 /// # Examples
 ///
@@ -1258,15 +1261,15 @@ unsafe impl<T: Sync> Sync for Packet<T> {}
 
 /// Inner representation for JoinHandle
 struct JoinInner<T> {
-    native: Option<imp::Thread>,
+    native: imp::Thread,
     thread: Thread,
     packet: Packet<T>,
 }
 
 impl<T> JoinInner<T> {
-    fn join(&mut self) -> Result<T> {
-        self.native.take().unwrap().join();
-        unsafe { (*self.packet.0.get()).take().unwrap() }
+    fn join(mut self) -> Result<T> {
+        self.native.join();
+        Arc::get_mut(&mut self.packet.0).unwrap().get_mut().take().unwrap()
     }
 }
 
@@ -1397,7 +1400,7 @@ pub fn thread(&self) -> &Thread {
     /// join_handle.join().expect("Couldn't join on the associated thread");
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn join(mut self) -> Result<T> {
+    pub fn join(self) -> Result<T> {
         self.0.join()
     }
 
@@ -1413,13 +1416,13 @@ pub fn is_running(&self) -> bool {
 
 impl<T> AsInner<imp::Thread> for JoinHandle<T> {
     fn as_inner(&self) -> &imp::Thread {
-        self.0.native.as_ref().unwrap()
+        &self.0.native
     }
 }
 
 impl<T> IntoInner<imp::Thread> for JoinHandle<T> {
     fn into_inner(self) -> imp::Thread {
-        self.0.native.unwrap()
+        self.0.native
     }
 }
 
@@ -1501,7 +1504,6 @@ fn _assert_both<T: Send + Sync>() {}
 ///
 /// ```
 /// # #![allow(dead_code)]
-/// #![feature(available_parallelism)]
 /// use std::{io, thread};
 ///
 /// fn main() -> io::Result<()> {
@@ -1513,7 +1515,7 @@ fn _assert_both<T: Send + Sync>() {}
 #[doc(alias = "available_concurrency")] // Alias for a previous name we gave this API on unstable.
 #[doc(alias = "hardware_concurrency")] // Alias for C++ `std::thread::hardware_concurrency`.
 #[doc(alias = "num_cpus")] // Alias for a popular ecosystem crate which provides similar functionality.
-#[unstable(feature = "available_parallelism", issue = "74479")]
+#[stable(feature = "available_parallelism", since = "1.59.0")]
 pub fn available_parallelism() -> io::Result<NonZeroUsize> {
     imp::available_parallelism()
 }
index 86cc93c44537663d08e1591e330c3a696176f3e1..b6867e68df745c378c75204964f8371093de1c10 100644 (file)
@@ -54,7 +54,7 @@
 /// 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
+/// Note, however, that instants are **not** guaranteed to be **steady**. In other
 /// words, each tick of the underlying clock might not be the same length (e.g.
 /// some seconds may be longer than others). An instant may jump forwards or
 /// experience time dilation (slow down or speed up), but it will never go
index 0716b22e902207efabe46879cbf28d0189ab7924..2adc17a5442614dbe34626fdd9b32de7c07b8086 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 0716b22e902207efabe46879cbf28d0189ab7924
+Subproject commit 2adc17a5442614dbe34626fdd9b32de7c07b8086
index 04dab6b804acc2e5f2b35556995ad1a318407cf7..2da41484ca564afc15543d16a356502d3a3b49b2 100644 (file)
@@ -1,7 +1,7 @@
 [package]
 name = "test"
 version = "0.0.0"
-edition = "2018"
+edition = "2021"
 
 [lib]
 crate-type = ["dylib", "rlib"]
index 2516f3452b186a4ba8f54ede65c3fe4d608249a1..fad83094cdf8aa8c6a3956ed2f659cf220418bb0 100644 (file)
 // running tests while providing a base that other test frameworks may
 // build off of.
 
-// N.B., this is also specified in this crate's Cargo.toml, but librustc_ast contains logic specific to
-// this crate, which relies on this attribute (rather than the value of `--crate-name` passed by
-// cargo) to detect this crate.
-
-#![crate_name = "test"]
 #![unstable(feature = "test", issue = "50297")]
 #![doc(test(attr(deny(warnings))))]
-#![feature(libc)]
-#![feature(rustc_private)]
 #![feature(nll)]
-#![feature(available_parallelism)]
 #![feature(bench_black_box)]
 #![feature(internal_output_capture)]
-#![feature(panic_unwind)]
 #![feature(staged_api)]
 #![feature(termination_trait_lib)]
 #![feature(test)]
@@ -444,8 +435,8 @@ pub fn convert_benchmarks_to_tests(tests: Vec<TestDescAndFn>) -> Vec<TestDescAnd
         .into_iter()
         .map(|x| {
             let testfn = match x.testfn {
-                DynBenchFn(bench) => DynTestFn(Box::new(move || {
-                    bench::run_once(|b| __rust_begin_short_backtrace(|| bench.run(b)))
+                DynBenchFn(benchfn) => DynTestFn(Box::new(move || {
+                    bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b)))
                 })),
                 StaticBenchFn(benchfn) => DynTestFn(Box::new(move || {
                     bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b)))
@@ -544,11 +535,9 @@ fn run_test_inner(
         TestRunOpts { strategy, nocapture: opts.nocapture, concurrency, time: opts.time_options };
 
     match testfn {
-        DynBenchFn(bencher) => {
+        DynBenchFn(benchfn) => {
             // Benchmarks aren't expected to panic, so we run them all in-process.
-            crate::bench::benchmark(id, desc, monitor_ch, opts.nocapture, |harness| {
-                bencher.run(harness)
-            });
+            crate::bench::benchmark(id, desc, monitor_ch, opts.nocapture, benchfn);
             None
         }
         StaticBenchFn(benchfn) => {
index 45fae9c76b44d1972a5009bb7cc6486f54513bd3..40b05704b40cb830e79f6b2174c60ead573ac644 100644 (file)
@@ -1,5 +1,4 @@
 #![allow(missing_docs)]
-#![allow(deprecated)] // Float
 
 use std::mem;
 
index 718613895dee4e30fd2170824b3d07e80c994cb3..7f0b6193d09acc311d81842ceb9b7a6f7ee5e0c9 100644 (file)
@@ -493,7 +493,7 @@ pub fn exclude_should_panic_option() {
 #[test]
 pub fn exact_filter_match() {
     fn tests() -> Vec<TestDescAndFn> {
-        vec!["base", "base::test", "base::test1", "base::test2"]
+        ["base", "base::test", "base::test1", "base::test2"]
             .into_iter()
             .map(|name| TestDescAndFn {
                 desc: TestDesc {
index 3512a57e8e4ae59254e5c5b6fed3c7303bf925ed..37bb38fb0df4efb64d557d31d515e83cd2a7183d 100644 (file)
@@ -74,11 +74,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     }
 }
 
-/// Represents a benchmark function.
-pub trait TDynBenchFn: Send {
-    fn run(&self, harness: &mut Bencher);
-}
-
 // A function that runs a test. If the function returns successfully,
 // the test succeeds; if the function panics then the test fails. We
 // may need to come up with a more clever definition of test in order
@@ -87,7 +82,7 @@ pub enum TestFn {
     StaticTestFn(fn()),
     StaticBenchFn(fn(&mut Bencher)),
     DynTestFn(Box<dyn FnOnce() + Send>),
-    DynBenchFn(Box<dyn TDynBenchFn + 'static>),
+    DynBenchFn(Box<dyn Fn(&mut Bencher) + Send>),
 }
 
 impl TestFn {
index 1941f2b5a0026253ce34ff8367491ba33947b9f2..69fce8d7795c17e442a6a65e2405f5b95ad14ba4 100644 (file)
@@ -3,7 +3,7 @@ name = "unwind"
 version = "0.0.0"
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust.git"
-edition = "2018"
+edition = "2021"
 include = [
   '/libunwind/*',
 ]
index 265f2194fef8d0ce03c61d1c2222828a7c823dde..aa0d4888f082dadf7f889c8b18286f0a14dfe54b 100644 (file)
@@ -19,7 +19,6 @@ ignore = [
     "library/backtrace",
     "library/portable-simd",
     "library/stdarch",
-    "compiler/rustc_codegen_cranelift",
     "compiler/rustc_codegen_gcc",
     "src/doc/book",
     "src/doc/edition-guide",
@@ -36,4 +35,9 @@ ignore = [
     "src/tools/rust-analyzer",
     "src/tools/rustfmt",
     "src/tools/rust-installer",
+
+    # these are ignored by a standard cargo fmt run
+    "compiler/rustc_codegen_cranelift/y.rs", # running rustfmt breaks this file
+    "compiler/rustc_codegen_cranelift/example",
+    "compiler/rustc_codegen_cranelift/scripts",
 ]
index 1ce1f0b26db58030254cf0a903fa10d751476da3..b68b2163f873a07291342ffef28dc7e7edbf8bd3 100644 (file)
@@ -44,11 +44,9 @@ libc = "0.2"
 serde = { version = "1.0.8", features = ["derive"] }
 serde_json = "1.0.2"
 toml = "0.5"
-lazy_static = "1.3.0"
 time = "0.1"
 ignore = "0.4.10"
 opener = "0.5"
-merge = "0.1.0"
 once_cell = "1.7.2"
 
 [target.'cfg(windows)'.dependencies.winapi]
index ed53a98e9a53f69967796a0da077cb4c10d139db..7105a2457e282329ebee43f59d269ffcd50bc635 100644 (file)
@@ -15,6 +15,8 @@
 //! switching compilers for the bootstrap and for build scripts will probably
 //! never get replaced.
 
+include!("../dylib_util.rs");
+
 use std::env;
 use std::path::PathBuf;
 use std::process::{Child, Command};
@@ -50,11 +52,11 @@ fn main() {
 
     let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
     let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
-    let mut dylib_path = bootstrap::util::dylib_path();
+    let mut dylib_path = dylib_path();
     dylib_path.insert(0, PathBuf::from(&libdir));
 
     let mut cmd = Command::new(rustc);
-    cmd.args(&args).env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
+    cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
 
     // Get the name of the crate we're compiling, if any.
     let crate_name =
@@ -161,7 +163,7 @@ fn main() {
         eprintln!(
             "{} command: {:?}={:?} {:?}",
             prefix,
-            bootstrap::util::dylib_path_var(),
+            dylib_path_var(),
             env::join_paths(&dylib_path).unwrap(),
             cmd,
         );
index e4396d53016ea5cf6cf0b95a90de99249cb2f0ab..ad3800834b07cc3f8d1892e3835fcfa01c3de612 100644 (file)
@@ -7,6 +7,8 @@
 use std::path::PathBuf;
 use std::process::Command;
 
+include!("../dylib_util.rs");
+
 fn main() {
     let args = env::args_os().skip(1).collect::<Vec<_>>();
     let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set");
@@ -20,14 +22,14 @@ fn main() {
         Err(_) => 0,
     };
 
-    let mut dylib_path = bootstrap::util::dylib_path();
+    let mut dylib_path = dylib_path();
     dylib_path.insert(0, PathBuf::from(libdir.clone()));
 
     let mut cmd = Command::new(rustdoc);
     cmd.args(&args)
         .arg("--sysroot")
         .arg(&sysroot)
-        .env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap());
+        .env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
 
     // Force all crates compiled by this compiler to (a) be unstable and (b)
     // allow the `rustc_private` feature to link to other unstable crates
@@ -59,7 +61,7 @@ fn main() {
     if verbose > 1 {
         eprintln!(
             "rustdoc command: {:?}={:?} {:?}",
-            bootstrap::util::dylib_path_var(),
+            dylib_path_var(),
             env::join_paths(&dylib_path).unwrap(),
             cmd,
         );
index 5a33073e6b022a7159e8109ac74d76e1cdf6ac62..7c36bb264c45ee0b5ca049a409759d8d88b90d58 100644 (file)
@@ -13,7 +13,7 @@ import sys
 import tarfile
 import tempfile
 
-from time import time
+from time import time, sleep
 
 # Acquire a lock on the build directory to make sure that
 # we don't cause a race condition while building
@@ -42,8 +42,10 @@ def acquire_lock(build_dir):
             while True:
                 try:
                     curs.execute("BEGIN EXCLUSIVE")
+                    break
                 except sqlite3.OperationalError:
                     pass
+                sleep(0.25)
             return curs
     except ImportError:
         print("warning: sqlite3 not available in python, skipping build directory lock")
@@ -974,6 +976,7 @@ class RustBuild(object):
 
     def build_bootstrap(self):
         """Build bootstrap"""
+        print("Building rustbuild")
         build_dir = os.path.join(self.build_dir, "bootstrap")
         if self.clean and os.path.exists(build_dir):
             shutil.rmtree(build_dir)
@@ -1133,7 +1136,7 @@ class RustBuild(object):
             recorded_submodules[data[3]] = data[2]
         for module in filtered_submodules:
             self.update_submodule(module[0], module[1], recorded_submodules)
-        print("Submodules updated in %.2f seconds" % (time() - start_time))
+        print("  Submodules updated in %.2f seconds" % (time() - start_time))
 
     def set_dist_environment(self, url):
         """Set download URL for normal environment"""
index bbd2c087ccabbc8858f47eaae444a61d99fe1e1b..6ccf8b1d5221cd6880daddbd724232fe08f35b0c 100644 (file)
@@ -351,7 +351,6 @@ pub enum Kind {
     Check,
     Clippy,
     Fix,
-    Format,
     Test,
     Bench,
     Dist,
@@ -399,7 +398,7 @@ macro_rules! describe {
                 native::Lld,
                 native::CrtBeginEnd
             ),
-            Kind::Check | Kind::Clippy { .. } | Kind::Fix | Kind::Format => describe!(
+            Kind::Check | Kind::Clippy { .. } | Kind::Fix => describe!(
                 check::Std,
                 check::Rustc,
                 check::Rustdoc,
@@ -989,10 +988,20 @@ pub fn cargo(
             }
         };
 
-        if use_new_symbol_mangling {
-            rustflags.arg("-Zsymbol-mangling-version=v0");
+        // cfg(bootstrap) -- drop the compiler.stage == 0 branch.
+        if compiler.stage == 0 {
+            if use_new_symbol_mangling {
+                rustflags.arg("-Zsymbol-mangling-version=v0");
+            } else {
+                rustflags.arg("-Zsymbol-mangling-version=legacy");
+            }
         } else {
-            rustflags.arg("-Zsymbol-mangling-version=legacy");
+            if use_new_symbol_mangling {
+                rustflags.arg("-Csymbol-mangling-version=v0");
+            } else {
+                rustflags.arg("-Csymbol-mangling-version=legacy");
+                rustflags.arg("-Zunstable-options");
+            }
         }
 
         // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
index 0c16fae01bca788ac7f2f7ba407c8db159da87d2..fac5d8db5119df6da5c7b4ab1a06241e19eba326 100644 (file)
@@ -13,7 +13,8 @@
 use std::path::{Path, PathBuf};
 use std::sync::Mutex;
 
-use lazy_static::lazy_static;
+// FIXME: replace with std::lazy after it gets stabilized and reaches beta
+use once_cell::sync::Lazy;
 
 use crate::builder::Step;
 
@@ -222,9 +223,7 @@ pub fn intern_path(&self, s: PathBuf) -> Interned<PathBuf> {
     }
 }
 
-lazy_static! {
-    pub static ref INTERNER: Interner = Interner::default();
-}
+pub static INTERNER: Lazy<Interner> = Lazy::new(Interner::default);
 
 /// This is essentially a `HashMap` which allows storing any type in its input and
 /// any type in its output. It is a write-once cache; values are never evicted,
index c0ab093f9524ad8c2a443b08a92a7d45350ec103..043b38ecece7da5cb58ab42914468bf0543c123a 100644 (file)
@@ -1143,7 +1143,6 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
         let libdir = builder.sysroot_libdir(target_compiler, target_compiler.host);
         let libdir_bin = libdir.parent().unwrap().join("bin");
         t!(fs::create_dir_all(&libdir_bin));
-
         if let Some(lld_install) = lld_install {
             let src_exe = exe("lld", target_compiler.host);
             let dst_exe = exe("rust-lld", target_compiler.host);
@@ -1161,17 +1160,11 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
             }
         }
 
-        // Similarly, copy `llvm-dwp` into libdir for Split DWARF. Only copy it when the LLVM
-        // backend is used to avoid unnecessarily building LLVM and because LLVM is not checked
-        // out by default when the LLVM backend is not enabled.
         if builder.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
-            let src_exe = exe("llvm-dwp", target_compiler.host);
-            let dst_exe = exe("rust-llvm-dwp", target_compiler.host);
             let llvm_config_bin = builder.ensure(native::Llvm { target: target_compiler.host });
             if !builder.config.dry_run {
                 let llvm_bin_dir = output(Command::new(llvm_config_bin).arg("--bindir"));
                 let llvm_bin_dir = Path::new(llvm_bin_dir.trim());
-                builder.copy(&llvm_bin_dir.join(&src_exe), &libdir_bin.join(&dst_exe));
 
                 // Since we've already built the LLVM tools, install them to the sysroot.
                 // This is the equivalent of installing the `llvm-tools-preview` component via
index 7a4593a75f280b06cd6bf9324a5947dce8d74b2d..5af9248583caefd33ec026ef7b8feb01ce933189 100644 (file)
@@ -18,7 +18,6 @@
 use crate::flags::{Color, Flags};
 use crate::util::exe;
 use build_helper::t;
-use merge::Merge;
 use serde::Deserialize;
 
 macro_rules! check_ci_llvm {
@@ -334,6 +333,10 @@ struct TomlConfig {
     profile: Option<String>,
 }
 
+trait Merge {
+    fn merge(&mut self, other: Self);
+}
+
 impl Merge for TomlConfig {
     fn merge(
         &mut self,
@@ -357,105 +360,136 @@ fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>) {
     }
 }
 
-/// TOML representation of various global build decisions.
-#[derive(Deserialize, Default, Clone, Merge)]
-#[serde(deny_unknown_fields, rename_all = "kebab-case")]
-struct Build {
-    build: Option<String>,
-    host: Option<Vec<String>>,
-    target: Option<Vec<String>>,
-    // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable
-    build_dir: Option<String>,
-    cargo: Option<String>,
-    rustc: Option<String>,
-    rustfmt: Option<PathBuf>,
-    docs: Option<bool>,
-    compiler_docs: Option<bool>,
-    docs_minification: Option<bool>,
-    submodules: Option<bool>,
-    fast_submodules: Option<bool>,
-    gdb: Option<String>,
-    nodejs: Option<String>,
-    npm: Option<String>,
-    python: Option<String>,
-    locked_deps: Option<bool>,
-    vendor: Option<bool>,
-    full_bootstrap: Option<bool>,
-    extended: Option<bool>,
-    tools: Option<HashSet<String>>,
-    verbose: Option<usize>,
-    sanitizers: Option<bool>,
-    profiler: Option<bool>,
-    cargo_native_static: Option<bool>,
-    low_priority: Option<bool>,
-    configure_args: Option<Vec<String>>,
-    local_rebuild: Option<bool>,
-    print_step_timings: Option<bool>,
-    print_step_rusage: Option<bool>,
-    check_stage: Option<u32>,
-    doc_stage: Option<u32>,
-    build_stage: Option<u32>,
-    test_stage: Option<u32>,
-    install_stage: Option<u32>,
-    dist_stage: Option<u32>,
-    bench_stage: Option<u32>,
-    patch_binaries_for_nix: Option<bool>,
+// We are using a decl macro instead of a derive proc macro here to reduce the compile time of
+// rustbuild.
+macro_rules! derive_merge {
+    ($(#[$attr:meta])* struct $name:ident {
+        $($field:ident: $field_ty:ty,)*
+    }) => {
+        $(#[$attr])*
+        struct $name {
+            $($field: $field_ty,)*
+        }
+
+        impl Merge for $name {
+            fn merge(&mut self, other: Self) {
+                $(
+                    if !self.$field.is_some() {
+                        self.$field = other.$field;
+                    }
+                )*
+            }
+        }
+    }
 }
 
-/// TOML representation of various global install decisions.
-#[derive(Deserialize, Default, Clone, Merge)]
-#[serde(deny_unknown_fields, rename_all = "kebab-case")]
-struct Install {
-    prefix: Option<String>,
-    sysconfdir: Option<String>,
-    docdir: Option<String>,
-    bindir: Option<String>,
-    libdir: Option<String>,
-    mandir: Option<String>,
-    datadir: Option<String>,
+derive_merge! {
+    /// TOML representation of various global build decisions.
+    #[derive(Deserialize, Default, Clone)]
+    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
+    struct Build {
+        build: Option<String>,
+        host: Option<Vec<String>>,
+        target: Option<Vec<String>>,
+        // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable
+        build_dir: Option<String>,
+        cargo: Option<String>,
+        rustc: Option<String>,
+        rustfmt: Option<PathBuf>,
+        docs: Option<bool>,
+        compiler_docs: Option<bool>,
+        docs_minification: Option<bool>,
+        submodules: Option<bool>,
+        fast_submodules: Option<bool>,
+        gdb: Option<String>,
+        nodejs: Option<String>,
+        npm: Option<String>,
+        python: Option<String>,
+        locked_deps: Option<bool>,
+        vendor: Option<bool>,
+        full_bootstrap: Option<bool>,
+        extended: Option<bool>,
+        tools: Option<HashSet<String>>,
+        verbose: Option<usize>,
+        sanitizers: Option<bool>,
+        profiler: Option<bool>,
+        cargo_native_static: Option<bool>,
+        low_priority: Option<bool>,
+        configure_args: Option<Vec<String>>,
+        local_rebuild: Option<bool>,
+        print_step_timings: Option<bool>,
+        print_step_rusage: Option<bool>,
+        check_stage: Option<u32>,
+        doc_stage: Option<u32>,
+        build_stage: Option<u32>,
+        test_stage: Option<u32>,
+        install_stage: Option<u32>,
+        dist_stage: Option<u32>,
+        bench_stage: Option<u32>,
+        patch_binaries_for_nix: Option<bool>,
+    }
 }
 
-/// TOML representation of how the LLVM build is configured.
-#[derive(Deserialize, Default, Merge)]
-#[serde(deny_unknown_fields, rename_all = "kebab-case")]
-struct Llvm {
-    skip_rebuild: Option<bool>,
-    optimize: Option<bool>,
-    thin_lto: Option<bool>,
-    release_debuginfo: Option<bool>,
-    assertions: Option<bool>,
-    tests: Option<bool>,
-    plugins: Option<bool>,
-    ccache: Option<StringOrBool>,
-    version_check: Option<bool>,
-    static_libstdcpp: Option<bool>,
-    ninja: Option<bool>,
-    targets: Option<String>,
-    experimental_targets: Option<String>,
-    link_jobs: Option<u32>,
-    link_shared: Option<bool>,
-    version_suffix: Option<String>,
-    clang_cl: Option<String>,
-    cflags: Option<String>,
-    cxxflags: Option<String>,
-    ldflags: Option<String>,
-    use_libcxx: Option<bool>,
-    use_linker: Option<String>,
-    allow_old_toolchain: Option<bool>,
-    polly: Option<bool>,
-    clang: Option<bool>,
-    download_ci_llvm: Option<StringOrBool>,
+derive_merge! {
+    /// TOML representation of various global install decisions.
+    #[derive(Deserialize, Default, Clone)]
+    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
+    struct Install {
+        prefix: Option<String>,
+        sysconfdir: Option<String>,
+        docdir: Option<String>,
+        bindir: Option<String>,
+        libdir: Option<String>,
+        mandir: Option<String>,
+        datadir: Option<String>,
+    }
 }
 
-#[derive(Deserialize, Default, Clone, Merge)]
-#[serde(deny_unknown_fields, rename_all = "kebab-case")]
-struct Dist {
-    sign_folder: Option<String>,
-    gpg_password_file: Option<String>,
-    upload_addr: Option<String>,
-    src_tarball: Option<bool>,
-    missing_tools: Option<bool>,
-    compression_formats: Option<Vec<String>>,
+derive_merge! {
+    /// TOML representation of how the LLVM build is configured.
+    #[derive(Deserialize, Default)]
+    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
+    struct Llvm {
+        skip_rebuild: Option<bool>,
+        optimize: Option<bool>,
+        thin_lto: Option<bool>,
+        release_debuginfo: Option<bool>,
+        assertions: Option<bool>,
+        tests: Option<bool>,
+        plugins: Option<bool>,
+        ccache: Option<StringOrBool>,
+        version_check: Option<bool>,
+        static_libstdcpp: Option<bool>,
+        ninja: Option<bool>,
+        targets: Option<String>,
+        experimental_targets: Option<String>,
+        link_jobs: Option<u32>,
+        link_shared: Option<bool>,
+        version_suffix: Option<String>,
+        clang_cl: Option<String>,
+        cflags: Option<String>,
+        cxxflags: Option<String>,
+        ldflags: Option<String>,
+        use_libcxx: Option<bool>,
+        use_linker: Option<String>,
+        allow_old_toolchain: Option<bool>,
+        polly: Option<bool>,
+        clang: Option<bool>,
+        download_ci_llvm: Option<StringOrBool>,
+    }
+}
+
+derive_merge! {
+    #[derive(Deserialize, Default, Clone)]
+    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
+    struct Dist {
+        sign_folder: Option<String>,
+        gpg_password_file: Option<String>,
+        upload_addr: Option<String>,
+        src_tarball: Option<bool>,
+        missing_tools: Option<bool>,
+        compression_formats: Option<Vec<String>>,
+    }
 }
 
 #[derive(Deserialize)]
@@ -471,80 +505,84 @@ fn default() -> StringOrBool {
     }
 }
 
-/// TOML representation of how the Rust build is configured.
-#[derive(Deserialize, Default, Merge)]
-#[serde(deny_unknown_fields, rename_all = "kebab-case")]
-struct Rust {
-    optimize: Option<bool>,
-    debug: Option<bool>,
-    codegen_units: Option<u32>,
-    codegen_units_std: Option<u32>,
-    debug_assertions: Option<bool>,
-    debug_assertions_std: Option<bool>,
-    overflow_checks: Option<bool>,
-    overflow_checks_std: Option<bool>,
-    debug_logging: Option<bool>,
-    debuginfo_level: Option<u32>,
-    debuginfo_level_rustc: Option<u32>,
-    debuginfo_level_std: Option<u32>,
-    debuginfo_level_tools: Option<u32>,
-    debuginfo_level_tests: Option<u32>,
-    run_dsymutil: Option<bool>,
-    backtrace: Option<bool>,
-    incremental: Option<bool>,
-    parallel_compiler: Option<bool>,
-    default_linker: Option<String>,
-    channel: Option<String>,
-    description: Option<String>,
-    musl_root: Option<String>,
-    rpath: Option<bool>,
-    verbose_tests: Option<bool>,
-    optimize_tests: Option<bool>,
-    codegen_tests: Option<bool>,
-    ignore_git: Option<bool>,
-    dist_src: Option<bool>,
-    save_toolstates: Option<String>,
-    codegen_backends: Option<Vec<String>>,
-    lld: Option<bool>,
-    use_lld: Option<bool>,
-    llvm_tools: Option<bool>,
-    deny_warnings: Option<bool>,
-    backtrace_on_ice: Option<bool>,
-    verify_llvm_ir: Option<bool>,
-    thin_lto_import_instr_limit: Option<u32>,
-    remap_debuginfo: Option<bool>,
-    jemalloc: Option<bool>,
-    test_compare_mode: Option<bool>,
-    llvm_libunwind: Option<String>,
-    control_flow_guard: Option<bool>,
-    new_symbol_mangling: Option<bool>,
-    profile_generate: Option<String>,
-    profile_use: Option<String>,
-    // ignored; this is set from an env var set by bootstrap.py
-    download_rustc: Option<StringOrBool>,
+derive_merge! {
+    /// TOML representation of how the Rust build is configured.
+    #[derive(Deserialize, Default)]
+    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
+    struct Rust {
+        optimize: Option<bool>,
+        debug: Option<bool>,
+        codegen_units: Option<u32>,
+        codegen_units_std: Option<u32>,
+        debug_assertions: Option<bool>,
+        debug_assertions_std: Option<bool>,
+        overflow_checks: Option<bool>,
+        overflow_checks_std: Option<bool>,
+        debug_logging: Option<bool>,
+        debuginfo_level: Option<u32>,
+        debuginfo_level_rustc: Option<u32>,
+        debuginfo_level_std: Option<u32>,
+        debuginfo_level_tools: Option<u32>,
+        debuginfo_level_tests: Option<u32>,
+        run_dsymutil: Option<bool>,
+        backtrace: Option<bool>,
+        incremental: Option<bool>,
+        parallel_compiler: Option<bool>,
+        default_linker: Option<String>,
+        channel: Option<String>,
+        description: Option<String>,
+        musl_root: Option<String>,
+        rpath: Option<bool>,
+        verbose_tests: Option<bool>,
+        optimize_tests: Option<bool>,
+        codegen_tests: Option<bool>,
+        ignore_git: Option<bool>,
+        dist_src: Option<bool>,
+        save_toolstates: Option<String>,
+        codegen_backends: Option<Vec<String>>,
+        lld: Option<bool>,
+        use_lld: Option<bool>,
+        llvm_tools: Option<bool>,
+        deny_warnings: Option<bool>,
+        backtrace_on_ice: Option<bool>,
+        verify_llvm_ir: Option<bool>,
+        thin_lto_import_instr_limit: Option<u32>,
+        remap_debuginfo: Option<bool>,
+        jemalloc: Option<bool>,
+        test_compare_mode: Option<bool>,
+        llvm_libunwind: Option<String>,
+        control_flow_guard: Option<bool>,
+        new_symbol_mangling: Option<bool>,
+        profile_generate: Option<String>,
+        profile_use: Option<String>,
+        // ignored; this is set from an env var set by bootstrap.py
+        download_rustc: Option<StringOrBool>,
+    }
 }
 
-/// TOML representation of how each build target is configured.
-#[derive(Deserialize, Default, Merge)]
-#[serde(deny_unknown_fields, rename_all = "kebab-case")]
-struct TomlTarget {
-    cc: Option<String>,
-    cxx: Option<String>,
-    ar: Option<String>,
-    ranlib: Option<String>,
-    default_linker: Option<PathBuf>,
-    linker: Option<String>,
-    llvm_config: Option<String>,
-    llvm_filecheck: Option<String>,
-    android_ndk: Option<String>,
-    sanitizers: Option<bool>,
-    profiler: Option<bool>,
-    crt_static: Option<bool>,
-    musl_root: Option<String>,
-    musl_libdir: Option<String>,
-    wasi_root: Option<String>,
-    qemu_rootfs: Option<String>,
-    no_std: Option<bool>,
+derive_merge! {
+    /// TOML representation of how each build target is configured.
+    #[derive(Deserialize, Default)]
+    #[serde(deny_unknown_fields, rename_all = "kebab-case")]
+    struct TomlTarget {
+        cc: Option<String>,
+        cxx: Option<String>,
+        ar: Option<String>,
+        ranlib: Option<String>,
+        default_linker: Option<PathBuf>,
+        linker: Option<String>,
+        llvm_config: Option<String>,
+        llvm_filecheck: Option<String>,
+        android_ndk: Option<String>,
+        sanitizers: Option<bool>,
+        profiler: Option<bool>,
+        crt_static: Option<bool>,
+        musl_root: Option<String>,
+        musl_libdir: Option<String>,
+        wasi_root: Option<String>,
+        qemu_rootfs: Option<String>,
+        no_std: Option<bool>,
+    }
 }
 
 impl Config {
@@ -1111,10 +1149,6 @@ pub fn verbose(&self) -> bool {
         self.verbose > 0
     }
 
-    pub fn very_verbose(&self) -> bool {
-        self.verbose > 1
-    }
-
     pub fn sanitizers_enabled(&self, target: TargetSelection) -> bool {
         self.target_config.get(&target).map(|t| t.sanitizers).flatten().unwrap_or(self.sanitizers)
     }
index dd179df394889e91dbe213d35bf1570d103a75e1..7d9b3da48ecb0578e12720eddb115844ecea3b66 100644 (file)
@@ -398,12 +398,12 @@ fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
             // component for now.
             maybe_install_llvm_runtime(builder, host, image);
 
-            let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
             let dst_dir = image.join("lib/rustlib").join(&*host.triple).join("bin");
             t!(fs::create_dir_all(&dst_dir));
 
             // Copy over lld if it's there
             if builder.config.lld_enabled {
+                let src_dir = builder.sysroot_libdir(compiler, host).parent().unwrap().join("bin");
                 let rust_lld = exe("rust-lld", compiler.host);
                 builder.copy(&src_dir.join(&rust_lld), &dst_dir.join(&rust_lld));
                 // for `-Z gcc-ld=lld`
@@ -417,10 +417,6 @@ fn prepare_image(builder: &Builder<'_>, compiler: Compiler, image: &Path) {
                 }
             }
 
-            // Copy over llvm-dwp if it's there
-            let exe = exe("rust-llvm-dwp", compiler.host);
-            builder.copy(&src_dir.join(&exe), &dst_dir.join(&exe));
-
             // Man pages
             t!(fs::create_dir_all(image.join("share/man/man1")));
             let man_src = builder.src.join("src/doc/man");
diff --git a/src/bootstrap/dylib_util.rs b/src/bootstrap/dylib_util.rs
new file mode 100644 (file)
index 0000000..6d75272
--- /dev/null
@@ -0,0 +1,28 @@
+// Various utilities for working with dylib paths.
+//
+// This file is meant to be included directly to avoid a dependency on the bootstrap library from
+// the rustc and rustdoc wrappers. This improves compilation time by reducing the linking time.
+
+/// Returns the environment variable which the dynamic library lookup path
+/// resides in for this platform.
+pub fn dylib_path_var() -> &'static str {
+    if cfg!(target_os = "windows") {
+        "PATH"
+    } else if cfg!(target_os = "macos") {
+        "DYLD_LIBRARY_PATH"
+    } else if cfg!(target_os = "haiku") {
+        "LIBRARY_PATH"
+    } else {
+        "LD_LIBRARY_PATH"
+    }
+}
+
+/// Parses the `dylib_path_var()` environment variable, returning a list of
+/// paths that are members of this lookup path.
+pub fn dylib_path() -> Vec<PathBuf> {
+    let var = match env::var_os(dylib_path_var()) {
+        Some(v) => v,
+        None => return vec![],
+    };
+    env::split_paths(&var).collect()
+}
index 2fddda74a28e924bfd3e7db776bdc38e67a15933..9180c5f03af6810974234c15d830d8d9881fe148 100644 (file)
@@ -401,26 +401,19 @@ pub fn parse(args: &[String]) -> Flags {
                     "\n
 Arguments:
     This subcommand accepts a number of paths to directories to the crates
-    and/or artifacts to compile. For example:
-
-        ./x.py build library/core
-        ./x.py build library/core library/proc_macro
-        ./x.py build library/std --stage 1
-
-    If no arguments are passed then the complete artifacts for that stage are
-    also compiled.
+    and/or artifacts to compile. For example, for a quick build of a usable
+    compiler:
 
-        ./x.py build
-        ./x.py build --stage 1
+        ./x.py build --stage 1 library/std
 
-    For a quick build of a usable compiler, you can pass:
+    This will build a compiler and standard library from the local source code.
+    Once this is done, build/$ARCH/stage1 contains a usable compiler.
 
-        ./x.py build --stage 1 library/test
+    If no arguments are passed then the default artifacts for that stage are
+    compiled. For example:
 
-    This will first build everything once (like `--stage 0` without further
-    arguments would), and then use the compiler built in stage 0 to build
-    library/test and its dependencies.
-    Once this is done, build/$ARCH/stage1 contains a usable compiler.",
+        ./x.py build --stage 0
+        ./x.py build ",
                 );
             }
             "check" | "c" => {
@@ -430,14 +423,9 @@ pub fn parse(args: &[String]) -> Flags {
     This subcommand accepts a number of paths to directories to the crates
     and/or artifacts to compile. For example:
 
-        ./x.py check library/core
-        ./x.py check library/core library/proc_macro
+        ./x.py check library/std
 
-    If no arguments are passed then the complete artifacts are compiled: std, test, and rustc. Note
-    also that since we use `cargo check`, by default this will automatically enable incremental
-    compilation, so there's no need to pass it separately, though it won't hurt. We also completely
-    ignore the stage passed, as there's no way to compile in non-stage 0 without actually building
-    the compiler.",
+    If no arguments are passed then many artifacts are checked.",
                 );
             }
             "clippy" => {
index 82462f9758e5c08853d2f59aa434888db863089a..8569089f70128beff3440f296c6859c3b853dd59 100644 (file)
 use std::io::{Read, Seek, SeekFrom, Write};
 use std::path::{Path, PathBuf};
 use std::process::{self, Command};
-use std::slice;
 use std::str;
 
 #[cfg(unix)]
@@ -472,10 +471,6 @@ pub fn new(config: Config) -> Build {
         build
     }
 
-    pub fn build_triple(&self) -> &[Interned<String>] {
-        slice::from_ref(&self.build.triple)
-    }
-
     // modified from `check_submodule` and `update_submodule` in bootstrap.py
     /// Given a path to the directory of a submodule, update it.
     ///
index 57178aa382ffd789ac68a6fb9b9cf9051aceb7b8..ee58bedcc8735104091947eead2b8b5af2dcd833 100644 (file)
 use crate::builder::Builder;
 use crate::config::{Config, TargetSelection};
 
-/// Returns the `name` as the filename of a static library for `target`.
-pub fn staticlib(name: &str, target: TargetSelection) -> String {
-    if target.contains("windows") { format!("{}.lib", name) } else { format!("lib{}.a", name) }
-}
-
 /// Given an executable called `name`, return the filename for the
 /// executable for a particular target.
 pub fn exe(name: &str, target: TargetSelection) -> String {
@@ -54,29 +49,7 @@ pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) {
     cmd.env(dylib_path_var(), t!(env::join_paths(list)));
 }
 
-/// Returns the environment variable which the dynamic library lookup path
-/// resides in for this platform.
-pub fn dylib_path_var() -> &'static str {
-    if cfg!(target_os = "windows") {
-        "PATH"
-    } else if cfg!(target_os = "macos") {
-        "DYLD_LIBRARY_PATH"
-    } else if cfg!(target_os = "haiku") {
-        "LIBRARY_PATH"
-    } else {
-        "LD_LIBRARY_PATH"
-    }
-}
-
-/// Parses the `dylib_path_var()` environment variable, returning a list of
-/// paths that are members of this lookup path.
-pub fn dylib_path() -> Vec<PathBuf> {
-    let var = match env::var_os(dylib_path_var()) {
-        Some(v) => v,
-        None => return vec![],
-    };
-    env::split_paths(&var).collect()
-}
+include!("dylib_util.rs");
 
 /// Adds a list of lookup paths to `cmd`'s link library lookup path.
 pub fn add_link_lib_path(path: Vec<PathBuf>, cmd: &mut Command) {
@@ -103,21 +76,6 @@ fn link_lib_path() -> Vec<PathBuf> {
     env::split_paths(&var).collect()
 }
 
-/// `push` all components to `buf`. On windows, append `.exe` to the last component.
-pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf {
-    let (&file, components) = components.split_last().expect("at least one component required");
-    let mut file = file.to_owned();
-
-    if cfg!(windows) {
-        file.push_str(".exe");
-    }
-
-    buf.extend(components);
-    buf.push(file);
-
-    buf
-}
-
 pub struct TimeIt(bool, Instant);
 
 /// Returns an RAII structure that prints out how long it took to drop.
index c27e42a266220a819684ddeed73be8598a3b1c74..66333e2b99214a3e9ab794afce703b991ba6ba0c 100644 (file)
@@ -17,12 +17,12 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   pkg-config \
   mingw-w64
 
-RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ
-ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
+RUN curl -sL https://nodejs.org/dist/v16.9.0/node-v16.9.0-linux-x64.tar.xz | tar -xJ
+ENV PATH="/node-v16.9.0-linux-x64/bin:${PATH}"
 # Install es-check
 # Pin its version to prevent unrelated CI failures due to future es-check versions.
-RUN npm install es-check@5.2.3 -g
-RUN npm install eslint@7.20.0 -g
+RUN npm install es-check@6.1.1 -g
+RUN npm install eslint@8.6.0 -g
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -40,5 +40,5 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \
            /scripts/validate-toolstate.sh && \
            /scripts/validate-error-codes.sh && \
            # Runs checks to ensure that there are no ES5 issues in our JS code.
-           es-check es5 ../src/librustdoc/html/static/js/*.js && \
+           es-check es6 ../src/librustdoc/html/static/js/*.js && \
            eslint ../src/librustdoc/html/static/js/*.js
index 3c17f316d1fe870e7ff11a5c565efe20b7a4f031..e358b8139d7d0c3e070dbd126e60f1b0c2c58df0 100644 (file)
@@ -48,7 +48,9 @@ cd musl-cross-make
 git checkout a54eb56f33f255dfca60be045f12a5cfaf5a72a9
 
 # Fix the cfi detection script in musl's configure so cfi is generated
-# when debug info is asked for.
+# when debug info is asked for. This patch is derived from
+# https://git.musl-libc.org/cgit/musl/commit/?id=c4d4028dde90562f631edf559fbc42d8ec1b29de.
+# When we upgrade to a version that includes this commit, we can remove the patch.
 mkdir patches/musl-1.1.24
 cp ../musl-patch-configure.diff patches/musl-1.1.24/0001-fix-cfi-detection.diff
 
index 8a0bb3c96e71927b80fa2286d7a5a5f2547c6aa4..d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3c 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 8a0bb3c96e71927b80fa2286d7a5a5f2547c6aa4
+Subproject commit d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3c
index 06f9e61931bcf58b91dfe6c924057e42ce273ee1..f8ba2f12df60ee19b96de24ae5b73af3de8a446b 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 06f9e61931bcf58b91dfe6c924057e42ce273ee1
+Subproject commit f8ba2f12df60ee19b96de24ae5b73af3de8a446b
index 9bf0028b557798ddd07a6f652e4d0c635d3d6620..875464457c4104686faf667f47848aa7b0f0a744 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 9bf0028b557798ddd07a6f652e4d0c635d3d6620
+Subproject commit 875464457c4104686faf667f47848aa7b0f0a744
index aea55d4f4b69cb0a19a8c0f589e584def8cbbfd2..534fd19b52eb27d5e40d73419588a5ee893c2696 100644 (file)
@@ -335,7 +335,8 @@ panic during execution. If the code doesn't panic, the test will fail.
 The `no_run` attribute will compile your code but not run it. This is
 important for examples such as "Here's how to retrieve a web page,"
 which you would want to ensure compiles, but might be run in a test
-environment that has no network access.
+environment that has no network access. This attribute can also be
+used to demonstrate code snippets that can cause Undefined Behavior.
 
 ```rust
 /// ```no_run
index 56ca7c03928009d53d34c9a6565df29f5e55f7b7..d60be193bda2b1108328ae68d8501656c0d0a63a 100644 (file)
@@ -84,6 +84,39 @@ in documentation.
 `#![feature(doc_cfg)]` feature gate. For more information, see [its chapter in the Unstable
 Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
 
+### `doc_auto_cfg`: Automatically generate `#[doc(cfg)]`
+
+`doc_auto_cfg` is an extension to the `#[doc(cfg)]` feature. With it, you don't need to add
+`#[doc(cfg(...)]` anymore unless you want to override the default behaviour. So if we take the
+previous source code:
+
+```rust
+#![feature(doc_auto_cfg)]
+
+/// Token struct that can only be used on Windows.
+#[cfg(any(windows, doc))]
+pub struct WindowsToken;
+
+/// Token struct that can only be used on Unix.
+#[cfg(any(unix, doc))]
+pub struct UnixToken;
+
+/// Token struct that is only available with the `serde` feature
+#[cfg(feature = "serde")]
+#[derive(serde::Deserialize)]
+pub struct SerdeToken;
+```
+
+It'll render almost the same, the difference being that `doc` will also be displayed. To fix this,
+you can use `doc_cfg_hide`:
+
+```rust
+#![feature(doc_cfg_hide)]
+#![doc(cfg_hide(doc))]
+```
+
+And `doc` won't show up anymore!
+
 [cfg-doc]: ./advanced-features.md
 [unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html
 [issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781
index f4d1ca0ec691130ffe2bcd74006655ae213d1012..39eb407269c1180931a07d1d10054aec8502bada 100644 (file)
@@ -27,7 +27,7 @@ When running a coverage-instrumented program, the counter values are written to
 [`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 `-Z 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 symbol-mangling-version=legacy`.
+> **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
 
index a3cb982f277a08860d4d4c8dc08dcd5b117510b7..bdf756df6fd79e0e4428af186fc60d4b6c9fc261 100644 (file)
@@ -8,9 +8,10 @@ path = "lib.rs"
 
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
+askama = { version = "0.11", default-features = false }
 pulldown-cmark = { version = "0.9", default-features = false }
 minifier = "0.0.41"
-rayon = "1.3.1"
+rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 smallvec = "1.6.1"
@@ -20,7 +21,6 @@ regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
 tracing = "0.1"
 tracing-tree = "0.2.0"
-tera = { version = "1.10.0", default-features = false }
 
 [dependencies.tracing-subscriber]
 version = "0.3.3"
index f54ab9f2b11aac9bc210bbc836c91bd8b087c821..eafc74b9945baf21b485c226eb36cd738213643f 100644 (file)
@@ -19,118 +19,119 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
 
         trace!("get_blanket_impls({:?})", ty);
         let mut impls = Vec::new();
-        for trait_def_id in self.cx.tcx.all_traits() {
-            if !self.cx.cache.access_levels.is_public(trait_def_id)
-                || self.cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
-            {
-                continue;
-            }
-            // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
-            let trait_impls = self.cx.tcx.trait_impls_of(trait_def_id);
-            for &impl_def_id in trait_impls.blanket_impls() {
-                trace!(
-                    "get_blanket_impls: Considering impl for trait '{:?}' {:?}",
-                    trait_def_id,
-                    impl_def_id
-                );
-                let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap();
-                let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
-                let may_apply = is_param && self.cx.tcx.infer_ctxt().enter(|infcx| {
-                    let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
-                    let ty = ty.subst(infcx.tcx, substs);
-                    let param_env = param_env.subst(infcx.tcx, substs);
+        self.cx.with_all_traits(|cx, all_traits| {
+            for &trait_def_id in all_traits {
+                if !cx.cache.access_levels.is_public(trait_def_id)
+                    || cx.generated_synthetics.get(&(ty, trait_def_id)).is_some()
+                {
+                    continue;
+                }
+                // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls
+                let trait_impls = cx.tcx.trait_impls_of(trait_def_id);
+                for &impl_def_id in trait_impls.blanket_impls() {
+                    trace!(
+                        "get_blanket_impls: Considering impl for trait '{:?}' {:?}",
+                        trait_def_id,
+                        impl_def_id
+                    );
+                    let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap();
+                    let is_param = matches!(trait_ref.self_ty().kind(), ty::Param(_));
+                    let may_apply = is_param && cx.tcx.infer_ctxt().enter(|infcx| {
+                        let substs = infcx.fresh_substs_for_item(DUMMY_SP, item_def_id);
+                        let ty = ty.subst(infcx.tcx, substs);
+                        let param_env = param_env.subst(infcx.tcx, substs);
 
-                    let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
-                    let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
+                        let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
+                        let trait_ref = trait_ref.subst(infcx.tcx, impl_substs);
 
-                    // Require the type the impl is implemented on to match
-                    // our type, and ignore the impl if there was a mismatch.
-                    let cause = traits::ObligationCause::dummy();
-                    let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty);
-                    if let Ok(InferOk { value: (), obligations }) = eq_result {
-                        // FIXME(eddyb) ignoring `obligations` might cause false positives.
-                        drop(obligations);
+                        // Require the type the impl is implemented on to match
+                        // our type, and ignore the impl if there was a mismatch.
+                        let cause = traits::ObligationCause::dummy();
+                        let eq_result = infcx.at(&cause, param_env).eq(trait_ref.self_ty(), ty);
+                        if let Ok(InferOk { value: (), obligations }) = eq_result {
+                            // FIXME(eddyb) ignoring `obligations` might cause false positives.
+                            drop(obligations);
 
-                        trace!(
-                            "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
-                            param_env,
-                            trait_ref,
-                            ty
-                        );
-                        let predicates = self
-                            .cx
-                            .tcx
-                            .predicates_of(impl_def_id)
-                            .instantiate(self.cx.tcx, impl_substs)
-                            .predicates
-                            .into_iter()
-                            .chain(Some(
-                                ty::Binder::dummy(trait_ref)
-                                    .to_poly_trait_predicate()
-                                    .map_bound(ty::PredicateKind::Trait)
-                                    .to_predicate(infcx.tcx),
-                            ));
-                        for predicate in predicates {
-                            debug!("testing predicate {:?}", predicate);
-                            let obligation = traits::Obligation::new(
-                                traits::ObligationCause::dummy(),
+                            trace!(
+                                "invoking predicate_may_hold: param_env={:?}, trait_ref={:?}, ty={:?}",
                                 param_env,
-                                predicate,
+                                trait_ref,
+                                ty
                             );
-                            match infcx.evaluate_obligation(&obligation) {
-                                Ok(eval_result) if eval_result.may_apply() => {}
-                                Err(traits::OverflowError::Canonical) => {}
-                                Err(traits::OverflowError::ErrorReporting) => {}
-                                _ => {
-                                    return false;
+                            let predicates = cx
+                                .tcx
+                                .predicates_of(impl_def_id)
+                                .instantiate(cx.tcx, impl_substs)
+                                .predicates
+                                .into_iter()
+                                .chain(Some(
+                                    ty::Binder::dummy(trait_ref)
+                                        .to_poly_trait_predicate()
+                                        .map_bound(ty::PredicateKind::Trait)
+                                        .to_predicate(infcx.tcx),
+                                ));
+                            for predicate in predicates {
+                                debug!("testing predicate {:?}", predicate);
+                                let obligation = traits::Obligation::new(
+                                    traits::ObligationCause::dummy(),
+                                    param_env,
+                                    predicate,
+                                );
+                                match infcx.evaluate_obligation(&obligation) {
+                                    Ok(eval_result) if eval_result.may_apply() => {}
+                                    Err(traits::OverflowError::Canonical) => {}
+                                    Err(traits::OverflowError::ErrorReporting) => {}
+                                    _ => {
+                                        return false;
+                                    }
                                 }
                             }
+                            true
+                        } else {
+                            false
                         }
-                        true
-                    } else {
-                        false
+                    });
+                    debug!(
+                        "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
+                        may_apply, trait_ref, ty
+                    );
+                    if !may_apply {
+                        continue;
                     }
-                });
-                debug!(
-                    "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}",
-                    may_apply, trait_ref, ty
-                );
-                if !may_apply {
-                    continue;
-                }
 
-                self.cx.generated_synthetics.insert((ty, trait_def_id));
+                    cx.generated_synthetics.insert((ty, trait_def_id));
 
-                impls.push(Item {
-                    name: None,
-                    attrs: Default::default(),
-                    visibility: Inherited,
-                    def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
-                    kind: box ImplItem(Impl {
-                        unsafety: hir::Unsafety::Normal,
-                        generics: clean_ty_generics(
-                            self.cx,
-                            self.cx.tcx.generics_of(impl_def_id),
-                            self.cx.tcx.explicit_predicates_of(impl_def_id),
-                        ),
-                        // FIXME(eddyb) compute both `trait_` and `for_` from
-                        // the post-inference `trait_ref`, as it's more accurate.
-                        trait_: Some(trait_ref.clean(self.cx)),
-                        for_: ty.clean(self.cx),
-                        items: self
-                            .cx
-                            .tcx
-                            .associated_items(impl_def_id)
-                            .in_definition_order()
-                            .map(|x| x.clean(self.cx))
-                            .collect::<Vec<_>>(),
-                        polarity: ty::ImplPolarity::Positive,
-                        kind: ImplKind::Blanket(box trait_ref.self_ty().clean(self.cx)),
-                    }),
-                    cfg: None,
-                });
+                    impls.push(Item {
+                        name: None,
+                        attrs: Default::default(),
+                        visibility: Inherited,
+                        def_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
+                        kind: box ImplItem(Impl {
+                            unsafety: hir::Unsafety::Normal,
+                            generics: clean_ty_generics(
+                                cx,
+                                cx.tcx.generics_of(impl_def_id),
+                                cx.tcx.explicit_predicates_of(impl_def_id),
+                            ),
+                            // FIXME(eddyb) compute both `trait_` and `for_` from
+                            // the post-inference `trait_ref`, as it's more accurate.
+                            trait_: Some(trait_ref.clean(cx)),
+                            for_: ty.clean(cx),
+                            items: cx
+                                .tcx
+                                .associated_items(impl_def_id)
+                                .in_definition_order()
+                                .map(|x| x.clean(cx))
+                                .collect::<Vec<_>>(),
+                            polarity: ty::ImplPolarity::Positive,
+                            kind: ImplKind::Blanket(box trait_ref.self_ty().clean(cx)),
+                        }),
+                        cfg: None,
+                    });
+                }
             }
-        }
+        });
+
         impls
     }
 }
index 5da20953bf2e30e4a8bcc2f9a8eb43d9b796a4f0..a2e612955b3498cecb506dc756b9d2735af0e0e4 100644 (file)
@@ -5,10 +5,10 @@
 
 use rustc_ast as ast;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::thin_vec::ThinVec;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::definitions::DefPathData;
 use rustc_hir::Mutability;
 use rustc_metadata::creader::{CStore, LoadedMacro};
 use rustc_middle::ty::{self, TyCtxt};
 /// These names are used later on by HTML rendering to generate things like
 /// source links back to the original item.
 crate fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemType) {
-    let crate_name = cx.tcx.crate_name(did.krate).to_string();
+    let crate_name = cx.tcx.crate_name(did.krate);
 
-    let relative = cx.tcx.def_path(did).data.into_iter().filter_map(|elem| {
-        // Filter out extern blocks
-        (elem.data != DefPathData::ForeignMod).then(|| elem.data.to_string())
-    });
+    let relative =
+        cx.tcx.def_path(did).data.into_iter().filter_map(|elem| elem.data.get_opt_name());
     let fqn = if let ItemType::Macro = kind {
         // Check to see if it is a macro 2.0 or built-in macro
         if matches!(
@@ -290,6 +288,7 @@ fn build_type_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::Typedef {
     attrs: Option<Attrs<'_>>,
     ret: &mut Vec<clean::Item>,
 ) {
+    let _prof_timer = cx.tcx.sess.prof.generic_activity("build_inherent_impls");
     let tcx = cx.tcx;
 
     // for each implementation of an item represented by `did`, build the clean::Item for that impl
@@ -337,7 +336,7 @@ fn merge_attrs(
         return;
     }
 
-    let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impl");
+    let _prof_timer = cx.tcx.sess.prof.generic_activity("build_impl");
 
     let tcx = cx.tcx;
     let associated_trait = tcx.impl_trait_ref(did);
@@ -515,7 +514,7 @@ fn build_module(
     // If we're re-exporting a re-export it may actually re-export something in
     // two namespaces, so the target may be listed twice. Make sure we only
     // visit each node at most once.
-    for &item in cx.tcx.item_children(did).iter() {
+    for &item in cx.tcx.module_children(did).iter() {
         if item.vis.is_public() {
             let res = item.res.expect_non_local();
             if let Some(def_id) = res.mod_def_id() {
@@ -540,7 +539,7 @@ fn build_module(
                                     name: prim_ty.as_sym(),
                                     args: clean::GenericArgs::AngleBracketed {
                                         args: Vec::new(),
-                                        bindings: Vec::new(),
+                                        bindings: ThinVec::new(),
                                     },
                                 }],
                             },
index 959be5478b4eca852b20fba9b6cf419dbbcefbec..a5bc70a74ae92b4163122d947a03cb21ec61cdce 100644 (file)
@@ -1004,7 +1004,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
 
             let what_rustc_thinks =
                 Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
-            let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_did(self.hir_id()));
+            let parent_item = cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(self.hir_id()));
             if let hir::ItemKind::Impl(impl_) = &parent_item.kind {
                 if impl_.of_trait.is_some() {
                     // Trait impl items always inherit the impl's visibility --
@@ -1350,17 +1350,23 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
             }
             TyKind::Slice(ref ty) => Slice(box ty.clean(cx)),
             TyKind::Array(ref ty, ref length) => {
-                let def_id = cx.tcx.hir().local_def_id(length.hir_id);
-                // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
-                // as we currently do not supply the parent generics to anonymous constants
-                // but do allow `ConstKind::Param`.
-                //
-                // `const_eval_poly` tries to to first substitute generic parameters which
-                // results in an ICE while manually constructing the constant and using `eval`
-                // does nothing for `ConstKind::Param`.
-                let ct = ty::Const::from_anon_const(cx.tcx, def_id);
-                let param_env = cx.tcx.param_env(def_id);
-                let length = print_const(cx, ct.eval(cx.tcx, param_env));
+                let length = match length {
+                    hir::ArrayLen::Infer(_, _) => "_".to_string(),
+                    hir::ArrayLen::Body(anon_const) => {
+                        let def_id = cx.tcx.hir().local_def_id(anon_const.hir_id);
+                        // NOTE(min_const_generics): We can't use `const_eval_poly` for constants
+                        // as we currently do not supply the parent generics to anonymous constants
+                        // but do allow `ConstKind::Param`.
+                        //
+                        // `const_eval_poly` tries to to first substitute generic parameters which
+                        // results in an ICE while manually constructing the constant and using `eval`
+                        // does nothing for `ConstKind::Param`.
+                        let ct = ty::Const::from_anon_const(cx.tcx, def_id);
+                        let param_env = cx.tcx.param_env(def_id);
+                        print_const(cx, ct.eval(cx.tcx, param_env))
+                    }
+                };
+
                 Array(box ty.clean(cx), length)
             }
             TyKind::Tup(tys) => Tuple(tys.iter().map(|x| x.clean(cx)).collect()),
@@ -1612,7 +1618,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
 
 impl Clean<Item> for ty::FieldDef {
     fn clean(&self, cx: &mut DocContext<'_>) -> Item {
-        clean_field(self.did, self.ident.name, cx.tcx.type_of(self.did).clean(cx), cx)
+        clean_field(self.did, self.name, cx.tcx.type_of(self.did).clean(cx), cx)
     }
 }
 
@@ -1683,7 +1689,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Item {
             }),
         };
         let what_rustc_thinks =
-            Item::from_def_id_and_parts(self.def_id, Some(self.ident.name), VariantItem(kind), cx);
+            Item::from_def_id_and_parts(self.def_id, Some(self.name), VariantItem(kind), cx);
         // don't show `pub` for variants, which always inherit visibility
         Item { visibility: Inherited, ..what_rustc_thinks }
     }
index 2b1a1d4a600d64f84ea9a9a03defb2a9140ceee9..00c6e38839f5489623c3568e3bed382459295b3e 100644 (file)
@@ -1,6 +1,5 @@
 use std::cell::RefCell;
 use std::default::Default;
-use std::fmt::Write;
 use std::hash::Hash;
 use std::lazy::SyncOnceCell as OnceCell;
 use std::path::PathBuf;
@@ -265,7 +264,7 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
                 })
                 .collect()
         } else {
-            tcx.item_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
+            tcx.module_children(root).iter().map(|item| item.res).filter_map(as_keyword).collect()
         }
     }
 
@@ -333,7 +332,7 @@ fn to_remote(url: impl ToString) -> ExternalLocation {
                 })
                 .collect()
         } else {
-            tcx.item_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
+            tcx.module_children(root).iter().map(|item| item.res).filter_map(as_primitive).collect()
         }
     }
 }
@@ -496,7 +495,7 @@ pub fn from_def_id_and_attrs_and_parts(
                 if let Ok((mut href, ..)) = href(*did, cx) {
                     debug!(?href);
                     if let Some(ref fragment) = *fragment {
-                        write!(href, "{}", fragment).unwrap()
+                        fragment.render(&mut href, cx.tcx()).unwrap()
                     }
                     Some(RenderedLink {
                         original_text: s.clone(),
@@ -889,20 +888,25 @@ fn single<T: IntoIterator>(it: T) -> Option<T::Item> {
 }
 
 crate trait NestedAttributesExt {
-    /// Returns `true` if the attribute list contains a specific `Word`
-    fn has_word(self, word: Symbol) -> bool;
+    /// Returns `true` if the attribute list contains a specific `word`
+    fn has_word(self, word: Symbol) -> bool
+    where
+        Self: std::marker::Sized,
+    {
+        <Self as NestedAttributesExt>::get_word_attr(self, word).is_some()
+    }
+
+    /// Returns `Some(attr)` if the attribute list contains 'attr'
+    /// corresponding to a specific `word`
     fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>;
 }
 
-impl<I: Iterator<Item = ast::NestedMetaItem> + IntoIterator<Item = ast::NestedMetaItem>>
-    NestedAttributesExt for I
+impl<I> NestedAttributesExt for I
+where
+    I: IntoIterator<Item = ast::NestedMetaItem>,
 {
-    fn has_word(self, word: Symbol) -> bool {
-        self.into_iter().any(|attr| attr.is_word() && attr.has_name(word))
-    }
-
-    fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
-        self.find(|attr| attr.is_word() && attr.has_name(word))
+    fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem> {
+        self.into_iter().find(|attr| attr.is_word() && attr.has_name(word))
     }
 }
 
@@ -1077,9 +1081,6 @@ impl Attributes {
         let mut out = String::new();
         add_doc_fragment(&mut out, ori);
         for new_frag in iter {
-            if new_frag.kind != ori.kind || new_frag.parent_module != ori.parent_module {
-                break;
-            }
             add_doc_fragment(&mut out, new_frag);
         }
         out.pop();
@@ -2060,14 +2061,14 @@ impl Path {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 crate enum GenericArgs {
-    AngleBracketed { args: Vec<GenericArg>, bindings: Vec<TypeBinding> },
+    AngleBracketed { args: Vec<GenericArg>, bindings: ThinVec<TypeBinding> },
     Parenthesized { inputs: Vec<Type>, output: Option<Box<Type>> },
 }
 
 // `GenericArgs` is in every `PathSegment`, so its size can significantly
 // affect rustdoc's memory usage.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(GenericArgs, 56);
+rustc_data_structures::static_assert_size!(GenericArgs, 40);
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 crate struct PathSegment {
@@ -2078,7 +2079,7 @@ impl Path {
 // `PathSegment` usually occurs multiple times in every `Path`, so its size can
 // significantly affect rustdoc's memory usage.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(PathSegment, 64);
+rustc_data_structures::static_assert_size!(PathSegment, 48);
 
 #[derive(Clone, Debug)]
 crate struct Typedef {
index 28bd0f0a405f9306952163f4f44da147e3e3e641..38da9a4635db888d1df7862dff479c193ea4e098 100644 (file)
 
 use rustc_ast as ast;
 use rustc_ast::tokenstream::TokenTree;
+use rustc_data_structures::thin_vec::ThinVec;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
+use rustc_session::parse::ParseSess;
+use rustc_span::source_map::FilePathMapping;
 use rustc_span::symbol::{kw, sym, Symbol};
 use std::fmt::Write as _;
 use std::mem;
@@ -108,7 +111,7 @@ fn external_generic_args(
     if cx.tcx.fn_trait_kind_from_lang_item(did).is_some() {
         let inputs = match ty_kind.unwrap() {
             ty::Tuple(tys) => tys.iter().map(|t| t.expect_ty().clean(cx)).collect(),
-            _ => return GenericArgs::AngleBracketed { args, bindings },
+            _ => return GenericArgs::AngleBracketed { args, bindings: bindings.into() },
         };
         let output = None;
         // FIXME(#20299) return type comes from a projection now
@@ -118,7 +121,7 @@ fn external_generic_args(
         // };
         GenericArgs::Parenthesized { inputs, output }
     } else {
-        GenericArgs::AngleBracketed { args, bindings }
+        GenericArgs::AngleBracketed { args, bindings: bindings.into() }
     }
 }
 
@@ -143,7 +146,7 @@ pub(super) fn external_path(
 /// Remove the generic arguments from a path.
 crate fn strip_path_generics(mut path: Path) -> Path {
     for ps in path.segments.iter_mut() {
-        ps.args = GenericArgs::AngleBracketed { args: vec![], bindings: vec![] }
+        ps.args = GenericArgs::AngleBracketed { args: vec![], bindings: ThinVec::new() }
     }
 
     path
@@ -178,6 +181,7 @@ pub(super) fn external_path(
         };
 
         if let Some(prim) = target.primitive_type() {
+            let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls");
             for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) {
                 inline::build_impl(cx, None, did, None, ret);
             }
@@ -225,7 +229,7 @@ pub(super) fn external_path(
 
 crate fn print_const(cx: &DocContext<'_>, n: &ty::Const<'_>) -> String {
     match n.val {
-        ty::ConstKind::Unevaluated(ty::Unevaluated { def, substs_: _, promoted }) => {
+        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);
                 print_const_expr(cx.tcx, cx.tcx.hir().body_owned_by(hir_id))
@@ -484,20 +488,67 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &ty::Const<'_>) ->
 /// Render a sequence of macro arms in a format suitable for displaying to the user
 /// as part of an item declaration.
 pub(super) fn render_macro_arms<'a>(
+    tcx: TyCtxt<'_>,
     matchers: impl Iterator<Item = &'a TokenTree>,
     arm_delim: &str,
 ) -> String {
     let mut out = String::new();
     for matcher in matchers {
-        writeln!(out, "    {} => {{ ... }}{}", render_macro_matcher(matcher), arm_delim).unwrap();
+        writeln!(out, "    {} => {{ ... }}{}", render_macro_matcher(tcx, matcher), arm_delim)
+            .unwrap();
     }
     out
 }
 
 /// Render a macro matcher in a format suitable for displaying to the user
 /// as part of an item declaration.
-pub(super) fn render_macro_matcher(matcher: &TokenTree) -> String {
-    rustc_ast_pretty::pprust::tt_to_string(matcher)
+pub(super) fn render_macro_matcher(tcx: TyCtxt<'_>, matcher: &TokenTree) -> String {
+    if let Some(snippet) = snippet_equal_to_token(tcx, matcher) {
+        snippet
+    } else {
+        rustc_ast_pretty::pprust::tt_to_string(matcher)
+    }
+}
+
+/// Find the source snippet for this token's Span, reparse it, and return the
+/// snippet if the reparsed TokenTree matches the argument TokenTree.
+fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String> {
+    // Find what rustc thinks is the source snippet.
+    // This may not actually be anything meaningful if this matcher was itself
+    // generated by a macro.
+    let source_map = tcx.sess.source_map();
+    let span = matcher.span();
+    let snippet = source_map.span_to_snippet(span).ok()?;
+
+    // Create a Parser.
+    let sess = ParseSess::new(FilePathMapping::empty());
+    let file_name = source_map.span_to_filename(span);
+    let mut parser =
+        match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) {
+            Ok(parser) => parser,
+            Err(diagnostics) => {
+                for mut diagnostic in diagnostics {
+                    diagnostic.cancel();
+                }
+                return None;
+            }
+        };
+
+    // Reparse a single token tree.
+    let mut reparsed_trees = match parser.parse_all_token_trees() {
+        Ok(reparsed_trees) => reparsed_trees,
+        Err(mut diagnostic) => {
+            diagnostic.cancel();
+            return None;
+        }
+    };
+    if reparsed_trees.len() != 1 {
+        return None;
+    }
+    let reparsed_tree = reparsed_trees.pop().unwrap();
+
+    // Compare against the original tree.
+    if reparsed_tree.eq_unspanned(matcher) { Some(snippet) } else { None }
 }
 
 pub(super) fn display_macro_source(
@@ -512,21 +563,21 @@ pub(super) fn display_macro_source(
     let matchers = tts.chunks(4).map(|arm| &arm[0]);
 
     if def.macro_rules {
-        format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(matchers, ";"))
+        format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx.tcx, matchers, ";"))
     } else {
         if matchers.len() <= 1 {
             format!(
                 "{}macro {}{} {{\n    ...\n}}",
                 vis.to_src_with_space(cx.tcx, def_id),
                 name,
-                matchers.map(render_macro_matcher).collect::<String>(),
+                matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::<String>(),
             )
         } else {
             format!(
                 "{}macro {} {{\n{}}}",
                 vis.to_src_with_space(cx.tcx, def_id),
                 name,
-                render_macro_arms(matchers, ","),
+                render_macro_arms(cx.tcx, matchers, ","),
             )
         }
     }
index d300afa313237dbd14603f55b57a5252e594cd61..959f83a021139e09877a1364864cb1b40028b449 100644 (file)
@@ -257,9 +257,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     /// If present, playground URL to use in the "Run" button added to code samples generated from
     /// standalone Markdown files. If not present, `playground_url` is used.
     crate markdown_playground_url: Option<String>,
-    /// If false, the `select` element to have search filtering by crates on rendered docs
-    /// won't be generated.
-    crate generate_search_filter: bool,
     /// Document items that have lower than `pub` visibility.
     crate document_private: bool,
     /// Document items that have `doc(hidden)`.
@@ -638,7 +635,6 @@ fn println_condition(condition: Condition) {
         let crate_version = matches.opt_str("crate-version");
         let enable_index_page = matches.opt_present("enable-index-page") || index_page.is_some();
         let static_root_path = matches.opt_str("static-root-path");
-        let generate_search_filter = !matches.opt_present("disable-per-crate-search");
         let test_run_directory = matches.opt_str("test-run-directory").map(PathBuf::from);
         let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from);
         let test_builder = matches.opt_str("test-builder").map(PathBuf::from);
@@ -724,7 +720,6 @@ fn println_condition(condition: Condition) {
                 markdown_no_toc,
                 markdown_css,
                 markdown_playground_url,
-                generate_search_filter,
                 document_private,
                 document_hidden,
                 generate_redirect_map,
index 32b66278bf4230f8afe78c843cf104700271d172..22f59d39799c4fbb56353affc95856af16f2ea47 100644 (file)
@@ -1,30 +1,23 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{self, Lrc};
-use rustc_driver::abort_on_err;
 use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::HirId;
-use rustc_hir::{
-    intravisit::{self, NestedVisitorMap, Visitor},
-    Path,
-};
-use rustc_interface::{interface, Queries};
+use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::{HirId, Path};
+use rustc_interface::interface;
 use rustc_middle::hir::map::Map;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_resolve as resolve;
-use rustc_resolve::Namespace::TypeNS;
 use rustc_session::config::{self, CrateType, ErrorOutputType};
 use rustc_session::lint;
 use rustc_session::DiagnosticOutput;
 use rustc_session::Session;
-use rustc_span::def_id::CRATE_DEF_INDEX;
-use rustc_span::source_map;
 use rustc_span::symbol::sym;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{source_map, Span};
 
 use std::cell::RefCell;
 use std::lazy::SyncLazy;
 
 crate use rustc_session::config::{DebuggingOptions, Input, Options};
 
+crate struct ResolverCaches {
+    pub all_traits: Option<Vec<DefId>>,
+    pub all_trait_impls: Option<Vec<DefId>>,
+}
+
 crate struct DocContext<'tcx> {
     crate tcx: TyCtxt<'tcx>,
     /// Name resolver. Used for intra-doc links.
     ///
     /// The `Rc<RefCell<...>>` wrapping is needed because that is what's returned by
-    /// [`Queries::expansion()`].
+    /// [`rustc_interface::Queries::expansion()`].
     // FIXME: see if we can get rid of this RefCell somehow
     crate resolver: Rc<RefCell<interface::BoxedResolver>>,
+    crate resolver_caches: ResolverCaches,
     /// Used for normalization.
     ///
     /// Most of this logic is copied from rustc_lint::late.
@@ -123,6 +122,18 @@ impl<'tcx> DocContext<'tcx> {
             _ => None,
         }
     }
+
+    crate fn with_all_traits(&mut self, f: impl FnOnce(&mut Self, &[DefId])) {
+        let all_traits = self.resolver_caches.all_traits.take();
+        f(self, all_traits.as_ref().expect("`all_traits` are already borrowed"));
+        self.resolver_caches.all_traits = all_traits;
+    }
+
+    crate fn with_all_trait_impls(&mut self, f: impl FnOnce(&mut Self, &[DefId])) {
+        let all_trait_impls = self.resolver_caches.all_trait_impls.take();
+        f(self, all_trait_impls.as_ref().expect("`all_trait_impls` are already borrowed"));
+        self.resolver_caches.all_trait_impls = all_trait_impls;
+    }
 }
 
 /// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
@@ -284,49 +295,10 @@ impl<'tcx> DocContext<'tcx> {
     }
 }
 
-crate fn create_resolver<'a>(
-    externs: config::Externs,
-    queries: &Queries<'a>,
-    sess: &Session,
-) -> Rc<RefCell<interface::BoxedResolver>> {
-    let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
-    let resolver = resolver.clone();
-
-    let resolver = crate::passes::collect_intra_doc_links::load_intra_link_crates(resolver, krate);
-
-    // FIXME: somehow rustdoc is still missing crates even though we loaded all
-    // the known necessary crates. Load them all unconditionally until we find a way to fix this.
-    // DO NOT REMOVE THIS without first testing on the reproducer in
-    // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
-    let extern_names: Vec<String> = externs
-        .iter()
-        .filter(|(_, entry)| entry.add_prelude)
-        .map(|(name, _)| name)
-        .cloned()
-        .collect();
-    resolver.borrow_mut().access(|resolver| {
-        sess.time("load_extern_crates", || {
-            for extern_name in &extern_names {
-                debug!("loading extern crate {}", extern_name);
-                if let Err(()) = resolver
-                    .resolve_str_path_error(
-                        DUMMY_SP,
-                        extern_name,
-                        TypeNS,
-                        LocalDefId { local_def_index: CRATE_DEF_INDEX }.to_def_id(),
-                  ) {
-                    warn!("unable to resolve external crate {} (do you have an unused `--extern` crate?)", extern_name)
-                  }
-            }
-        });
-    });
-
-    resolver
-}
-
 crate fn run_global_ctxt(
     tcx: TyCtxt<'_>,
     resolver: Rc<RefCell<interface::BoxedResolver>>,
+    resolver_caches: ResolverCaches,
     show_coverage: bool,
     render_options: RenderOptions,
     output_format: OutputFormat,
@@ -355,6 +327,14 @@ impl<'tcx> DocContext<'tcx> {
     });
     rustc_passes::stability::check_unused_or_stable_features(tcx);
 
+    let auto_traits = resolver_caches
+        .all_traits
+        .as_ref()
+        .expect("`all_traits` are already borrowed")
+        .iter()
+        .copied()
+        .filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id))
+        .collect();
     let access_levels = AccessLevels {
         map: tcx.privacy_access_levels(()).map.iter().map(|(k, v)| (k.to_def_id(), *v)).collect(),
     };
@@ -362,16 +342,14 @@ impl<'tcx> DocContext<'tcx> {
     let mut ctxt = DocContext {
         tcx,
         resolver,
+        resolver_caches,
         param_env: ParamEnv::empty(),
         external_traits: Default::default(),
         active_extern_traits: Default::default(),
         substs: Default::default(),
         impl_trait_bounds: Default::default(),
         generated_synthetics: Default::default(),
-        auto_traits: tcx
-            .all_traits()
-            .filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id))
-            .collect(),
+        auto_traits,
         module_trait_cache: FxHashMap::default(),
         cache: Cache::new(access_levels, render_options.document_private),
         inlined: FxHashSet::default(),
index 6b9ccd37cfb371196476b7c65fb1738541202d33..a8fef4a317802c7fd39ca71513d559977c69ed94 100644 (file)
@@ -4,13 +4,14 @@
 use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX};
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::sym;
+use rustc_span::{sym, Symbol};
 
 use crate::clean::{self, types::ExternalLocation, ExternalCrate, ItemId, PrimitiveType};
 use crate::core::DocContext;
 use crate::fold::DocFolder;
 use crate::formats::item_type::ItemType;
 use crate::formats::Impl;
+use crate::html::format::join_with_double_colon;
 use crate::html::markdown::short_markdown_summary;
 use crate::html::render::search_index::get_function_type_for_search;
 use crate::html::render::IndexItem;
     /// URLs when a type is being linked to. External paths are not located in
     /// this map because the `External` type itself has all the information
     /// necessary.
-    crate paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
+    crate paths: FxHashMap<DefId, (Vec<Symbol>, ItemType)>,
 
     /// Similar to `paths`, but only holds external paths. This is only used for
     /// generating explicit hyperlinks to other crates.
-    crate external_paths: FxHashMap<DefId, (Vec<String>, ItemType)>,
+    crate external_paths: FxHashMap<DefId, (Vec<Symbol>, ItemType)>,
 
     /// Maps local `DefId`s of exported types to fully qualified paths.
     /// Unlike 'paths', this mapping ignores any renames that occur
@@ -55,7 +56,7 @@
     /// to the path used if the corresponding type is inlined. By
     /// doing this, we can detect duplicate impls on a trait page, and only display
     /// the impl for the inlined type.
-    crate exact_paths: FxHashMap<DefId, Vec<String>>,
+    crate exact_paths: FxHashMap<DefId, Vec<Symbol>>,
 
     /// This map contains information about all known traits of this crate.
     /// Implementations of a crate should inherit the documentation of the
@@ -92,7 +93,7 @@
     crate masked_crates: FxHashSet<CrateNum>,
 
     // Private fields only used when initially crawling a crate to build a cache
-    stack: Vec<String>,
+    stack: Vec<Symbol>,
     parent_stack: Vec<DefId>,
     parent_is_trait_impl: bool,
     stripped_mod: bool,
@@ -155,7 +156,7 @@ impl Cache {
             let dst = &render_options.output;
             let location = e.location(extern_url, extern_url_takes_precedence, dst, tcx);
             cx.cache.extern_locations.insert(e.crate_num, location);
-            cx.cache.external_paths.insert(e.def_id(), (vec![name.to_string()], ItemType::Module));
+            cx.cache.external_paths.insert(e.def_id(), (vec![name], ItemType::Module));
         }
 
         // FIXME: avoid this clone (requires implementing Default manually)
@@ -164,10 +165,9 @@ impl Cache {
             let crate_name = tcx.crate_name(def_id.krate);
             // Recall that we only allow primitive modules to be at the root-level of the crate.
             // If that restriction is ever lifted, this will have to include the relative paths instead.
-            cx.cache.external_paths.insert(
-                def_id,
-                (vec![crate_name.to_string(), prim.as_sym().to_string()], ItemType::Primitive),
-            );
+            cx.cache
+                .external_paths
+                .insert(def_id, (vec![crate_name, prim.as_sym()], ItemType::Primitive));
         }
 
         krate = CacheBuilder { tcx, cache: &mut cx.cache }.fold_crate(krate);
@@ -299,7 +299,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
                         self.cache.search_index.push(IndexItem {
                             ty: item.type_(),
                             name: s.to_string(),
-                            path: path.join("::"),
+                            path: join_with_double_colon(path),
                             desc,
                             parent,
                             parent_idx: None,
@@ -320,7 +320,7 @@ fn fold_item(&mut self, item: clean::Item) -> Option<clean::Item> {
         // Keep track of the fully qualified path for this item.
         let pushed = match item.name {
             Some(n) if !n.is_empty() => {
-                self.cache.stack.push(n.to_string());
+                self.cache.stack.push(n);
                 true
             }
             _ => false,
index 981eb9589e9f1cb8ac7db8d96bca71911db5d811..8571a6a137f5101687d769642177c6a60df46c59 100644 (file)
@@ -19,6 +19,7 @@
 use rustc_middle::ty::DefIdTree;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::CRATE_DEF_INDEX;
+use rustc_span::{sym, Symbol};
 use rustc_target::spec::abi::Abi;
 
 use crate::clean::{
@@ -29,6 +30,7 @@
 use crate::html::escape::Escape;
 use crate::html::render::Context;
 
+use super::url_parts_builder::estimate_item_path_byte_length;
 use super::url_parts_builder::UrlPartsBuilder;
 
 crate trait Print {
@@ -502,11 +504,22 @@ fn print<'a, 'tcx: 'a>(
     NotInExternalCache,
 }
 
+// Panics if `syms` is empty.
+crate fn join_with_double_colon(syms: &[Symbol]) -> String {
+    let mut s = String::with_capacity(estimate_item_path_byte_length(syms.len()));
+    s.push_str(&syms[0].as_str());
+    for sym in &syms[1..] {
+        s.push_str("::");
+        s.push_str(&sym.as_str());
+    }
+    s
+}
+
 crate fn href_with_root_path(
     did: DefId,
     cx: &Context<'_>,
     root_path: Option<&str>,
-) -> Result<(String, ItemType, Vec<String>), HrefError> {
+) -> Result<(String, ItemType, Vec<Symbol>), HrefError> {
     let tcx = cx.tcx();
     let def_kind = tcx.def_kind(did);
     let did = match def_kind {
@@ -518,7 +531,7 @@ fn print<'a, 'tcx: 'a>(
     };
     let cache = cx.cache();
     let relative_to = &cx.current;
-    fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
+    fn to_module_fqp(shortty: ItemType, fqp: &[Symbol]) -> &[Symbol] {
         if shortty == ItemType::Module { fqp } else { &fqp[..fqp.len() - 1] }
     }
 
@@ -533,9 +546,9 @@ fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
     let mut is_remote = false;
     let (fqp, shortty, mut url_parts) = match cache.paths.get(&did) {
         Some(&(ref fqp, shortty)) => (fqp, shortty, {
-            let module_fqp = to_module_fqp(shortty, fqp);
+            let module_fqp = to_module_fqp(shortty, fqp.as_slice());
             debug!(?fqp, ?shortty, ?module_fqp);
-            href_relative_parts(module_fqp, relative_to)
+            href_relative_parts(module_fqp, relative_to).collect()
         }),
         None => {
             if let Some(&(ref fqp, shortty)) = cache.external_paths.get(&did) {
@@ -548,10 +561,12 @@ fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
                             is_remote = true;
                             let s = s.trim_end_matches('/');
                             let mut builder = UrlPartsBuilder::singleton(s);
-                            builder.extend(module_fqp.iter().map(String::as_str));
+                            builder.extend(module_fqp.iter().copied());
                             builder
                         }
-                        ExternalLocation::Local => href_relative_parts(module_fqp, relative_to),
+                        ExternalLocation::Local => {
+                            href_relative_parts(module_fqp, relative_to).collect()
+                        }
                         ExternalLocation::Unknown => return Err(HrefError::DocumentationNotBuilt),
                     },
                 )
@@ -567,45 +582,50 @@ fn to_module_fqp(shortty: ItemType, fqp: &[String]) -> &[String] {
         }
     }
     debug!(?url_parts);
-    let last = &fqp.last().unwrap()[..];
     match shortty {
         ItemType::Module => {
             url_parts.push("index.html");
         }
         _ => {
-            let filename = format!("{}.{}.html", shortty.as_str(), last);
-            url_parts.push(&filename);
+            let prefix = shortty.as_str();
+            let last = fqp.last().unwrap();
+            url_parts.push_fmt(format_args!("{}.{}.html", prefix, last));
         }
     }
     Ok((url_parts.finish(), shortty, fqp.to_vec()))
 }
 
-crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<String>), HrefError> {
+crate fn href(did: DefId, cx: &Context<'_>) -> Result<(String, ItemType, Vec<Symbol>), HrefError> {
     href_with_root_path(did, cx, None)
 }
 
 /// Both paths should only be modules.
 /// This is because modules get their own directories; that is, `std::vec` and `std::vec::Vec` will
 /// both need `../iter/trait.Iterator.html` to get at the iterator trait.
-crate fn href_relative_parts(fqp: &[String], relative_to_fqp: &[String]) -> UrlPartsBuilder {
+crate fn href_relative_parts<'fqp>(
+    fqp: &'fqp [Symbol],
+    relative_to_fqp: &[Symbol],
+) -> Box<dyn Iterator<Item = Symbol> + 'fqp> {
     for (i, (f, r)) in fqp.iter().zip(relative_to_fqp.iter()).enumerate() {
         // e.g. linking to std::iter from std::vec (`dissimilar_part_count` will be 1)
         if f != r {
             let dissimilar_part_count = relative_to_fqp.len() - i;
-            let fqp_module = fqp[i..fqp.len()].iter().map(String::as_str);
-            return iter::repeat("..").take(dissimilar_part_count).chain(fqp_module).collect();
+            let fqp_module = &fqp[i..fqp.len()];
+            return box iter::repeat(sym::dotdot)
+                .take(dissimilar_part_count)
+                .chain(fqp_module.iter().copied());
         }
     }
     // e.g. linking to std::sync::atomic from std::sync
     if relative_to_fqp.len() < fqp.len() {
-        fqp[relative_to_fqp.len()..fqp.len()].iter().map(String::as_str).collect()
+        box fqp[relative_to_fqp.len()..fqp.len()].iter().copied()
     // e.g. linking to std::sync from std::sync::atomic
     } else if fqp.len() < relative_to_fqp.len() {
         let dissimilar_part_count = relative_to_fqp.len() - fqp.len();
-        iter::repeat("..").take(dissimilar_part_count).collect()
+        box iter::repeat(sym::dotdot).take(dissimilar_part_count)
     // linking to the same module
     } else {
-        UrlPartsBuilder::new()
+        box iter::empty()
     }
 }
 
@@ -632,14 +652,14 @@ fn resolved_path<'cx>(
             if let Ok((_, _, fqp)) = href(did, cx) {
                 format!(
                     "{}::{}",
-                    fqp[..fqp.len() - 1].join("::"),
-                    anchor(did, fqp.last().unwrap(), cx)
+                    join_with_double_colon(&fqp[..fqp.len() - 1]),
+                    anchor(did, *fqp.last().unwrap(), cx)
                 )
             } else {
                 last.name.to_string()
             }
         } else {
-            anchor(did, last.name.as_str(), cx).to_string()
+            anchor(did, last.name, cx).to_string()
         };
         write!(w, "{}{}", path, last.args.print(cx))?;
     }
@@ -668,30 +688,31 @@ fn primitive_link(
                 needs_termination = true;
             }
             Some(&def_id) => {
-                let cname_sym;
                 let loc = match m.extern_locations[&def_id.krate] {
                     ExternalLocation::Remote(ref s) => {
-                        cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx());
-                        Some(vec![s.trim_end_matches('/'), cname_sym.as_str()])
+                        let cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx());
+                        let builder: UrlPartsBuilder =
+                            [s.as_str().trim_end_matches('/'), cname_sym.as_str()]
+                                .into_iter()
+                                .collect();
+                        Some(builder)
                     }
                     ExternalLocation::Local => {
-                        cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx());
-                        Some(if cx.current.first().map(|x| &x[..]) == Some(cname_sym.as_str()) {
-                            iter::repeat("..").take(cx.current.len() - 1).collect()
+                        let cname_sym = ExternalCrate { crate_num: def_id.krate }.name(cx.tcx());
+                        Some(if cx.current.first() == Some(&cname_sym) {
+                            iter::repeat(sym::dotdot).take(cx.current.len() - 1).collect()
                         } else {
-                            let cname = iter::once(cname_sym.as_str());
-                            iter::repeat("..").take(cx.current.len()).chain(cname).collect()
+                            iter::repeat(sym::dotdot)
+                                .take(cx.current.len())
+                                .chain(iter::once(cname_sym))
+                                .collect()
                         })
                     }
                     ExternalLocation::Unknown => None,
                 };
-                if let Some(loc) = loc {
-                    write!(
-                        f,
-                        "<a class=\"primitive\" href=\"{}/primitive.{}.html\">",
-                        loc.join("/"),
-                        prim.as_sym()
-                    )?;
+                if let Some(mut loc) = loc {
+                    loc.push_fmt(format_args!("primitive.{}.html", prim.as_sym()));
+                    write!(f, "<a class=\"primitive\" href=\"{}\">", loc.finish())?;
                     needs_termination = true;
                 }
             }
@@ -730,7 +751,7 @@ fn tybounds<'a, 'tcx: 'a>(
 
 crate fn anchor<'a, 'cx: 'a>(
     did: DefId,
-    text: &'a str,
+    text: Symbol,
     cx: &'cx Context<'_>,
 ) -> impl fmt::Display + 'a {
     let parts = href(did, cx);
@@ -742,8 +763,8 @@ fn tybounds<'a, 'tcx: 'a>(
                 short_ty,
                 url,
                 short_ty,
-                fqp.join("::"),
-                text
+                join_with_double_colon(&fqp),
+                text.as_str()
             )
         } else {
             write!(f, "{}", text)
@@ -960,7 +981,7 @@ fn fmt_type<'cx>(
                         url = url,
                         shortty = ItemType::AssocType,
                         name = name,
-                        path = path.join("::")
+                        path = join_with_double_colon(path),
                     )?;
                 }
                 _ => write!(f, "{}", name)?,
@@ -1270,7 +1291,7 @@ impl clean::Visibility {
                     debug!("path={:?}", path);
                     // modified from `resolved_path()` to work with `DefPathData`
                     let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
-                    let anchor = anchor(vis_did, last_name.as_str(), cx).to_string();
+                    let anchor = anchor(vis_did, last_name, cx).to_string();
 
                     let mut s = "pub(in ".to_owned();
                     for seg in &path.data[..path.data.len() - 1] {
index 3d3fa3aaeaa519f803fac82b7377d1fb6fa030d5..4ca71ea8684b29e62e16dea28d1985007eb2f126 100644 (file)
@@ -7,9 +7,9 @@
 use crate::html::format::{Buffer, Print};
 use crate::html::render::{ensure_trailing_slash, StylePath};
 
-use serde::Serialize;
+use askama::Template;
 
-#[derive(Clone, Serialize)]
+#[derive(Clone)]
 crate struct Layout {
     crate logo: String,
     crate favicon: String,
     /// The given user css file which allow to customize the generated
     /// documentation theme.
     crate css_file_extension: Option<PathBuf>,
-    /// If false, the `select` element to have search filtering by crates on rendered docs
-    /// won't be generated.
-    crate generate_search_filter: bool,
     /// If true, then scrape-examples.js will be included in the output HTML file
     crate scrape_examples_extension: bool,
 }
 
-#[derive(Serialize)]
 crate struct Page<'a> {
     crate title: &'a str,
     crate css_class: &'a str,
@@ -45,7 +41,8 @@ impl<'a> Page<'a> {
     }
 }
 
-#[derive(Serialize)]
+#[derive(Template)]
+#[template(path = "page.html")]
 struct PageLayout<'a> {
     static_root_path: &'a str,
     page: &'a Page<'a>,
@@ -58,7 +55,6 @@ struct PageLayout<'a> {
 }
 
 crate fn render<T: Print, S: Print>(
-    templates: &tera::Tera,
     layout: &Layout,
     page: &Page<'_>,
     sidebar: S,
@@ -76,7 +72,7 @@ struct PageLayout<'a> {
     let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version");
     let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
     let sidebar = Buffer::html().to_display(sidebar);
-    let teractx = tera::Context::from_serialize(PageLayout {
+    PageLayout {
         static_root_path,
         page,
         layout,
@@ -85,9 +81,9 @@ struct PageLayout<'a> {
         content,
         krate_with_trailing_slash,
         rustdoc_version,
-    })
-    .unwrap();
-    templates.render("page.html", &teractx).unwrap()
+    }
+    .render()
+    .unwrap()
 }
 
 crate fn redirect(url: &str) -> String {
index 534a542d58ed0b596e5ffe754128715b5ea80fb9..865e14f694dccbcc752b7adfc19547e93a93b1d3 100644 (file)
 use rustc_session::Session;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::FileName;
-use rustc_span::symbol::sym;
+use rustc_span::{sym, Symbol};
 
 use super::print_item::{full_path, item_path, print_item};
 use super::search_index::build_index;
-use super::templates;
 use super::write_shared::write_shared;
 use super::{
     collect_spans_and_sources, print_sidebar, settings, AllTypes, LinkFromSrc, NameDoc, StylePath,
@@ -30,7 +29,7 @@
 use crate::formats::item_type::ItemType;
 use crate::formats::FormatRenderer;
 use crate::html::escape::Escape;
-use crate::html::format::Buffer;
+use crate::html::format::{join_with_double_colon, Buffer};
 use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
 use crate::html::{layout, sources};
 use crate::scrape_examples::AllCallLocations;
@@ -46,7 +45,7 @@
 crate struct Context<'tcx> {
     /// Current hierarchy of components leading down to what's currently being
     /// rendered
-    pub(crate) current: Vec<String>,
+    pub(crate) current: Vec<Symbol>,
     /// The current destination folder of where HTML artifacts should be placed.
     /// This changes as the context descends into the module hierarchy.
     crate dst: PathBuf,
@@ -65,7 +64,7 @@
     ///
     /// [#82381]: https://github.com/rust-lang/rust/issues/82381
     crate shared: Rc<SharedContext<'tcx>>,
-    /// This flag indicates whether `[src]` links should be generated or not. If
+    /// This flag indicates whether source links should be generated or not. If
     /// the source files are present in the html rendering, then this will be
     /// `true`.
     crate include_sources: bool,
     /// the crate.
     redirections: Option<RefCell<FxHashMap<String, String>>>,
 
-    pub(crate) templates: tera::Tera,
-
     /// Correspondance map used to link types used in the source code pages to allow to click on
     /// links to jump to the type's definition.
     crate span_correspondance_map: FxHashMap<rustc_span::Span, LinkFromSrc>,
@@ -179,7 +176,7 @@ fn render_item(&self, it: &clean::Item, is_module: bool) -> String {
                 title.push_str(" in ");
             }
             // No need to include the namespace for primitive types and keywords
-            title.push_str(&self.current.join("::"));
+            title.push_str(&join_with_double_colon(&self.current));
         };
         title.push_str(" - Rust");
         let tyname = it.type_();
@@ -218,29 +215,28 @@ fn render_item(&self, it: &clean::Item, is_module: bool) -> String {
 
         if !self.render_redirect_pages {
             layout::render(
-                &self.shared.templates,
                 &self.shared.layout,
                 &page,
                 |buf: &mut _| print_sidebar(self, it, buf),
-                |buf: &mut _| print_item(self, &self.shared.templates, it, buf, &page),
+                |buf: &mut _| print_item(self, it, buf, &page),
                 &self.shared.style_files,
             )
         } else {
             if let Some(&(ref names, ty)) = self.cache().paths.get(&it.def_id.expect_def_id()) {
                 let mut path = String::new();
                 for name in &names[..names.len() - 1] {
-                    path.push_str(name);
+                    path.push_str(&name.as_str());
                     path.push('/');
                 }
-                path.push_str(&item_path(ty, names.last().unwrap()));
+                path.push_str(&item_path(ty, &names.last().unwrap().as_str()));
                 match self.shared.redirections {
                     Some(ref redirections) => {
                         let mut current_path = String::new();
                         for name in &self.current {
-                            current_path.push_str(name);
+                            current_path.push_str(&name.as_str());
                             current_path.push('/');
                         }
-                        current_path.push_str(&item_path(ty, names.last().unwrap()));
+                        current_path.push_str(&item_path(ty, &names.last().unwrap().as_str()));
                         redirections.borrow_mut().insert(current_path, path);
                     }
                     None => return layout::redirect(&format!("{}{}", self.root_path(), path)),
@@ -391,7 +387,6 @@ fn init(
             extension_css,
             resource_suffix,
             static_root_path,
-            generate_search_filter,
             unstable_features,
             generate_redirect_map,
             show_type_layout,
@@ -421,12 +416,10 @@ fn init(
             default_settings,
             krate: krate.name(tcx).to_string(),
             css_file_extension: extension_css,
-            generate_search_filter,
             scrape_examples_extension: !call_locations.is_empty(),
         };
         let mut issue_tracker_base_url = None;
         let mut include_sources = true;
-        let templates = templates::load()?;
 
         // Crawl the crate attributes looking for attributes which control how we're
         // going to emit HTML
@@ -481,7 +474,6 @@ fn init(
             errors: receiver,
             redirections: if generate_redirect_map { Some(Default::default()) } else { None },
             show_type_layout,
-            templates,
             span_correspondance_map: matches,
             cache,
             call_locations,
@@ -577,7 +569,6 @@ fn after_krate(&mut self) -> Result<(), Error> {
         };
         let all = self.shared.all.replace(AllTypes::new());
         let v = layout::render(
-            &self.shared.templates,
             &self.shared.layout,
             &page,
             sidebar,
@@ -599,7 +590,6 @@ fn after_krate(&mut self) -> Result<(), Error> {
             .map(StylePath::basename)
             .collect::<Result<_, Error>>()?;
         let v = layout::render(
-            &self.shared.templates,
             &self.shared.layout,
             &page,
             sidebar,
@@ -644,8 +634,8 @@ fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error> {
             self.render_redirect_pages = item.is_stripped();
         }
         let scx = &self.shared;
-        let item_name = item.name.as_ref().unwrap().to_string();
-        self.dst.push(&item_name);
+        let item_name = item.name.unwrap();
+        self.dst.push(&*item_name.as_str());
         self.current.push(item_name);
 
         info!("Recursing into {}", self.dst.display());
@@ -665,7 +655,7 @@ fn mod_item_in(&mut self, item: &clean::Item) -> Result<(), Error> {
                 _ => unreachable!(),
             };
             let items = self.build_sidebar_items(module);
-            let js_dst = self.dst.join("sidebar-items.js");
+            let js_dst = self.dst.join(&format!("sidebar-items{}.js", self.shared.resource_suffix));
             let v = format!("initSidebarItems({});", serde_json::to_string(&items).unwrap());
             scx.fs.write(js_dst, v)?;
         }
index 16334890da674ed6b6c947988269ce4d14181cfa..f0cbe79bd065e96058b153b75a5ae4699b8ec071 100644 (file)
@@ -31,7 +31,6 @@
 mod context;
 mod print_item;
 mod span_map;
-mod templates;
 mod write_shared;
 
 crate use self::context::*;
@@ -70,8 +69,9 @@
 use crate::formats::{AssocItemRender, Impl, RenderMode};
 use crate::html::escape::Escape;
 use crate::html::format::{
-    href, print_abi_with_space, print_constness_with_space, print_default_space,
-    print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace,
+    href, join_with_double_colon, print_abi_with_space, print_constness_with_space,
+    print_default_space, print_generic_bounds, print_where_clause, Buffer, HrefError,
+    PrintWithSpace,
 };
 use crate::html::highlight;
 use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
@@ -182,7 +182,7 @@ pub fn basename(&self) -> Result<String, Error> {
 
 fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
     if let Some(l) = cx.src_href(item) {
-        write!(buf, "<a class=\"srclink\" href=\"{}\" title=\"goto source code\">[src]</a>", l)
+        write!(buf, "<a class=\"srclink\" href=\"{}\" title=\"goto source code\">source</a>", l)
     }
 }
 
@@ -312,14 +312,6 @@ fn print_entries(f: &mut Buffer, e: &FxHashSet<ItemEntry>, title: &str, class: &
         f.write_str(
             "<h1 class=\"fqn\">\
                  <span class=\"in-band\">List of all items</span>\
-                 <span class=\"out-of-band\">\
-                     <span id=\"render-detail\">\
-                         <a id=\"toggle-all-docs\" href=\"javascript:void(0)\" \
-                            title=\"collapse all docs\">\
-                             [<span class=\"inner\">&#x2212;</span>]\
-                         </a>\
-                     </span>
-                 </span>
              </h1>",
         );
         // Note: print_entries does not escape the title, because we know the current set of titles
@@ -807,7 +799,7 @@ fn render_stability_since_raw(
     const_stability: Option<ConstStability>,
     containing_ver: Option<Symbol>,
     containing_const_ver: Option<Symbol>,
-) {
+) -> bool {
     let ver = ver.filter(|inner| !inner.is_empty());
 
     match (ver, const_stability) {
@@ -850,8 +842,9 @@ fn render_stability_since_raw(
                 v
             );
         }
-        _ => {}
+        _ => return false,
     }
+    true
 }
 
 fn render_assoc_item(
@@ -1198,11 +1191,9 @@ fn render_deref_methods(
             }
         }
         render_assoc_items_inner(w, cx, container_item, did, what, derefs);
-    } else {
-        if let Some(prim) = target.primitive_type() {
-            if let Some(&did) = cache.primitive_locations.get(&prim) {
-                render_assoc_items_inner(w, cx, container_item, did, what, derefs);
-            }
+    } else if let Some(prim) = target.primitive_type() {
+        if let Some(&did) = cache.primitive_locations.get(&prim) {
+            render_assoc_items_inner(w, cx, container_item, did, what, derefs);
         }
     }
 }
@@ -1640,7 +1631,7 @@ fn render_default_items(
 }
 
 // Render the items that appear on the right side of methods, impls, and
-// associated types. For example "1.0.0 (const: 1.39.0) [src]".
+// associated types. For example "1.0.0 (const: 1.39.0) · source".
 fn render_rightside(
     w: &mut Buffer,
     cx: &Context<'_>,
@@ -1658,13 +1649,16 @@ fn render_rightside(
     };
 
     write!(w, "<div class=\"rightside\">");
-    render_stability_since_raw(
+    let has_stability = render_stability_since_raw(
         w,
         item.stable_since(tcx),
         const_stability,
         containing_item.stable_since(tcx),
         const_stable_since,
     );
+    if has_stability {
+        w.write_str(" · ");
+    }
 
     write_srclink(cx, item, w);
     w.write_str("</div>");
@@ -1831,7 +1825,11 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
         ty = it.type_(),
         path = relpath
     );
-    write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath);
+    write!(
+        buffer,
+        "<script defer src=\"{}sidebar-items{}.js\"></script>",
+        relpath, cx.shared.resource_suffix
+    );
     // Closes sidebar-elems div.
     buffer.write_str("</div>");
 }
@@ -2516,7 +2514,7 @@ fn collect_paths_for_type(first_ty: clean::Type, cache: &Cache) -> Vec<String> {
         let fqp = cache.exact_paths.get(&did).cloned().or_else(get_extern);
 
         if let Some(path) = fqp {
-            out.push(path.join("::"));
+            out.push(join_with_double_colon(&path));
         }
     };
 
index 44a9ec5ea42108000788e2d382a36dfab9161ada..67821f19a23f6a7093f3dcac12ba5f6d4c1513e7 100644 (file)
 use crate::formats::{AssocItemRender, Impl, RenderMode};
 use crate::html::escape::Escape;
 use crate::html::format::{
-    print_abi_with_space, print_constness_with_space, print_where_clause, Buffer, PrintWithSpace,
+    join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause,
+    Buffer, PrintWithSpace,
 };
 use crate::html::highlight;
 use crate::html::layout::Page;
 use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
+use crate::html::url_parts_builder::UrlPartsBuilder;
 
-use serde::Serialize;
+use askama::Template;
 
 const ITEM_TABLE_OPEN: &str = "<div class=\"item-table\">";
 const ITEM_TABLE_CLOSE: &str = "</div>";
 const ITEM_TABLE_ROW_CLOSE: &str = "</div>";
 
 // A component in a `use` path, like `string` in std::string::ToString
-#[derive(Serialize)]
-struct PathComponent<'a> {
+struct PathComponent {
     path: String,
-    name: &'a str,
+    name: Symbol,
 }
 
-#[derive(Serialize)]
+#[derive(Template)]
+#[template(path = "print_item.html")]
 struct ItemVars<'a> {
     page: &'a Page<'a>,
     static_root_path: &'a str,
     typ: &'a str,
     name: &'a str,
     item_type: &'a str,
-    path_components: Vec<PathComponent<'a>>,
+    path_components: Vec<PathComponent>,
     stability_since_raw: &'a str,
     src_href: Option<&'a str>,
 }
 
-pub(super) fn print_item(
-    cx: &Context<'_>,
-    templates: &tera::Tera,
-    item: &clean::Item,
-    buf: &mut Buffer,
-    page: &Page<'_>,
-) {
+pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, page: &Page<'_>) {
     debug_assert!(!item.is_stripped());
     let typ = match *item.kind {
         clean::ModuleItem(_) => {
@@ -108,10 +104,10 @@ pub(super) fn print_item(
     );
     let stability_since_raw: String = stability_since_raw.into_inner();
 
-    // Write `src` tag
+    // Write source tag
     //
     // When this item is part of a `crate use` in a downstream crate, the
-    // [src] link in the downstream documentation will actually come back to
+    // source link in the downstream documentation will actually come back to
     // this page, and this link will be auto-clicked. The `id` attribute is
     // used to find the link to auto-click.
     let src_href =
@@ -127,24 +123,23 @@ pub(super) fn print_item(
             .take(amt)
             .map(|(i, component)| PathComponent {
                 path: "../".repeat(cur.len() - i - 1),
-                name: component,
+                name: *component,
             })
             .collect()
     };
 
     let item_vars = ItemVars {
-        page: page,
+        page,
         static_root_path: page.get_static_root_path(),
-        typ: typ,
+        typ,
         name: item.name.as_ref().unwrap().as_str(),
         item_type: &item.type_().to_string(),
-        path_components: path_components,
+        path_components,
         stability_since_raw: &stability_since_raw,
         src_href: src_href.as_deref(),
     };
 
-    let teractx = tera::Context::from_serialize(item_vars).unwrap();
-    let heading = templates.render("print_item.html", &teractx).unwrap();
+    let heading = item_vars.render().unwrap();
     buf.write_str(&heading);
 
     match *item.kind {
@@ -269,7 +264,7 @@ fn cmp(
     indices.dedup_by_key(|i| {
         (
             items[*i].def_id,
-            if items[*i].name.as_ref().is_some() { Some(full_path(cx, &items[*i])) } else { None },
+            if items[*i].name.is_some() { Some(full_path(cx, &items[*i])) } else { None },
             items[*i].type_(),
             if items[*i].is_import() { *i } else { 0 },
         )
@@ -311,22 +306,18 @@ fn cmp(
 
                 w.write_str(ITEM_TABLE_ROW_OPEN);
                 match *src {
-                    Some(ref src) => write!(
+                    Some(src) => write!(
                         w,
                         "<div class=\"item-left\"><code>{}extern crate {} as {};",
                         myitem.visibility.print_with_space(myitem.def_id, cx),
-                        anchor(myitem.def_id.expect_def_id(), src.as_str(), cx),
-                        myitem.name.as_ref().unwrap(),
+                        anchor(myitem.def_id.expect_def_id(), src, cx),
+                        myitem.name.unwrap(),
                     ),
                     None => write!(
                         w,
                         "<div class=\"item-left\"><code>{}extern crate {};",
                         myitem.visibility.print_with_space(myitem.def_id, cx),
-                        anchor(
-                            myitem.def_id.expect_def_id(),
-                            myitem.name.as_ref().unwrap().as_str(),
-                            cx
-                        ),
+                        anchor(myitem.def_id.expect_def_id(), myitem.name.unwrap(), cx),
                     ),
                 }
                 w.write_str("</code></div>");
@@ -398,7 +389,7 @@ fn cmp(
                              {stab_tags}\
                      </div>\
                      <div class=\"item-right docblock-short\">{docs}</div>",
-                    name = *myitem.name.as_ref().unwrap(),
+                    name = myitem.name.unwrap(),
                     stab_tags = extra_info_tags(myitem, item, cx.tcx()),
                     docs = MarkdownSummaryLine(&doc_value, &myitem.links(cx)).into_string(),
                     class = myitem.type_(),
@@ -470,7 +461,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
     let asyncness = f.header.asyncness.print_with_space();
     let unsafety = f.header.unsafety.print_with_space();
     let abi = print_abi_with_space(f.header.abi).to_string();
-    let name = it.name.as_ref().unwrap();
+    let name = it.name.unwrap();
 
     let generics_len = format!("{:#}", f.generics.print(cx)).len();
     let header_len = "fn ".len()
@@ -526,7 +517,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
                 it.visibility.print_with_space(it.def_id, cx),
                 t.unsafety.print_with_space(),
                 if t.is_auto { "auto " } else { "" },
-                it.name.as_ref().unwrap(),
+                it.name.unwrap(),
                 t.generics.print(cx),
                 bounds
             );
@@ -667,7 +658,7 @@ fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_conte
     }
 
     fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item) {
-        let name = m.name.as_ref().unwrap();
+        let name = m.name.unwrap();
         info!("Documenting {} on {:?}", name, t.name);
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
@@ -864,20 +855,21 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
         }
     }
 
+    let mut js_src_path: UrlPartsBuilder = std::iter::repeat("..")
+        .take(cx.current.len())
+        .chain(std::iter::once("implementors"))
+        .collect();
+    if it.def_id.is_local() {
+        js_src_path.extend(cx.current.iter().copied());
+    } else {
+        let (ref path, _) = cache.external_paths[&it.def_id.expect_def_id()];
+        js_src_path.extend(path[..path.len() - 1].iter().copied());
+    }
+    js_src_path.push_fmt(format_args!("{}.{}.js", it.type_(), it.name.unwrap()));
     write!(
         w,
-        "<script type=\"text/javascript\" \
-                 src=\"{root_path}/implementors/{path}/{ty}.{name}.js\" async>\
-         </script>",
-        root_path = vec![".."; cx.current.len()].join("/"),
-        path = if it.def_id.is_local() {
-            cx.current.join("/")
-        } else {
-            let (ref path, _) = cache.external_paths[&it.def_id.expect_def_id()];
-            path[..path.len() - 1].join("/")
-        },
-        ty = it.type_(),
-        name = *it.name.as_ref().unwrap()
+        "<script type=\"text/javascript\" src=\"{src}\" async></script>",
+        src = js_src_path.finish(),
     );
 }
 
@@ -888,7 +880,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
             write!(
                 w,
                 "trait {}{}{} = {};",
-                it.name.as_ref().unwrap(),
+                it.name.unwrap(),
                 t.generics.print(cx),
                 print_where_clause(&t.generics, cx, 0, true),
                 bounds(&t.bounds, true, cx)
@@ -912,7 +904,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:
             write!(
                 w,
                 "type {}{}{where_clause} = impl {bounds};",
-                it.name.as_ref().unwrap(),
+                it.name.unwrap(),
                 t.generics.print(cx),
                 where_clause = print_where_clause(&t.generics, cx, 0, true),
                 bounds = bounds(&t.bounds, false, cx),
@@ -951,7 +943,7 @@ fn write_content(
             write!(
                 w,
                 "type {}{}{where_clause} = {type_};",
-                it.name.as_ref().unwrap(),
+                it.name.unwrap(),
                 t.generics.print(cx),
                 where_clause = print_where_clause(&t.generics, cx, 0, true),
                 type_ = t.type_.print(cx),
@@ -1004,7 +996,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
                    Fields<a href=\"#fields\" class=\"anchor\"></a></h2>"
         );
         for (field, ty) in fields {
-            let name = field.name.as_ref().expect("union field name");
+            let name = field.name.expect("union field name");
             let id = format!("{}.{}", ItemType::StructField, name);
             write!(
                 w,
@@ -1049,7 +1041,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                 w,
                 "{}enum {}{}{}",
                 it.visibility.print_with_space(it.def_id, cx),
-                it.name.as_ref().unwrap(),
+                it.name.unwrap(),
                 e.generics.print(cx),
                 print_where_clause(&e.generics, cx, 0, true),
             );
@@ -1064,7 +1056,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                 }
                 for v in &e.variants {
                     w.write_str("    ");
-                    let name = v.name.as_ref().unwrap();
+                    let name = v.name.unwrap();
                     match *v.kind {
                         clean::VariantItem(ref var) => match var {
                             clean::Variant::CLike => write!(w, "{}", name),
@@ -1113,15 +1105,14 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
         );
         document_non_exhaustive(w, it);
         for variant in &e.variants {
-            let id =
-                cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.as_ref().unwrap()));
+            let id = cx.derive_id(format!("{}.{}", ItemType::Variant, variant.name.unwrap()));
             write!(
                 w,
                 "<h3 id=\"{id}\" class=\"variant small-section-header\">\
                     <a href=\"#{id}\" class=\"anchor field\"></a>\
                     <code>{name}",
                 id = id,
-                name = variant.name.as_ref().unwrap()
+                name = variant.name.unwrap()
             );
             if let clean::VariantItem(clean::Variant::Tuple(ref s)) = *variant.kind {
                 w.write_str("(");
@@ -1133,18 +1124,24 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             w.write_str("</h3>");
 
             use crate::clean::Variant;
-            if let Some((extra, fields)) = match *variant.kind {
-                clean::VariantItem(Variant::Struct(ref s)) => Some(("", &s.fields)),
-                clean::VariantItem(Variant::Tuple(ref fields)) => Some(("Tuple ", fields)),
+
+            let heading_and_fields = match &*variant.kind {
+                clean::VariantItem(Variant::Struct(s)) => Some(("Fields", &s.fields)),
+                // Documentation on tuple variant fields is rare, so to reduce noise we only emit
+                // the section if at least one field is documented.
+                clean::VariantItem(Variant::Tuple(fields))
+                    if fields.iter().any(|f| f.doc_value().is_some()) =>
+                {
+                    Some(("Tuple Fields", fields))
+                }
                 _ => None,
-            } {
-                let variant_id = cx.derive_id(format!(
-                    "{}.{}.fields",
-                    ItemType::Variant,
-                    variant.name.as_ref().unwrap()
-                ));
+            };
+
+            if let Some((heading, fields)) = heading_and_fields {
+                let variant_id =
+                    cx.derive_id(format!("{}.{}.fields", ItemType::Variant, variant.name.unwrap()));
                 write!(w, "<div class=\"sub-variant\" id=\"{id}\">", id = variant_id);
-                write!(w, "<h4>{extra}Fields</h4>", extra = extra,);
+                write!(w, "<h4>{heading}</h4>", heading = heading);
                 document_non_exhaustive(w, variant);
                 for field in fields {
                     match *field.kind {
@@ -1152,8 +1149,8 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                         clean::StructFieldItem(ref ty) => {
                             let id = cx.derive_id(format!(
                                 "variant.{}.field.{}",
-                                variant.name.as_ref().unwrap(),
-                                field.name.as_ref().unwrap()
+                                variant.name.unwrap(),
+                                field.name.unwrap()
                             ));
                             write!(
                                 w,
@@ -1163,7 +1160,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                                     <code>{f}:&nbsp;{t}</code>\
                                 </span>",
                                 id = id,
-                                f = field.name.as_ref().unwrap(),
+                                f = field.name.unwrap(),
                                 t = ty.print(cx)
                             );
                             document(w, cx, field, Some(variant), HeadingOffset::H5);
@@ -1202,7 +1199,7 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac
 
 fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) {
     wrap_into_docblock(w, |w| {
-        let name = it.name.as_ref().expect("proc-macros always have names");
+        let name = it.name.expect("proc-macros always have names");
         match m.kind {
             MacroKind::Bang => {
                 wrap_item(w, "macro", |w| {
@@ -1246,7 +1243,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::
                 w,
                 "{vis}const {name}: {typ}",
                 vis = it.visibility.print_with_space(it.def_id, cx),
-                name = it.name.as_ref().unwrap(),
+                name = it.name.unwrap(),
                 typ = c.type_.print(cx),
             );
 
@@ -1339,7 +1336,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
                 "{vis}static {mutability}{name}: {typ}",
                 vis = it.visibility.print_with_space(it.def_id, cx),
                 mutability = s.mutability.print_with_space(),
-                name = it.name.as_ref().unwrap(),
+                name = it.name.unwrap(),
                 typ = s.type_.print(cx)
             );
         });
@@ -1356,7 +1353,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
                 w,
                 "    {}type {};\n}}",
                 it.visibility.print_with_space(it.def_id, cx),
-                it.name.as_ref().unwrap(),
+                it.name.unwrap(),
             );
         });
     });
@@ -1408,7 +1405,7 @@ fn take_parts<'a>(s: &mut &'a str) -> (&'a str, &'a str) {
 }
 
 pub(super) fn full_path(cx: &Context<'_>, item: &clean::Item) -> String {
-    let mut s = cx.current.join("::");
+    let mut s = join_with_double_colon(&cx.current);
     s.push_str("::");
     s.push_str(item.name.unwrap().as_str());
     s
@@ -1467,7 +1464,7 @@ fn render_stability_since(
         item.const_stability(tcx),
         containing_item.stable_since(tcx),
         containing_item.const_stable_since(tcx),
-    )
+    );
 }
 
 fn compare_impl<'a, 'b>(lhs: &'a &&Impl, rhs: &'b &&Impl, cx: &Context<'_>) -> Ordering {
@@ -1524,12 +1521,7 @@ fn render_union(
     tab: &str,
     cx: &Context<'_>,
 ) {
-    write!(
-        w,
-        "{}union {}",
-        it.visibility.print_with_space(it.def_id, cx),
-        it.name.as_ref().unwrap()
-    );
+    write!(w, "{}union {}", it.visibility.print_with_space(it.def_id, cx), it.name.unwrap());
     if let Some(g) = g {
         write!(w, "{}", g.print(cx));
         write!(w, "{}", print_where_clause(g, cx, 0, true));
@@ -1549,7 +1541,7 @@ fn render_union(
                 w,
                 "    {}{}: {},\n{}",
                 field.visibility.print_with_space(field.def_id, cx),
-                field.name.as_ref().unwrap(),
+                field.name.unwrap(),
                 ty.print(cx),
                 tab
             );
@@ -1557,7 +1549,7 @@ fn render_union(
     }
 
     if it.has_stripped_fields().unwrap() {
-        write!(w, "    // some fields omitted\n{}", tab);
+        write!(w, "    /* private fields */\n{}", tab);
     }
     if toggle {
         toggle_close(w);
@@ -1580,7 +1572,7 @@ fn render_struct(
         "{}{}{}",
         it.visibility.print_with_space(it.def_id, cx),
         if structhead { "struct " } else { "" },
-        it.name.as_ref().unwrap()
+        it.name.unwrap()
     );
     if let Some(g) = g {
         write!(w, "{}", g.print(cx))
@@ -1605,7 +1597,7 @@ fn render_struct(
                         "\n{}    {}{}: {},",
                         tab,
                         field.visibility.print_with_space(field.def_id, cx),
-                        field.name.as_ref().unwrap(),
+                        field.name.unwrap(),
                         ty.print(cx),
                     );
                 }
@@ -1613,13 +1605,11 @@ fn render_struct(
 
             if has_visible_fields {
                 if it.has_stripped_fields().unwrap() {
-                    write!(w, "\n{}    // some fields omitted", tab);
+                    write!(w, "\n{}    /* private fields */", tab);
                 }
                 write!(w, "\n{}", tab);
             } else if it.has_stripped_fields().unwrap() {
-                // If there are no visible fields we can just display
-                // `{ /* fields omitted */ }` to save space.
-                write!(w, " /* fields omitted */ ");
+                write!(w, " /* private fields */ ");
             }
             if toggle {
                 toggle_close(w);
@@ -1776,8 +1766,8 @@ fn write_size_of_layout(w: &mut Buffer, layout: &Layout, tag_size: u64) {
                     };
 
                     for (index, layout) in variants.iter_enumerated() {
-                        let ident = adt.variants[index].ident;
-                        write!(w, "<li><code>{name}</code>: ", name = ident);
+                        let name = adt.variants[index].name;
+                        write!(w, "<li><code>{name}</code>: ", name = name);
                         write_size_of_layout(w, layout, tag_size);
                         writeln!(w, "</li>");
                     }
index 0fbe090f2190abf831d04d0e3c3b0a6968930ebb..87138b9571c2a0e36515203263dfe060e730a508 100644 (file)
@@ -10,6 +10,7 @@
 use crate::clean::types::{FnRetTy, Function, GenericBound, Generics, Type, WherePredicate};
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
+use crate::html::format::join_with_double_colon;
 use crate::html::markdown::short_markdown_summary;
 use crate::html::render::{IndexItem, IndexItemFunctionType, RenderType, TypeWithKind};
 
@@ -28,7 +29,7 @@
             cache.search_index.push(IndexItem {
                 ty: item.type_(),
                 name: item.name.unwrap().to_string(),
-                path: fqp[..fqp.len() - 1].join("::"),
+                path: join_with_double_colon(&fqp[..fqp.len() - 1]),
                 desc,
                 parent: Some(did),
                 parent_idx: None,
     struct CrateData<'a> {
         doc: String,
         items: Vec<&'a IndexItem>,
-        paths: Vec<(ItemType, String)>,
+        paths: Vec<(ItemType, Symbol)>,
         // The String is alias name and the vec is the list of the elements with this alias.
         //
         // To be noted: the `usize` elements are indexes to `items`.
@@ -154,7 +155,10 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
                 "f",
                 &self.items.iter().map(|item| &item.search_type).collect::<Vec<_>>(),
             )?;
-            crate_data.serialize_field("p", &self.paths)?;
+            crate_data.serialize_field(
+                "p",
+                &self.paths.iter().map(|(it, s)| (it, s.to_string())).collect::<Vec<_>>(),
+            )?;
             if has_aliases {
                 crate_data.serialize_field("a", &self.aliases)?;
             }
diff --git a/src/librustdoc/html/render/templates.rs b/src/librustdoc/html/render/templates.rs
deleted file mode 100644 (file)
index d1f1823..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-use std::error::Error as StdError;
-
-use crate::error::Error;
-
-pub(crate) fn load() -> Result<tera::Tera, Error> {
-    let mut templates = tera::Tera::default();
-
-    macro_rules! include_template {
-        ($file:literal, $fullpath:literal) => {
-            templates.add_raw_template($file, include_str!($fullpath)).map_err(|e| Error {
-                file: $file.into(),
-                error: format!("{}: {}", e, e.source().map(|e| e.to_string()).unwrap_or_default()),
-            })?
-        };
-    }
-
-    include_template!("page.html", "../templates/page.html");
-    include_template!("print_item.html", "../templates/print_item.html");
-    Ok(templates)
-}
index 563f4ae7385ce3d3f6503e2bc9b5257410e6c5db..3fa16c6c3b88067287439c3eb2267e59827655e9 100644 (file)
@@ -240,7 +240,7 @@ fn ver_url(cx: &Context<'_>, basename: &'static str) -> String {
     }
 
     if (*cx.shared).layout.logo.is_empty() {
-        write_toolchain("rust-logo.png", static_files::RUST_LOGO)?;
+        write_toolchain("rust-logo.svg", static_files::RUST_LOGO_SVG)?;
     }
     if (*cx.shared).layout.favicon.is_empty() {
         write_toolchain("favicon.svg", static_files::RUST_FAVICON_SVG)?;
@@ -494,14 +494,7 @@ fn to_json_string(&self) -> String {
                     })
                     .collect::<String>()
             );
-            let v = layout::render(
-                &cx.shared.templates,
-                &cx.shared.layout,
-                &page,
-                "",
-                content,
-                &cx.shared.style_files,
-            );
+            let v = layout::render(&cx.shared.layout, &page, "", content, &cx.shared.style_files);
             cx.shared.fs.write(dst, v)?;
         }
     }
@@ -569,7 +562,7 @@ struct Implementor {
 
         let mut mydst = dst.clone();
         for part in &remote_path[..remote_path.len() - 1] {
-            mydst.push(part);
+            mydst.push(part.to_string());
         }
         cx.shared.ensure_dir(&mydst)?;
         mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1]));
index 04c2b7a0c9abafd837792eca480ce8e1e4a4476a..bae04f2095a3d079d63a6a09636953c3c592292b 100644 (file)
@@ -203,7 +203,6 @@ fn emit_source(
             static_extra_scripts: &[&format!("source-script{}", self.cx.shared.resource_suffix)],
         };
         let v = layout::render(
-            &self.cx.shared.templates,
             &self.cx.shared.layout,
             &page,
             "",
index e5c667a37c6696681dfd25521c121259e8507081..d7f33d6131c8499d3612e09c78735fc58f6f502e 100644 (file)
@@ -108,7 +108,7 @@ html {
 /* General structure and fonts */
 
 body {
-       font: 16px/1.4 "Source Serif 4", NanumBarunGothic, serif;
+       font: 1rem/1.4 "Source Serif 4", NanumBarunGothic, serif;
        margin: 0;
        position: relative;
 
@@ -118,13 +118,13 @@ body {
 }
 
 h1 {
-       font-size: 1.5em;
+       font-size: 1.5rem;
 }
 h2 {
-       font-size: 1.4em;
+       font-size: 1.4rem;
 }
 h3 {
-       font-size: 1.3em;
+       font-size: 1.3rem;
 }
 h1, h2, h3, h4, h5, h6 {
        font-weight: 500;
@@ -137,17 +137,25 @@ h1, h2, h3, h4 {
        margin: 15px 0 5px 0;
 }
 h1.fqn {
+       margin: 0;
+       padding: 0;
+}
+.main-heading {
        display: flex;
-       border-bottom: 1px dashed;
-       margin-top: 0;
+       border-bottom: 1px dashed #DDDDDD;
+       padding-bottom: 6px;
+       margin-bottom: 15px;
 
        /* workaround to keep flex from breaking below 700 px width due to the float: right on the nav
           above the h1 */
        padding-left: 1px;
 }
-h1.fqn > .in-band > a:hover {
+.main-heading a:hover {
        text-decoration: underline;
 }
+#toggle-all-docs {
+       text-decoration: none;
+}
 /* The only headings that get underlines are:
         Markdown-generated headings within the top-doc
         Rustdoc-generated h2 section headings (e.g. "Implementations", "Required Methods", etc)
@@ -160,10 +168,10 @@ h2,
        border-bottom: 1px solid;
 }
 h3.code-header {
-       font-size: 1.1em;
+       font-size: 1.1rem;
 }
 h4.code-header {
-       font-size: 1em;
+       font-size: 1rem;
 }
 h3.code-header, h4.code-header {
        font-weight: 600;
@@ -195,18 +203,20 @@ h1, h2, h3, h4, h5, h6,
 .sidebar, a.source, .search-input, .search-results .result-name,
 .content table td:first-child > a,
 .item-left > a,
-div.item-list .out-of-band, span.since,
+.out-of-band,
+span.since,
 #source-sidebar, #sidebar-toggle,
 details.rustdoc-toggle > summary::before,
 div.impl-items > div:not(.docblock):not(.item-info),
-.content ul.crate a.crate, a.srclink,
+.content ul.crate a.crate,
+a.srclink,
 /* This selector is for the items listed in the "all items" page. */
 #main-content > ul.docblock > li > a {
        font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
 }
 
 .content ul.crate a.crate {
-       font-size: 16px/1.6;
+       font-size: 1rem/1.6;
 }
 
 ol, ul {
@@ -317,7 +327,7 @@ li {
 
 nav.sub {
        position: relative;
-       font-size: 16px;
+       font-size: 1rem;
        text-transform: uppercase;
 }
 
@@ -423,7 +433,7 @@ nav.sub {
 
 .sidebar .location {
        border: 1px solid;
-       font-size: 17px;
+       font-size: 1.0625rem;
        margin: 30px 10px 20px 10px;
        text-align: center;
        word-wrap: break-word;
@@ -432,7 +442,7 @@ nav.sub {
 }
 
 .sidebar .version {
-       font-size: 15px;
+       font-size: 0.9375rem;
        text-align: center;
        border-bottom: 1px solid;
        overflow-wrap: break-word;
@@ -470,7 +480,7 @@ nav.sub {
        overflow: hidden;
        line-height: 15px;
        padding: 7px 5px;
-       font-size: 14px;
+       font-size: 0.875rem;
        font-weight: 300;
        transition: border 500ms ease-out;
 }
@@ -479,7 +489,7 @@ nav.sub {
        border-top: 1px solid;
        border-bottom: 1px solid;
        text-align: center;
-       font-size: 17px;
+       font-size: 1.0625rem;
        margin-bottom: 5px;
        font-weight: inherit;
        padding: 0;
@@ -545,6 +555,10 @@ nav.sub {
        position: relative;
 }
 
+.search-loading {
+       text-align: center;
+}
+
 #results > table {
        width: 100%;
        table-layout: fixed;
@@ -579,18 +593,18 @@ nav.sub {
        white-space: pre-wrap;
 }
 
-.top-doc .docblock h2 { font-size: 1.3em; }
-.top-doc .docblock h3 { font-size: 1.15em; }
+.top-doc .docblock h2 { font-size: 1.3rem; }
+.top-doc .docblock h3 { font-size: 1.15rem; }
 .top-doc .docblock h4,
 .top-doc .docblock h5 {
-       font-size: 1.1em;
+       font-size: 1.1rem;
 }
 .top-doc .docblock h6 {
-       font-size: 1em;
+       font-size: 1rem;
 }
 
-.docblock h5 { font-size: 1em; }
-.docblock h6 { font-size: 0.95em; }
+.docblock h5 { font-size: 1rem; }
+.docblock h6 { font-size: 0.95rem; }
 
 .docblock {
        margin-left: 24px;
@@ -605,10 +619,12 @@ nav.sub {
 .content .out-of-band {
        flex-grow: 0;
        text-align: right;
-       font-size: 23px;
-       margin: 0px;
+       margin-left: auto;
+       margin-right: 0;
+       font-size: 1.15rem;
        padding: 0 0 0 12px;
        font-weight: normal;
+       float: right;
 }
 
 .method > .code-header, .trait-impl > .code-header, .invisible > .code-header {
@@ -646,7 +662,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.1em; }
+.content td h1, .content td h2 { margin-left: 0; font-size: 1.1rem; }
 .content tr:first-child td { border-top: 0; }
 
 .docblock table {
@@ -687,7 +703,7 @@ nav.sub {
 .content .multi-column li { width: 100%; display: inline-block; }
 
 .content > .methods > .method {
-       font-size: 1em;
+       font-size: 1rem;
        position: relative;
 }
 /* Shift "where ..." part of method or fn definition down a line */
@@ -695,7 +711,7 @@ nav.sub {
 .content .fn .where,
 .content .where.fmt-newline {
        display: block;
-       font-size: 0.8em;
+       font-size: 0.8rem;
 }
 
 .content .methods > div:not(.notable-traits):not(.method) {
@@ -718,7 +734,7 @@ nav.sub {
 }
 
 .content .item-info code {
-       font-size: 90%;
+       font-size: 0.81rem;
 }
 
 .content .item-info {
@@ -732,7 +748,7 @@ nav.sub {
 
 .content .item-info::before {
        content: '⬑';
-       font-size: 25px;
+       font-size: 1.5625rem;
        position: absolute;
        top: -6px;
        left: -19px;
@@ -835,7 +851,7 @@ h2.small-section-header > .anchor {
        position: absolute;
        top: 0;
        right: 0;
-       font-size: 17px;
+       font-size: 1.0625rem;
        font-weight: normal;
 }
 
@@ -862,18 +878,24 @@ h2.small-section-header > .anchor {
        display: inline-flex;
        width: calc(100% - 63px);
 }
+.search-results-title {
+       display: inline;
+}
+#search-settings {
+       font-size: 1.5rem;
+       font-weight: 500;
+       margin-bottom: 20px;
+}
 #crate-search {
        min-width: 115px;
        margin-top: 5px;
-       padding: 6px;
-       padding-right: 19px;
-       flex: none;
+       margin-left: 0.2em;
+       padding-left: 0.3em;
+       padding-right: 23px;
        border: 0;
-       border-right: 0;
-       border-radius: 4px 0 0 4px;
+       border-radius: 4px;
        outline: none;
        cursor: pointer;
-       border-right: 1px solid;
        -moz-appearance: none;
        -webkit-appearance: none;
        /* Removes default arrow from firefox */
@@ -905,7 +927,7 @@ h2.small-section-header > .anchor {
        border-radius: 1px;
        margin-top: 5px;
        padding: 10px 16px;
-       font-size: 17px;
+       font-size: 1.0625rem;
        transition: border-color 300ms ease;
        transition: border-radius 300ms ease-in-out;
        transition: box-shadow 300ms ease-in-out;
@@ -1000,7 +1022,7 @@ body.blur > :not(#help) {
 #help span.top, #help span.bottom {
        text-align: center;
        display: block;
-       font-size: 18px;
+       font-size: 1.125rem;
 
 }
 #help span.top {
@@ -1030,7 +1052,7 @@ body.blur > :not(#help) {
 .stab {
        padding: 3px;
        margin-bottom: 5px;
-       font-size: 90%;
+       font-size: 0.9rem;
        font-weight: normal;
 }
 .stab p {
@@ -1038,7 +1060,7 @@ body.blur > :not(#help) {
 }
 
 .stab .emoji {
-       font-size: 1.2em;
+       font-size: 1.2rem;
 }
 
 /* Black one-pixel outline around emoji shapes */
@@ -1054,7 +1076,7 @@ body.blur > :not(#help) {
 .import-item .stab {
        border-radius: 3px;
        display: inline-block;
-       font-size: 80%;
+       font-size: 0.8rem;
        line-height: 1.2;
        margin-bottom: 0;
        margin-left: .3em;
@@ -1072,7 +1094,7 @@ body.blur > :not(#help) {
        font-size: initial;
 }
 
-.impl-items .since, .impl .since, .methods .since {
+.rightside {
        padding-left: 12px;
        padding-right: 2px;
        position: initial;
@@ -1080,8 +1102,11 @@ body.blur > :not(#help) {
 
 .impl-items .srclink, .impl .srclink, .methods .srclink {
        /* Override header settings otherwise it's too bold */
-       font-size: 17px;
        font-weight: normal;
+       font-size: 1rem;
+}
+.impl .srclink {
+       font-size: 1.0625rem;
 }
 
 .rightside {
@@ -1089,7 +1114,7 @@ body.blur > :not(#help) {
 }
 
 .has-srclink {
-       font-size: 16px;
+       font-size: 1rem;
        margin-bottom: 12px;
        /* Push the src link out to the right edge consistently */
        justify-content: space-between;
@@ -1117,18 +1142,21 @@ pre.rust .question-mark {
 
 a.test-arrow {
        display: inline-block;
+       visibility: hidden;
        position: absolute;
        padding: 5px 10px 5px 10px;
        border-radius: 5px;
-       font-size: 130%;
+       font-size: 1.3rem;
        top: 5px;
        right: 5px;
        z-index: 1;
 }
+.example-wrap:hover .test-arrow {
+       visibility: visible;
+}
 a.test-arrow:hover{
        text-decoration: none;
 }
-
 .section-header:hover a:before {
        position: absolute;
        left: -25px;
@@ -1144,10 +1172,6 @@ a.test-arrow:hover{
        font-weight: 300;
 }
 
-.since + .srclink {
-       padding-left: 10px;
-}
-
 .item-spacer {
        width: 100%;
        height: 12px;
@@ -1155,19 +1179,19 @@ a.test-arrow:hover{
 
 .out-of-band > span.since {
        position: initial;
-       font-size: 20px;
+       font-size: 1.25rem;
        margin-right: 5px;
 }
 
 h3.variant {
        font-weight: 600;
-       font-size: 1.1em;
+       font-size: 1.1rem;
        margin-bottom: 10px;
        border-bottom: none;
 }
 
 .sub-variant h4 {
-       font-size: 1em;
+       font-size: 1rem;
        font-weight: 400;
        border-bottom: none;
        margin-top: 0;
@@ -1227,7 +1251,7 @@ h3.variant {
        padding: 5px 3px 3px 3px;
        border-radius: 6px;
        margin-left: 5px;
-       font-size: 16px;
+       font-size: 1rem;
 }
 
 .tooltip.ignore::after {
@@ -1260,7 +1284,7 @@ h3.variant {
 
 .tooltip.compile_fail, .tooltip.should_panic, .tooltip.ignore {
        font-weight: bold;
-       font-size: 20px;
+       font-size: 1.25rem;
 }
 
 .notable-traits-tooltip {
@@ -1279,7 +1303,7 @@ h3.variant {
        border-radius: 6px;
        margin-left: 5px;
        z-index: 10;
-       font-size: 16px;
+       font-size: 1rem;
        cursor: default;
        position: absolute;
        border: 1px solid;
@@ -1299,14 +1323,14 @@ h3.variant {
 .notable-traits .notable {
        margin: 0;
        margin-bottom: 13px;
-       font-size: 19px;
+       font-size: 1.1875rem;
        font-weight: 600;
 }
 
 .notable-traits .docblock code.content{
        margin: 0;
        padding: 0;
-       font-size: 20px;
+       font-size: 1.25rem;
 }
 
 /* Example code has the "Run" button that needs to be positioned relative to the pre */
@@ -1344,7 +1368,7 @@ pre.rust {
        float: left;
        width: 33.3%;
        text-align: center;
-       font-size: 18px;
+       font-size: 1.125rem;
        cursor: pointer;
        border: 0;
        border-top: 2px solid;
@@ -1357,7 +1381,7 @@ pre.rust {
 
 #titles > button > div.count {
        display: inline-block;
-       font-size: 16px;
+       font-size: 1rem;
 }
 
 .notable-traits {
@@ -1384,7 +1408,7 @@ pre.rust {
        left: 0;
        cursor: pointer;
        font-weight: bold;
-       font-size: 1.2em;
+       font-size: 1.2rem;
        border-bottom: 1px solid;
        display: flex;
        height: 40px;
@@ -1398,7 +1422,7 @@ pre.rust {
        overflow: auto;
 }
 #source-sidebar > .title {
-       font-size: 1.5em;
+       font-size: 1.5rem;
        text-align: center;
        border-bottom: 1px solid;
        margin-bottom: 6px;
@@ -1426,6 +1450,9 @@ pre.rust {
 
 #theme-picker, #settings-menu, #help-button, #copy-path {
        padding: 4px;
+       /* Rare exception to specifying font sizes in rem. Since these are acting
+          as icons, it's okay to specify their sizes in pixels. */
+       font-size: 16px;
        width: 27px;
        height: 29px;
        border: 1px solid;
@@ -1437,7 +1464,9 @@ pre.rust {
        right: 30px;
        font-family: "Fira Sans", Arial, sans-serif;
        text-align: center;
-       font-size: 17px;
+       /* Rare exception to specifying font sizes in rem. Since this is acting
+          as an icon, it's okay to specify their sizes in pixels. */
+       font-size: 16px;
        padding-top: 2px;
 }
 
@@ -1499,7 +1528,7 @@ kbd {
        border: 0;
        border-collapse: collapse;
        border-spacing: 0;
-       font-size: 16px;
+       font-size: 1rem;
 }
 
 .table-display tr td:first-child {
@@ -1511,11 +1540,11 @@ kbd {
 }
 .table-display .out-of-band {
        position: relative;
-       font-size: 19px;
+       font-size: 1.1875rem;
        display: block;
 }
 #implementors-list > .impl-items .table-display .out-of-band {
-       font-size: 17px;
+       font-size: 1.0625rem;
 }
 
 .table-display td:hover .anchor {
@@ -1557,7 +1586,7 @@ div.name.expand + .children {
 div.name::before {
        content: "\25B6";
        padding-left: 4px;
-       font-size: 0.7em;
+       font-size: 0.7rem;
        position: absolute;
        left: -16px;
        top: 4px;
@@ -1624,7 +1653,7 @@ details.rustdoc-toggle.top-doc > summary::before,
 details.rustdoc-toggle.non-exhaustive > summary,
 details.rustdoc-toggle.non-exhaustive > summary::before {
        font-family: 'Fira Sans';
-       font-size: 16px;
+       font-size: 1rem;
 }
 
 details.non-exhaustive {
@@ -1768,7 +1797,7 @@ details.rustdoc-toggle[open] > summary.hideme::after {
                min-height: 39px;
                background: inherit;
                text-align: left;
-               font-size: 24px;
+               font-size: 1.5rem;
        }
 
        .sidebar .location:empty {
@@ -1909,7 +1938,7 @@ details.rustdoc-toggle[open] > summary.hideme::after {
        }
 
        .show-it > .block.items > ul > li > a {
-               font-size: 21px;
+               font-size: 1.3125rem;
        }
 
        /* Because of ios, we need to actually have a full height sidebar title so the
index 38040eeca52d494aef3e88cafe31b6dbdfdbd632..23ee87a4e681d8680e9b592b50d49fb300d9bf17 100644 (file)
@@ -61,7 +61,7 @@ pre, .rustdoc.source .example-wrap {
        background-color: #14191f;
 }
 
-.rust-logo > img {
+.rust-logo {
        filter: drop-shadow(1px 0 0px #fff)
                drop-shadow(0 1px 0 #fff)
                drop-shadow(-1px 0 0 #fff)
@@ -222,7 +222,7 @@ nav.main .separator {
 a {
        color: #39AFD7;
 }
-a.srclink,
+
 a#toggle-all-docs,
 a.anchor,
 .small-section-header a,
@@ -351,11 +351,8 @@ a.test-arrow:hover {
        color: #999;
 }
 
-:target, :target > * {
-       background: rgba(255, 236, 164, 0.06);
-}
-
 :target {
+       background: rgba(255, 236, 164, 0.06);
        border-right: 3px solid rgba(255, 180, 76, 0.85);
 }
 
index f4181e431c896259350f4b082252fb751508503e..2db725c9b4e975a966191e9f442b22d975484565 100644 (file)
@@ -32,7 +32,7 @@ pre, .rustdoc.source .example-wrap {
        background-color: #505050;
 }
 
-.rust-logo > img {
+.rust-logo {
        filter: drop-shadow(1px 0 0px #fff)
                drop-shadow(0 1px 0 #fff)
                drop-shadow(-1px 0 0 #fff)
@@ -180,7 +180,7 @@ nav.main .separator {
 a {
        color: #D2991D;
 }
-a.srclink,
+
 a#toggle-all-docs,
 a.anchor,
 .small-section-header a,
@@ -295,11 +295,8 @@ a.test-arrow:hover{
        color: #999;
 }
 
-:target, :target > * {
-       background-color: #494a3d;
-}
-
 :target {
+       background-color: #494a3d;
        border-right: 3px solid #bb7410;
 }
 
index 176f63098a49f5c8fe22cb7384cdc214b924b4d3..3c8dbeb98c5b3623b20c04cfcc1bfa0ac9a5e881 100644 (file)
@@ -43,7 +43,7 @@ pre, .rustdoc.source .example-wrap {
        scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
 }
 
-.rust-logo > img {
+.rust-logo {
        /* No need for a border in here! */
 }
 
@@ -177,7 +177,7 @@ nav.main .separator {
 a {
        color: #3873AD;
 }
-a.srclink,
+
 a#toggle-all-docs,
 a.anchor,
 .small-section-header a,
@@ -243,10 +243,6 @@ details.undocumented > summary::before {
        border-color: #bfbfbf;
 }
 
-.since {
-       color: grey;
-}
-
 .result-name .primitive > i, .result-name .keyword > i {
        color: black;
 }
@@ -284,11 +280,8 @@ a.test-arrow:hover{
        color: #999;
 }
 
-:target, :target > * {
-       background: #FDFFD3;
-}
-
 :target {
+       background: #FDFFD3;
        border-right: 3px solid #AD7C37;
 }
 
index 7cfe6c13550d31bc31355616bbb9cb77fd1b25ef..ea4b45cae1618e6e20e6d61897da953f34b66b30 100644 (file)
Binary files a/src/librustdoc/html/static/images/favicon-16x16.png and b/src/librustdoc/html/static/images/favicon-16x16.png differ
index 5109c1de8bea744180448b347fb44ddef23b90f4..69b8613ce1506e1c92b864f91cc46df06348c62b 100644 (file)
Binary files a/src/librustdoc/html/static/images/favicon-32x32.png and b/src/librustdoc/html/static/images/favicon-32x32.png differ
diff --git a/src/librustdoc/html/static/images/rust-logo.png b/src/librustdoc/html/static/images/rust-logo.png
deleted file mode 100644 (file)
index 74b4bd6..0000000
Binary files a/src/librustdoc/html/static/images/rust-logo.png and /dev/null differ
diff --git a/src/librustdoc/html/static/images/rust-logo.svg b/src/librustdoc/html/static/images/rust-logo.svg
new file mode 100644 (file)
index 0000000..62424d8
--- /dev/null
@@ -0,0 +1,61 @@
+<svg version="1.1" height="106" width="106" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="logo" transform="translate(53, 53)">
+  <path id="r" transform="translate(0.5, 0.5)" stroke="black" stroke-width="1" stroke-linejoin="round" d="
+    M -9,-15 H 4 C 12,-15 12,-7 4,-7 H -9 Z
+    M -40,22 H 0 V 11 H -9 V 3 H 1 C 12,3 6,22 15,22 H 40
+    V 3 H 34 V 5 C 34,13 25,12 24,7 C 23,2 19,-2 18,-2 C 33,-10 24,-26 12,-26 H -35
+    V -15 H -25 V 11 H -40 Z" />
+  <g id="gear" mask="url(#holes)">
+    <circle r="43" fill="none" stroke="black" stroke-width="9" />
+    <g id="cogs">
+      <polygon id="cog" stroke="black" stroke-width="3" stroke-linejoin="round" points="46,3 51,0 46,-3" />
+      <use xlink:href="#cog" transform="rotate(11.25)" />
+      <use xlink:href="#cog" transform="rotate(22.50)" />
+      <use xlink:href="#cog" transform="rotate(33.75)" />
+      <use xlink:href="#cog" transform="rotate(45.00)" />
+      <use xlink:href="#cog" transform="rotate(56.25)" />
+      <use xlink:href="#cog" transform="rotate(67.50)" />
+      <use xlink:href="#cog" transform="rotate(78.75)" />
+      <use xlink:href="#cog" transform="rotate(90.00)" />
+      <use xlink:href="#cog" transform="rotate(101.25)" />
+      <use xlink:href="#cog" transform="rotate(112.50)" />
+      <use xlink:href="#cog" transform="rotate(123.75)" />
+      <use xlink:href="#cog" transform="rotate(135.00)" />
+      <use xlink:href="#cog" transform="rotate(146.25)" />
+      <use xlink:href="#cog" transform="rotate(157.50)" />
+      <use xlink:href="#cog" transform="rotate(168.75)" />
+      <use xlink:href="#cog" transform="rotate(180.00)" />
+      <use xlink:href="#cog" transform="rotate(191.25)" />
+      <use xlink:href="#cog" transform="rotate(202.50)" />
+      <use xlink:href="#cog" transform="rotate(213.75)" />
+      <use xlink:href="#cog" transform="rotate(225.00)" />
+      <use xlink:href="#cog" transform="rotate(236.25)" />
+      <use xlink:href="#cog" transform="rotate(247.50)" />
+      <use xlink:href="#cog" transform="rotate(258.75)" />
+      <use xlink:href="#cog" transform="rotate(270.00)" />
+      <use xlink:href="#cog" transform="rotate(281.25)" />
+      <use xlink:href="#cog" transform="rotate(292.50)" />
+      <use xlink:href="#cog" transform="rotate(303.75)" />
+      <use xlink:href="#cog" transform="rotate(315.00)" />
+      <use xlink:href="#cog" transform="rotate(326.25)" />
+      <use xlink:href="#cog" transform="rotate(337.50)" />
+      <use xlink:href="#cog" transform="rotate(348.75)" />
+    </g>
+    <g id="mounts">
+      <polygon id="mount" stroke="black" stroke-width="6" stroke-linejoin="round" points="-7,-42 0,-35 7,-42" />
+      <use xlink:href="#mount" transform="rotate(72)" />
+      <use xlink:href="#mount" transform="rotate(144)" />
+      <use xlink:href="#mount" transform="rotate(216)" />
+      <use xlink:href="#mount" transform="rotate(288)" />
+    </g>
+  </g>
+  <mask id="holes">
+    <rect x="-60" y="-60" width="120" height="120" fill="white"/>
+    <circle id="hole" cy="-40" r="3" />
+    <use xlink:href="#hole" transform="rotate(72)" />
+    <use xlink:href="#hole" transform="rotate(144)" />
+    <use xlink:href="#hole" transform="rotate(216)" />
+    <use xlink:href="#hole" transform="rotate(288)" />
+  </mask>
+</g>
+</svg>
index f81f6d5d61fed658d7d551424b82b95a33a963b2..f41c1bd817ab284f3afb2a58eb804a45208fbc54 100644 (file)
@@ -289,8 +289,8 @@ function hideThemeButtonState() {
             var params = searchState.getQueryStringParams();
             if (params.search !== undefined) {
                 var search = searchState.outputElement();
-                search.innerHTML = "<h3 style=\"text-align: center;\">" +
-                   searchState.loadingText + "</h3>";
+                search.innerHTML = "<h3 class=\"search-loading\">" +
+                    searchState.loadingText + "</h3>";
                 searchState.showResults(search);
                 loadSearch();
             }
index cf320f7b4958a14a10eaf0d16c48ab3f20e73a77..e859431e1f189e68a7b761d85374b89df4a929a4 100644 (file)
@@ -1085,7 +1085,7 @@ window.initSearch = function(rawSearchIndex) {
         return "<button>" + text + " <div class=\"count\">(" + nbElems + ")</div></button>";
     }
 
-    function showResults(results, go_to_first) {
+    function showResults(results, go_to_first, filterCrates) {
         var search = searchState.outputElement();
         if (go_to_first || (results.others.length === 1
             && getSettingValue("go-to-only-result") === "true"
@@ -1126,9 +1126,16 @@ window.initSearch = function(rawSearchIndex) {
             }
         }
 
-        var output = "<h1>Results for " + escape(query.query) +
+        let crates = `<select id="crate-search"><option value="All crates">All crates</option>`;
+        for (let c of window.ALL_CRATES) {
+            crates += `<option value="${c}" ${c == filterCrates && "selected"}>${c}</option>`;
+        }
+        crates += `</select>`;
+        var output = `<div id="search-settings">
+            <h1 class="search-results-title">Results for ${escape(query.query)} ` +
             (query.type ? " (type: " + escape(query.type) + ")" : "") + "</h1>" +
-            "<div id=\"titles\">" +
+            ` in ${crates} ` +
+            `</div><div id="titles">` +
             makeTabHeader(0, "In Names", ret_others[1]) +
             makeTabHeader(1, "In Parameters", ret_in_args[1]) +
             makeTabHeader(2, "In Return Types", ret_returned[1]) +
@@ -1141,6 +1148,7 @@ window.initSearch = function(rawSearchIndex) {
         resultsElem.appendChild(ret_returned[0]);
 
         search.innerHTML = output;
+        document.getElementById("crate-search").addEventListener("input", updateCrate);
         search.appendChild(resultsElem);
         // Reset focused elements.
         searchState.focusedByTab = [null, null, null];
@@ -1316,7 +1324,8 @@ window.initSearch = function(rawSearchIndex) {
         }
 
         var filterCrates = getFilterCrates();
-        showResults(execSearch(query, searchWords, filterCrates), params["go_to_first"]);
+        showResults(execSearch(query, searchWords, filterCrates),
+            params["go_to_first"], filterCrates);
     }
 
     function buildIndex(rawSearchIndex) {
@@ -1552,19 +1561,6 @@ window.initSearch = function(rawSearchIndex) {
             }
         });
 
-
-        var selectCrate = document.getElementById("crate-search");
-        if (selectCrate) {
-            selectCrate.onchange = function() {
-                updateLocalStorage("rustdoc-saved-filter-crate", selectCrate.value);
-                // 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.
-                currentResults = null;
-                search(undefined, true);
-            };
-        }
-
         // Push and pop states are used to add search results to the browser
         // history.
         if (searchState.browserSupportsHistoryApi()) {
@@ -1616,6 +1612,15 @@ window.initSearch = function(rawSearchIndex) {
         };
     }
 
+    function updateCrate(ev) {
+        updateLocalStorage("rustdoc-saved-filter-crate", ev.target.value);
+        // 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.
+        currentResults = null;
+        search(undefined, true);
+    }
+
     searchWords = buildIndex(rawSearchIndex);
     registerSearchEvents();
     // If there's a search term in the URL, execute the search now.
index 56c5399d074b64c8f5479416a6f1a90a5ce020ec..cd369a93d8283cff07f7fafe1075d2ab2dd0aee0 100644 (file)
@@ -67,8 +67,9 @@
 /// The contents of `LICENSE-MIT.txt`, the text of the MIT License.
 crate static LICENSE_MIT: &[u8] = include_bytes!("static/LICENSE-MIT.txt");
 
-/// The contents of `rust-logo.png`, the default icon of the documentation.
-crate static RUST_LOGO: &[u8] = include_bytes!("static/images/rust-logo.png");
+/// The contents of `rust-logo.svg`, the default icon of the documentation.
+crate static RUST_LOGO_SVG: &[u8] = include_bytes!("static/images/rust-logo.svg");
+
 /// The default documentation favicons (SVG and PNG fallbacks)
 crate static RUST_FAVICON_SVG: &[u8] = include_bytes!("static/images/favicon.svg");
 crate static RUST_FAVICON_PNG_16: &[u8] = include_bytes!("static/images/favicon-16x16.png");
diff --git a/src/librustdoc/html/templates/STYLE.md b/src/librustdoc/html/templates/STYLE.md
deleted file mode 100644 (file)
index fff65e3..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-# Style for Templates
-
-This directory has templates in the [Tera templating language](teradoc), which is very
-similar to [Jinja2](jinjadoc) and [Django](djangodoc) templates, and also to [Askama](askamadoc).
-
-[teradoc]: https://tera.netlify.app/docs/#templates
-[jinjadoc]: https://jinja.palletsprojects.com/en/3.0.x/templates/
-[djangodoc]: https://docs.djangoproject.com/en/3.2/topics/templates/
-[askamadoc]: https://docs.rs/askama/0.10.5/askama/
-
-We want our rendered output to have as little unnecessary whitespace as
-possible, so that pages load quickly. To achieve that we use Tera's
-[whitespace control] features. At the end of most lines, we put an empty comment
-tag with the whitespace control characters: `{#- -#}`. This causes all
-whitespace between the end of the line and the beginning of the next, including
-indentation, to be omitted on render. Sometimes we want to preserve a single
-space. In those cases we put the space at the end of the line, followed by
-`{# -#}`, which is a directive to remove following whitespace but not preceding.
-We also use the whitespace control characters in most instances of tags with
-control flow, for example `{%- if foo -%}`.
-
-[whitespace control]: https://tera.netlify.app/docs/#whitespace-control
-
-We want our templates to be readable, so we use indentation and newlines
-liberally. We indent by four spaces after opening an HTML tag _or_ a Tera
-tag. In most cases an HTML tag should be followed by a newline, but if the
-tag has simple contents and fits with its close tag on a single line, the
-contents don't necessarily need a new line.
-
-Tera templates support quite sophisticated control flow. To keep our templates
-simple and understandable, we use only a subset: `if` and `for`. In particular
-we avoid [assignments in the template logic](assignments) and [Tera
-macros](macros). This also may make things easier if we switch to a different
-Jinja-style template system, like Askama, in the future.
-
-[assignments]: https://tera.netlify.app/docs/#assignments
-[macros]: https://tera.netlify.app/docs/#macros
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
deleted file mode 100644 (file)
index 00b46b1..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-<!DOCTYPE html> {#- -#}
-<html lang="en"> {#- -#}
-<head> {#- -#}
-    <meta charset="utf-8"> {#- -#}
-    <meta name="viewport" content="width=device-width, initial-scale=1.0"> {#- -#}
-    <meta name="generator" content="rustdoc"> {#- -#}
-    <meta name="description" content="{{page.description}}"> {#- -#}
-    <meta name="keywords" content="{{page.keywords}}"> {#- -#}
-    <title>{{page.title}}</title> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Regular.ttf.woff2"> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Regular.woff2"> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}FiraSans-Medium.woff2"> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
-    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path | safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
-    <link rel="stylesheet" type="text/css" {# -#}
-          href="{{static_root_path | safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
-    <link rel="stylesheet" type="text/css" {# -#}
-          href="{{static_root_path | safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
-          id="mainThemeStyle"> {#- -#}
-    {%- for theme in themes -%}
-        <link rel="stylesheet" type="text/css" {# -#}
-            href="{{static_root_path | safe}}{{theme}}{{page.resource_suffix}}.css" {# -#}
-        {%- if theme == "light" -%}
-            id="themeStyle"
-        {%- else -%}
-            disabled
-        {%- endif -%}
-        >
-    {%- endfor -%}
-    <script id="default-settings" {# -#}
-      {% for k, v in layout.default_settings %}
-        data-{{k}}="{{v}}"
-      {%- endfor -%}
-    ></script> {#- -#}
-    <script src="{{static_root_path | safe}}storage{{page.resource_suffix}}.js"></script> {#- -#}
-    <script src="{{page.root_path | safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
-    <script defer src="{{static_root_path | safe}}main{{page.resource_suffix}}.js"></script> {#- -#}
-    {%- for script in page.static_extra_scripts -%}
-    <script defer src="{{static_root_path | safe}}{{script}}.js"></script> {#- -#}
-    {% endfor %}
-    {%- if layout.scrape_examples_extension -%}
-    <script defer src="{{page.root_path | safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
-    {%- endif -%}
-    {%- for script in page.extra_scripts -%}
-    <script defer src="{{page.root_path | safe}}{{script}}.js"></script> {#- -#}
-    {% endfor %}
-    <noscript> {#- -#}
-        <link rel="stylesheet" {# -#}
-           href="{{static_root_path | safe}}noscript{{page.resource_suffix}}.css"> {#- -#}
-    </noscript> {#- -#}
-    {%- if layout.css_file_extension -%}
-        <link rel="stylesheet" type="text/css" {# -#}
-            href="{{static_root_path | safe}}theme{{page.resource_suffix}}.css"> {#- -#}
-    {%- endif -%}
-    {%- if layout.favicon -%}
-        <link rel="shortcut icon" href="{{layout.favicon}}"> {#- -#}
-    {%- else -%}
-        <link rel="alternate icon" type="image/png" {# -#}
-            href="{{static_root_path | safe}}favicon-16x16{{page.resource_suffix}}.png"> {#- -#}
-        <link rel="alternate icon" type="image/png" {# -#}
-            href="{{static_root_path | safe}}favicon-32x32{{page.resource_suffix}}.png"> {#- -#}
-        <link rel="icon" type="image/svg+xml" {# -#}
-            href="{{static_root_path | safe}}favicon{{page.resource_suffix}}.svg"> {#- -#}
-    {%- endif -%}
-    {{- layout.external_html.in_header | safe -}}
-</head> {#- -#}
-<body class="rustdoc {{page.css_class}}"> {#- -#}
-    <!--[if lte IE 11]> {#- -#}
-    <div class="warning"> {#- -#}
-        This old browser is unsupported and will most likely display funky things. {#- -#}
-    </div> {#- -#}
-    <![endif]--> {#- -#}
-    {{- layout.external_html.before_content | safe -}}
-    <nav class="sidebar"> {#- -#}
-        <div class="sidebar-menu" role="button">&#9776;</div> {#- -#}
-        <a class="sidebar-logo" href="{{page.root_path | safe}}{{krate_with_trailing_slash | safe}}index.html"> {#- -#}
-            <div class="logo-container"> {#- -#}
-            {%- if layout.logo -%}
-                <img src="{{layout.logo}}" alt="logo"> {#- -#}
-            {%- else -%}
-                <img class="rust-logo" src="{{static_root_path | safe}}rust-logo{{page.resource_suffix}}.png" alt="logo"> {#- -#}
-            {%- endif -%}
-            </div>
-        </a> {#- -#}
-        {{- sidebar | safe -}}
-    </nav> {#- -#}
-    <main> {#- -#}
-        <div class="width-limiter"> {#- -#}
-            <div class="sub-container"> {#- -#}
-                <a class="sub-logo-container" href="{{page.root_path | safe}}{{krate_with_trailing_slash | safe}}index.html"> {#- -#}
-                    {%- if layout.logo -%}
-                    <img src="{{layout.logo}}" alt="logo">
-                    {%- else -%}
-                    <img class="rust-logo" src="{{static_root_path | safe}}rust-logo{{page.resource_suffix}}.png" alt="logo">
-                    {%- endif -%}
-                </a> {#- -#}
-                <nav class="sub"> {#- -#}
-                    <div class="theme-picker"> {#- -#}
-                        <button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"> {#- -#}
-                            <img width="18" height="18" alt="Pick another theme!" {# -#}
-                             src="{{static_root_path | safe}}brush{{page.resource_suffix}}.svg"> {#- -#}
-                        </button> {#- -#}
-                        <div id="theme-choices" role="menu"></div> {#- -#}
-                    </div> {#- -#}
-                    <form class="search-form"> {#- -#}
-                        <div class="search-container"> {#- -#}
-                            <div>{%- if layout.generate_search_filter -%}
-                                <select id="crate-search"> {#- -#}
-                                    <option value="All crates">All crates</option> {#- -#}
-                                </select> {#- -#}
-                                {%- endif -%}
-                                <input {# -#}
-                                    class="search-input" {# -#}
-                                    name="search" {# -#}
-                                    autocomplete="off" {# -#}
-                                    spellcheck="false" {# -#}
-                                    placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
-                                    type="search"> {#- -#}
-                            </div> {#- -#}
-                            <button type="button" id="help-button" title="help">?</button> {#- -#}
-                            <a id="settings-menu" href="{{page.root_path | safe}}settings.html" title="settings"> {#- -#}
-                                <img width="18" height="18" alt="Change settings" {# -#}
-                                     src="{{static_root_path | safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
-                            </a> {#- -#}
-                        </div> {#- -#}
-                    </form> {#- -#}
-                </nav> {#- -#}
-            </div> {#- -#}
-            <section id="main-content" class="content">{{- content | safe -}}</section> {#- -#}
-            <section id="search" class="content hidden"></section> {#- -#}
-        </div> {#- -#}
-    </main> {#- -#}
-    {{- layout.external_html.after_content | safe -}}
-    <div id="rustdoc-vars" {# -#}
-         data-root-path="{{page.root_path | safe}}" {# -#}
-         data-current-crate="{{layout.krate}}" {# -#}
-         data-themes="{{themes | join(sep=",") }}" {# -#}
-         data-resource-suffix="{{page.resource_suffix}}" {# -#}
-         data-rustdoc-version="{{rustdoc_version}}" {# -#}
-    > {#- -#}
-    </div>
-</body> {#- -#}
-</html> {#- -#}
diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html
deleted file mode 100644 (file)
index 5a468f3..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-<h1 class="fqn"> {#- -#}
-    <span class="in-band"> {#- -#}
-        {{-typ-}}
-        {#- The breadcrumbs of the item path, like std::string -#}
-        {%- for component in path_components -%}
-        <a href="{{component.path | safe}}index.html">{{component.name}}</a>::<wbr>
-        {%- endfor -%}
-        <a class="{{item_type}}" href="#">{{name}}</a> {#- -#}
-        <button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#}
-            <img src="{{static_root_path | safe}}clipboard{{page.resource_suffix}}.svg" {# -#}
-                width="19" height="18" {# -#}
-                alt="Copy item path"> {#- -#}
-        </button> {#- -#}
-    </span> {#- -#}
-    <span class="out-of-band"> {#- -#}
-        {{- stability_since_raw | safe -}}
-        <span id="render-detail"> {#- -#}
-            <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs"> {#- -#}
-                [<span class="inner">&#x2212;</span>] {#- -#}
-            </a> {#- -#}
-        </span> {#- -#}
-        {%- if src_href -%}
-        <a class="srclink" href="{{src_href | safe}}" title="goto source code">[src]</a>
-        {%- endif -%}
-    </span> {#- -#}
-</h1> {#- -#}
index dee9f5e5038a827242dc48b4332fcd51cdaec604..437d3995e29fca356eb31f085d9f10437496507a 100644 (file)
@@ -1,44 +1,50 @@
 use crate::html::format::href_relative_parts;
+use rustc_span::{sym, Symbol};
 
-fn assert_relative_path(expected: &str, relative_to_fqp: &[&str], fqp: &[&str]) {
-    let relative_to_fqp: Vec<String> = relative_to_fqp.iter().copied().map(String::from).collect();
-    let fqp: Vec<String> = fqp.iter().copied().map(String::from).collect();
-    assert_eq!(expected, href_relative_parts(&fqp, &relative_to_fqp).finish());
+fn assert_relative_path(expected: &[Symbol], relative_to_fqp: &[Symbol], fqp: &[Symbol]) {
+    // No `create_default_session_globals_then` call is needed here because all
+    // the symbols used are static, and no `Symbol::intern` calls occur.
+    assert_eq!(expected, href_relative_parts(&fqp, &relative_to_fqp).collect::<Vec<_>>());
 }
 
 #[test]
 fn href_relative_parts_basic() {
-    let relative_to_fqp = &["std", "vec"];
-    let fqp = &["std", "iter"];
-    assert_relative_path("../iter", relative_to_fqp, fqp);
+    let relative_to_fqp = &[sym::std, sym::vec];
+    let fqp = &[sym::std, sym::iter];
+    assert_relative_path(&[sym::dotdot, sym::iter], relative_to_fqp, fqp);
 }
+
 #[test]
 fn href_relative_parts_parent_module() {
-    let relative_to_fqp = &["std", "vec"];
-    let fqp = &["std"];
-    assert_relative_path("..", relative_to_fqp, fqp);
+    let relative_to_fqp = &[sym::std, sym::vec];
+    let fqp = &[sym::std];
+    assert_relative_path(&[sym::dotdot], relative_to_fqp, fqp);
 }
+
 #[test]
 fn href_relative_parts_different_crate() {
-    let relative_to_fqp = &["std", "vec"];
-    let fqp = &["core", "iter"];
-    assert_relative_path("../../core/iter", relative_to_fqp, fqp);
+    let relative_to_fqp = &[sym::std, sym::vec];
+    let fqp = &[sym::core, sym::iter];
+    assert_relative_path(&[sym::dotdot, sym::dotdot, sym::core, sym::iter], relative_to_fqp, fqp);
 }
+
 #[test]
 fn href_relative_parts_same_module() {
-    let relative_to_fqp = &["std", "vec"];
-    let fqp = &["std", "vec"];
-    assert_relative_path("", relative_to_fqp, fqp);
+    let relative_to_fqp = &[sym::std, sym::vec];
+    let fqp = &[sym::std, sym::vec];
+    assert_relative_path(&[], relative_to_fqp, fqp);
 }
+
 #[test]
 fn href_relative_parts_child_module() {
-    let relative_to_fqp = &["std"];
-    let fqp = &["std", "vec"];
-    assert_relative_path("vec", relative_to_fqp, fqp);
+    let relative_to_fqp = &[sym::std];
+    let fqp = &[sym::std, sym::vec];
+    assert_relative_path(&[sym::vec], relative_to_fqp, fqp);
 }
+
 #[test]
 fn href_relative_parts_root() {
     let relative_to_fqp = &[];
-    let fqp = &["std"];
-    assert_relative_path("std", relative_to_fqp, fqp);
+    let fqp = &[sym::std];
+    assert_relative_path(&[sym::std], relative_to_fqp, fqp);
 }
index 918d5e6bd1b3a3da274d920dfd089f3906b6b866..2bb78aa7dc9c074310397db957e2ad7b4c2bf7c3 100644 (file)
@@ -1,3 +1,7 @@
+use std::fmt::{self, Write};
+
+use rustc_span::Symbol;
+
 /// A builder that allows efficiently and easily constructing the part of a URL
 /// after the domain: `nightly/core/str/struct.Bytes.html`.
 ///
@@ -10,6 +14,7 @@
 
 impl UrlPartsBuilder {
     /// Create an empty buffer.
+    #[allow(dead_code)]
     crate fn new() -> Self {
         Self { buf: String::new() }
     }
@@ -62,6 +67,26 @@ fn with_capacity_bytes(count: usize) -> Self {
         self.buf.push_str(part);
     }
 
+    /// Push a component onto the buffer, using [`format!`]'s formatting syntax.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage (equivalent to the example for [`UrlPartsBuilder::push`]):
+    ///
+    /// ```ignore (private-type)
+    /// let mut builder = UrlPartsBuilder::new();
+    /// builder.push("core");
+    /// builder.push("str");
+    /// builder.push_fmt(format_args!("{}.{}.html", "struct", "Bytes"));
+    /// assert_eq!(builder.finish(), "core/str/struct.Bytes.html");
+    /// ```
+    crate fn push_fmt(&mut self, args: fmt::Arguments<'_>) {
+        if !self.buf.is_empty() {
+            self.buf.push('/');
+        }
+        self.buf.write_fmt(args).unwrap()
+    }
+
     /// Push a component onto the front of the buffer.
     ///
     /// # Examples
@@ -93,10 +118,25 @@ fn with_capacity_bytes(count: usize) -> Self {
 
 /// This is just a guess at the average length of a URL part,
 /// used for [`String::with_capacity`] calls in the [`FromIterator`]
-/// and [`Extend`] impls.
+/// and [`Extend`] impls, and for [estimating item path lengths].
 ///
-/// This is intentionally on the lower end to avoid overallocating.
-const AVG_PART_LENGTH: usize = 5;
+/// The value `8` was chosen for two main reasons:
+///
+/// * It seems like a good guess for the average part length.
+/// * jemalloc's size classes are all multiples of eight,
+///   which means that the amount of memory it allocates will often match
+///   the amount requested, avoiding wasted bytes.
+///
+/// [estimating item path lengths]: estimate_item_path_byte_length
+const AVG_PART_LENGTH: usize = 8;
+
+/// Estimate the number of bytes in an item's path, based on how many segments it has.
+///
+/// **Note:** This is only to be used with, e.g., [`String::with_capacity()`];
+/// the return value is just a rough estimate.
+crate const fn estimate_item_path_byte_length(segment_count: usize) -> usize {
+    AVG_PART_LENGTH * segment_count
+}
 
 impl<'a> FromIterator<&'a str> for UrlPartsBuilder {
     fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
@@ -115,5 +155,26 @@ fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
     }
 }
 
+impl FromIterator<Symbol> for UrlPartsBuilder {
+    fn from_iter<T: IntoIterator<Item = Symbol>>(iter: T) -> Self {
+        // This code has to be duplicated from the `&str` impl because of
+        // `Symbol::as_str`'s lifetimes.
+        let iter = iter.into_iter();
+        let mut builder = Self::with_capacity_bytes(AVG_PART_LENGTH * iter.size_hint().0);
+        iter.for_each(|part| builder.push(part.as_str()));
+        builder
+    }
+}
+
+impl Extend<Symbol> for UrlPartsBuilder {
+    fn extend<T: IntoIterator<Item = Symbol>>(&mut self, iter: T) {
+        // This code has to be duplicated from the `&str` impl because of
+        // `Symbol::as_str`'s lifetimes.
+        let iter = iter.into_iter();
+        self.buf.reserve(AVG_PART_LENGTH * iter.size_hint().0);
+        iter.for_each(|part| self.push(part.as_str()));
+    }
+}
+
 #[cfg(test)]
 mod tests;
index 43338c95010a0cb01538d4d7161d4d6cf2e23df7..636e1ab55279f995644b8f49e619503eb8218c3e 100644 (file)
@@ -40,6 +40,16 @@ fn push_front_non_empty() {
     t(builder, "nightly/core/str/struct.Bytes.html");
 }
 
+#[test]
+fn push_fmt() {
+    let mut builder = UrlPartsBuilder::new();
+    builder.push_fmt(format_args!("{}", "core"));
+    builder.push("str");
+    builder.push_front("nightly");
+    builder.push_fmt(format_args!("{}.{}.html", "struct", "Bytes"));
+    t(builder, "nightly/core/str/struct.Bytes.html");
+}
+
 #[test]
 fn collect() {
     t(["core", "str"].into_iter().collect(), "core/str");
index 88a5c0c5ca260530be521957348127cb02c16f09..81fbfd9fdbd166da4619f6c7277671343076e531 100644 (file)
@@ -120,7 +120,7 @@ fn get_trait_items(&mut self) -> Vec<(types::Id, types::Item)> {
                                 })
                                 .0
                                 .last()
-                                .map(Clone::clone),
+                                .map(|s| s.to_string()),
                             visibility: types::Visibility::Public,
                             inner: types::ItemEnum::Trait(trait_item.clone().into_tcx(self.tcx)),
                             span: None,
@@ -230,7 +230,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
                         from_item_id(k.into()),
                         types::ItemSummary {
                             crate_id: k.krate.as_u32(),
-                            path,
+                            path: path.iter().map(|s| s.to_string()).collect(),
                             kind: kind.into_tcx(self.tcx),
                         },
                     )
index 014ac484dcfaec553a34f87d375ed6b9f882d86b..a647a0fbfa55d52d213310635d86bab5b0842f5d 100644 (file)
@@ -18,6 +18,7 @@
 #![feature(iter_intersperse)]
 #![recursion_limit = "256"]
 #![warn(rustc::internal)]
+#![allow(clippy::collapsible_if, clippy::collapsible_else_if)]
 
 #[macro_use]
 extern crate tracing;
@@ -82,6 +83,7 @@
 use rustc_session::{early_error, early_warn};
 
 use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
+use crate::passes::collect_intra_doc_links;
 
 /// A macro to create a FxHashMap.
 ///
@@ -798,7 +800,15 @@ fn main_options(options: config::Options) -> MainResult {
             // We need to hold on to the complete resolver, so we cause everything to be
             // cloned for the analysis passes to use. Suboptimal, but necessary in the
             // current architecture.
-            let resolver = core::create_resolver(externs, queries, sess);
+            // FIXME(#83761): Resolver cloning can lead to inconsistencies between data in the
+            // two copies because one of the copies can be modified after `TyCtxt` construction.
+            let (resolver, resolver_caches) = {
+                let (krate, resolver, _) = &*abort_on_err(queries.expansion(), sess).peek();
+                let resolver_caches = resolver.borrow_mut().access(|resolver| {
+                    collect_intra_doc_links::early_resolve_intra_doc_links(resolver, krate, externs)
+                });
+                (resolver.clone(), resolver_caches)
+            };
 
             if sess.diagnostic().has_errors_or_lint_errors() {
                 sess.fatal("Compilation failed, aborting rustdoc");
@@ -811,6 +821,7 @@ fn main_options(options: config::Options) -> MainResult {
                     core::run_global_ctxt(
                         tcx,
                         resolver,
+                        resolver_caches,
                         show_coverage,
                         render_options,
                         output_format,
index b86ec8abefaaea8e242b16cc79d4362ae32b8804..e8f8ff988c1f0233b7db810c0e1f045491880092 100644 (file)
@@ -131,7 +131,7 @@ fn add_test(&mut self, _: String, config: LangString, _: usize) {
             );
         }
     } else if tests.found_tests > 0
-        && !cx.cache.access_levels.is_public(item.def_id.expect_def_id())
+        && !cx.cache.access_levels.is_exported(item.def_id.expect_def_id())
     {
         cx.tcx.struct_span_lint_hir(
             crate::lint::PRIVATE_DOC_TESTS,
index 26ccdb1c87eccc4f70d2072813325efd196cc8c5..af62232e792acd057378e08abd96ac6943964555 100644 (file)
@@ -13,7 +13,7 @@
     PerNS,
 };
 use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug, ty};
 use rustc_resolve::ParentScope;
 use rustc_session::lint::Lint;
@@ -25,8 +25,8 @@
 use pulldown_cmark::LinkType;
 
 use std::borrow::Cow;
-use std::cell::Cell;
 use std::convert::{TryFrom, TryInto};
+use std::fmt::Write;
 use std::mem;
 use std::ops::Range;
 
@@ -38,7 +38,7 @@
 use crate::visit::DocVisitor;
 
 mod early;
-crate use early::load_intra_link_crates;
+crate use early::early_resolve_intra_doc_links;
 
 crate const COLLECT_INTRA_DOC_LINKS: Pass = Pass {
     name: "collect-intra-doc-links",
 };
 
 fn collect_intra_doc_links(krate: Crate, cx: &mut DocContext<'_>) -> Crate {
-    let mut collector = LinkCollector {
-        cx,
-        mod_ids: Vec::new(),
-        kind_side_channel: Cell::new(None),
-        visited_links: FxHashMap::default(),
-    };
+    let mut collector =
+        LinkCollector { cx, mod_ids: Vec::new(), visited_links: FxHashMap::default() };
     collector.visit_crate(&krate);
     krate
 }
@@ -240,53 +236,73 @@ enum AnchorFailure {
 
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
 crate enum UrlFragment {
-    Method(Symbol),
-    TyMethod(Symbol),
-    AssociatedConstant(Symbol),
-    AssociatedType(Symbol),
-
-    StructField(Symbol),
-    Variant(Symbol),
-    VariantField { variant: Symbol, field: Symbol },
-
+    Item(ItemFragment),
     UserWritten(String),
 }
 
 impl UrlFragment {
+    /// Render the fragment, including the leading `#`.
+    crate fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result {
+        match self {
+            UrlFragment::Item(frag) => frag.render(s, tcx),
+            UrlFragment::UserWritten(raw) => write!(s, "#{}", raw),
+        }
+    }
+}
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+crate struct ItemFragment(FragmentKind, DefId);
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+crate enum FragmentKind {
+    Method,
+    TyMethod,
+    AssociatedConstant,
+    AssociatedType,
+
+    StructField,
+    Variant,
+    VariantField,
+}
+
+impl ItemFragment {
     /// Create a fragment for an associated item.
     ///
     /// `is_prototype` is whether this associated item is a trait method
     /// without a default definition.
-    fn from_assoc_item(name: Symbol, kind: ty::AssocKind, is_prototype: bool) -> Self {
+    fn from_assoc_item(def_id: DefId, kind: ty::AssocKind, is_prototype: bool) -> Self {
         match kind {
             ty::AssocKind::Fn => {
                 if is_prototype {
-                    UrlFragment::TyMethod(name)
+                    ItemFragment(FragmentKind::TyMethod, def_id)
                 } else {
-                    UrlFragment::Method(name)
+                    ItemFragment(FragmentKind::Method, def_id)
                 }
             }
-            ty::AssocKind::Const => UrlFragment::AssociatedConstant(name),
-            ty::AssocKind::Type => UrlFragment::AssociatedType(name),
+            ty::AssocKind::Const => ItemFragment(FragmentKind::AssociatedConstant, def_id),
+            ty::AssocKind::Type => ItemFragment(FragmentKind::AssociatedType, def_id),
         }
     }
-}
 
-/// Render the fragment, including the leading `#`.
-impl std::fmt::Display for UrlFragment {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(f, "#")?;
-        match self {
-            UrlFragment::Method(name) => write!(f, "method.{}", name),
-            UrlFragment::TyMethod(name) => write!(f, "tymethod.{}", name),
-            UrlFragment::AssociatedConstant(name) => write!(f, "associatedconstant.{}", name),
-            UrlFragment::AssociatedType(name) => write!(f, "associatedtype.{}", name),
-            UrlFragment::StructField(name) => write!(f, "structfield.{}", name),
-            UrlFragment::Variant(name) => write!(f, "variant.{}", name),
-            UrlFragment::VariantField { variant, field } => {
-                write!(f, "variant.{}.field.{}", variant, field)
+    /// Render the fragment, including the leading `#`.
+    crate fn render(&self, s: &mut String, tcx: TyCtxt<'_>) -> std::fmt::Result {
+        write!(s, "#")?;
+        match *self {
+            ItemFragment(kind, def_id) => {
+                let name = tcx.item_name(def_id);
+                match kind {
+                    FragmentKind::Method => write!(s, "method.{}", name),
+                    FragmentKind::TyMethod => write!(s, "tymethod.{}", name),
+                    FragmentKind::AssociatedConstant => write!(s, "associatedconstant.{}", name),
+                    FragmentKind::AssociatedType => write!(s, "associatedtype.{}", name),
+                    FragmentKind::StructField => write!(s, "structfield.{}", name),
+                    FragmentKind::Variant => write!(s, "variant.{}", name),
+                    FragmentKind::VariantField => {
+                        let variant = tcx.item_name(tcx.parent(def_id).unwrap());
+                        write!(s, "variant.{}.field.{}", variant, name)
+                    }
+                }
             }
-            UrlFragment::UserWritten(raw) => write!(f, "{}", raw),
         }
     }
 }
@@ -296,7 +312,7 @@ struct ResolutionInfo {
     module_id: DefId,
     dis: Option<Disambiguator>,
     path_str: String,
-    extra_fragment: Option<UrlFragment>,
+    extra_fragment: Option<String>,
 }
 
 #[derive(Clone)]
@@ -310,7 +326,6 @@ struct DiagnosticInfo<'a> {
 #[derive(Clone, Debug, Hash)]
 struct CachedLink {
     pub res: (Res, Option<UrlFragment>),
-    pub side_channel: Option<(DefKind, DefId)>,
 }
 
 struct LinkCollector<'a, 'tcx> {
@@ -320,10 +335,6 @@ struct LinkCollector<'a, 'tcx> {
     /// The last module will be used if the parent scope of the current item is
     /// unknown.
     mod_ids: Vec<DefId>,
-    /// This is used to store the kind of associated items,
-    /// because `clean` and the disambiguator code expect them to be different.
-    /// See the code for associated items on inherent impls for details.
-    kind_side_channel: Cell<Option<(DefKind, DefId)>>,
     /// Cache the resolved links so we can avoid resolving (and emitting errors for) the same link.
     /// The link will be `None` if it could not be resolved (i.e. the error was cached).
     visited_links: FxHashMap<ResolutionInfo, Option<CachedLink>>,
@@ -340,7 +351,7 @@ fn variant_field<'path>(
         &self,
         path_str: &'path str,
         module_id: DefId,
-    ) -> Result<(Res, Option<UrlFragment>), ErrorKind<'path>> {
+    ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
         let tcx = self.cx.tcx;
         let no_res = || ResolutionFailure::NotResolved {
             module_id,
@@ -387,14 +398,10 @@ fn variant_field<'path>(
                 }
                 match tcx.type_of(did).kind() {
                     ty::Adt(def, _) if def.is_enum() => {
-                        if def.all_fields().any(|item| item.ident.name == variant_field_name) {
-                            Ok((
-                                ty_res,
-                                Some(UrlFragment::VariantField {
-                                    variant: variant_name,
-                                    field: variant_field_name,
-                                }),
-                            ))
+                        if let Some(field) =
+                            def.all_fields().find(|f| f.ident(tcx).name == variant_field_name)
+                        {
+                            Ok((ty_res, Some(ItemFragment(FragmentKind::VariantField, field.did))))
                         } else {
                             Err(ResolutionFailure::NotResolved {
                                 module_id,
@@ -422,7 +429,7 @@ fn resolve_primitive_associated_item(
         prim_ty: PrimitiveType,
         ns: Namespace,
         item_name: Symbol,
-    ) -> Option<(Res, UrlFragment, Option<(DefKind, DefId)>)> {
+    ) -> Option<(Res, ItemFragment)> {
         let tcx = self.cx.tcx;
 
         prim_ty.impls(tcx).into_iter().find_map(|&impl_| {
@@ -430,8 +437,8 @@ fn resolve_primitive_associated_item(
                 .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_)
                 .map(|item| {
                     let kind = item.kind;
-                    let fragment = UrlFragment::from_assoc_item(item_name, kind, false);
-                    (Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id)))
+                    let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
+                    (Res::Primitive(prim_ty), fragment)
                 })
         })
     }
@@ -505,8 +512,30 @@ fn resolve<'path>(
         path_str: &'path str,
         ns: Namespace,
         module_id: DefId,
-        extra_fragment: &Option<UrlFragment>,
+        user_fragment: &Option<String>,
     ) -> Result<(Res, Option<UrlFragment>), ErrorKind<'path>> {
+        let (res, rustdoc_fragment) = self.resolve_inner(path_str, ns, module_id)?;
+        let chosen_fragment = match (user_fragment, rustdoc_fragment) {
+            (Some(_), Some(r_frag)) => {
+                let diag_res = match r_frag {
+                    ItemFragment(_, did) => Res::Def(self.cx.tcx.def_kind(did), did),
+                };
+                let failure = AnchorFailure::RustdocAnchorConflict(diag_res);
+                return Err(ErrorKind::AnchorFailure(failure));
+            }
+            (Some(u_frag), None) => Some(UrlFragment::UserWritten(u_frag.clone())),
+            (None, Some(r_frag)) => Some(UrlFragment::Item(r_frag)),
+            (None, None) => None,
+        };
+        Ok((res, chosen_fragment))
+    }
+
+    fn resolve_inner<'path>(
+        &mut self,
+        path_str: &'path str,
+        ns: Namespace,
+        module_id: DefId,
+    ) -> Result<(Res, Option<ItemFragment>), ErrorKind<'path>> {
         if let Some(res) = self.resolve_path(path_str, ns, module_id) {
             match res {
                 // FIXME(#76467): make this fallthrough to lookup the associated
@@ -514,10 +543,10 @@ fn resolve<'path>(
                 Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => assert_eq!(ns, ValueNS),
                 Res::Def(DefKind::AssocTy, _) => assert_eq!(ns, TypeNS),
                 Res::Def(DefKind::Variant, _) => {
-                    return handle_variant(self.cx, res, extra_fragment);
+                    return handle_variant(self.cx, res);
                 }
                 // Not a trait item; just return what we found.
-                _ => return Ok((res, extra_fragment.clone())),
+                _ => return Ok((res, None)),
             }
         }
 
@@ -548,23 +577,10 @@ fn resolve<'path>(
         resolve_primitive(&path_root, TypeNS)
             .or_else(|| self.resolve_path(&path_root, TypeNS, module_id))
             .and_then(|ty_res| {
-                let (res, fragment, side_channel) =
+                let (res, fragment) =
                     self.resolve_associated_item(ty_res, item_name, ns, module_id)?;
-                let result = if extra_fragment.is_some() {
-                    // NOTE: can never be a primitive since `side_channel.is_none()` only when `res`
-                    // is a trait (and the side channel DefId is always an associated item).
-                    let diag_res = side_channel.map_or(res, |(k, r)| Res::Def(k, r));
-                    Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(diag_res)))
-                } else {
-                    // HACK(jynelson): `clean` expects the type, not the associated item
-                    // but the disambiguator logic expects the associated item.
-                    // Store the kind in a side channel so that only the disambiguator logic looks at it.
-                    if let Some((kind, id)) = side_channel {
-                        self.kind_side_channel.set(Some((kind, id)));
-                    }
-                    Ok((res, Some(fragment)))
-                };
-                Some(result)
+
+                Some(Ok((res, Some(fragment))))
             })
             .unwrap_or_else(|| {
                 if ns == Namespace::ValueNS {
@@ -618,6 +634,39 @@ fn def_id_to_res(&self, ty_id: DefId) -> Option<Res> {
         })
     }
 
+    /// Convert a PrimitiveType to a Ty, where possible.
+    ///
+    /// This is used for resolving trait impls for primitives
+    fn primitive_type_to_ty(&mut self, prim: PrimitiveType) -> Option<Ty<'tcx>> {
+        use PrimitiveType::*;
+        let tcx = self.cx.tcx;
+
+        // FIXME: Only simple types are supported here, see if we can support
+        // other types such as Tuple, Array, Slice, etc.
+        // See https://github.com/rust-lang/rust/issues/90703#issuecomment-1004263455
+        Some(tcx.mk_ty(match prim {
+            Bool => ty::Bool,
+            Str => ty::Str,
+            Char => ty::Char,
+            Never => ty::Never,
+            I8 => ty::Int(ty::IntTy::I8),
+            I16 => ty::Int(ty::IntTy::I16),
+            I32 => ty::Int(ty::IntTy::I32),
+            I64 => ty::Int(ty::IntTy::I64),
+            I128 => ty::Int(ty::IntTy::I128),
+            Isize => ty::Int(ty::IntTy::Isize),
+            F32 => ty::Float(ty::FloatTy::F32),
+            F64 => ty::Float(ty::FloatTy::F64),
+            U8 => ty::Uint(ty::UintTy::U8),
+            U16 => ty::Uint(ty::UintTy::U16),
+            U32 => ty::Uint(ty::UintTy::U32),
+            U64 => ty::Uint(ty::UintTy::U64),
+            U128 => ty::Uint(ty::UintTy::U128),
+            Usize => ty::Uint(ty::UintTy::Usize),
+            _ => return None,
+        }))
+    }
+
     /// Returns:
     /// - None if no associated item was found
     /// - Some((_, _, Some(_))) if an item was found and should go through a side channel
@@ -628,11 +677,26 @@ fn resolve_associated_item(
         item_name: Symbol,
         ns: Namespace,
         module_id: DefId,
-    ) -> Option<(Res, UrlFragment, Option<(DefKind, DefId)>)> {
+    ) -> Option<(Res, ItemFragment)> {
         let tcx = self.cx.tcx;
 
         match root_res {
-            Res::Primitive(prim) => self.resolve_primitive_associated_item(prim, ns, item_name),
+            Res::Primitive(prim) => {
+                self.resolve_primitive_associated_item(prim, ns, item_name).or_else(|| {
+                    let assoc_item = self
+                        .primitive_type_to_ty(prim)
+                        .map(|ty| {
+                            resolve_associated_trait_item(ty, module_id, item_name, ns, self.cx)
+                        })
+                        .flatten();
+
+                    assoc_item.map(|item| {
+                        let kind = item.kind;
+                        let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
+                        (root_res, fragment)
+                    })
+                })
+            }
             Res::Def(DefKind::TyAlias, did) => {
                 // Resolve the link on the type the alias points to.
                 // FIXME: if the associated item is defined directly on the type alias,
@@ -666,19 +730,21 @@ fn resolve_associated_item(
                     // To handle that properly resolve() would have to support
                     // something like [`ambi_fn`](<SomeStruct as SomeTrait>::ambi_fn)
                     .or_else(|| {
-                        let item =
-                            resolve_associated_trait_item(did, module_id, item_name, ns, self.cx);
+                        let item = resolve_associated_trait_item(
+                            tcx.type_of(did),
+                            module_id,
+                            item_name,
+                            ns,
+                            self.cx,
+                        );
                         debug!("got associated item {:?}", item);
                         item
                     });
 
                 if let Some(item) = assoc_item {
                     let kind = item.kind;
-                    let fragment = UrlFragment::from_assoc_item(item_name, kind, false);
-                    // HACK(jynelson): `clean` expects the type, not the associated item
-                    // but the disambiguator logic expects the associated item.
-                    // Store the kind in a side channel so that only the disambiguator logic looks at it.
-                    return Some((root_res, fragment, Some((kind.as_def_kind(), item.def_id))));
+                    let fragment = ItemFragment::from_assoc_item(item.def_id, kind, false);
+                    return Some((root_res, fragment));
                 }
 
                 if ns != Namespace::ValueNS {
@@ -708,24 +774,20 @@ fn resolve_associated_item(
                     .non_enum_variant()
                     .fields
                     .iter()
-                    .find(|item| item.ident.name == item_name)?;
-                Some((
-                    root_res,
-                    UrlFragment::StructField(field.ident.name),
-                    Some((DefKind::Field, field.did)),
-                ))
+                    .find(|item| item.ident(tcx).name == item_name)?;
+                Some((root_res, ItemFragment(FragmentKind::StructField, field.did)))
             }
             Res::Def(DefKind::Trait, did) => tcx
                 .associated_items(did)
                 .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, did)
                 .map(|item| {
-                    let fragment = UrlFragment::from_assoc_item(
-                        item_name,
+                    let fragment = ItemFragment::from_assoc_item(
+                        item.def_id,
                         item.kind,
                         !item.defaultness.has_value(),
                     );
                     let res = Res::Def(item.kind.as_def_kind(), item.def_id);
-                    (res, fragment, None)
+                    (res, fragment)
                 }),
             _ => None,
         }
@@ -742,23 +804,32 @@ fn check_full_res(
         ns: Namespace,
         path_str: &str,
         module_id: DefId,
-        extra_fragment: &Option<UrlFragment>,
+        extra_fragment: &Option<String>,
     ) -> Option<Res> {
         // resolve() can't be used for macro namespace
         let result = match ns {
-            Namespace::MacroNS => self.resolve_macro(path_str, module_id).map_err(ErrorKind::from),
+            Namespace::MacroNS => self
+                .resolve_macro(path_str, module_id)
+                .map(|res| (res, None))
+                .map_err(ErrorKind::from),
             Namespace::TypeNS | Namespace::ValueNS => {
-                self.resolve(path_str, ns, module_id, extra_fragment).map(|(res, _)| res)
+                self.resolve(path_str, ns, module_id, extra_fragment)
             }
         };
 
         let res = match result {
-            Ok(res) => Some(res),
+            Ok((res, frag)) => {
+                if let Some(UrlFragment::Item(ItemFragment(_, id))) = frag {
+                    Some(Res::Def(self.cx.tcx.def_kind(id), id))
+                } else {
+                    Some(res)
+                }
+            }
             Err(ErrorKind::Resolve(box kind)) => kind.full_res(),
             Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => Some(res),
             Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None,
         };
-        self.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res)
+        res
     }
 }
 
@@ -767,12 +838,12 @@ fn check_full_res(
 /// Given `[std::io::Error::source]`, where `source` is unresolved, this would
 /// find `std::error::Error::source` and return
 /// `<io::Error as error::Error>::source`.
-fn resolve_associated_trait_item(
-    did: DefId,
+fn resolve_associated_trait_item<'a>(
+    ty: Ty<'a>,
     module: DefId,
     item_name: Symbol,
     ns: Namespace,
-    cx: &mut DocContext<'_>,
+    cx: &mut DocContext<'a>,
 ) -> Option<ty::AssocItem> {
     // FIXME: this should also consider blanket impls (`impl<T> X for T`). Unfortunately
     // `get_auto_trait_and_blanket_impls` is broken because the caching behavior is wrong. In the
@@ -780,7 +851,7 @@ fn resolve_associated_trait_item(
 
     // Next consider explicit impls: `impl MyTrait for MyType`
     // Give precedence to inherent impls.
-    let traits = traits_implemented_by(cx, did, module);
+    let traits = traits_implemented_by(cx, ty, module);
     debug!("considering traits {:?}", traits);
     let mut candidates = traits.iter().filter_map(|&trait_| {
         cx.tcx.associated_items(trait_).find_by_name_and_namespace(
@@ -799,7 +870,11 @@ fn resolve_associated_trait_item(
 ///
 /// NOTE: this cannot be a query because more traits could be available when more crates are compiled!
 /// So it is not stable to serialize cross-crate.
-fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -> FxHashSet<DefId> {
+fn traits_implemented_by<'a>(
+    cx: &mut DocContext<'a>,
+    ty: Ty<'a>,
+    module: DefId,
+) -> FxHashSet<DefId> {
     let mut resolver = cx.resolver.borrow_mut();
     let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| {
         resolver.access(|resolver| {
@@ -813,7 +888,6 @@ fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -
     });
 
     let tcx = cx.tcx;
-    let ty = tcx.type_of(type_);
     let iter = in_scope_traits.iter().flat_map(|&trait_| {
         trace!("considering explicit impl for trait {:?}", trait_);
 
@@ -826,19 +900,10 @@ fn traits_implemented_by(cx: &mut DocContext<'_>, type_: DefId, module: DefId) -
                 "comparing type {} with kind {:?} against type {:?}",
                 impl_type,
                 impl_type.kind(),
-                type_
+                ty
             );
             // Fast path: if this is a primitive simple `==` will work
-            let saw_impl = impl_type == ty
-                || match impl_type.kind() {
-                    // Check if these are the same def_id
-                    ty::Adt(def, _) => {
-                        debug!("adt def_id: {:?}", def.did);
-                        def.did == type_
-                    }
-                    ty::Foreign(def_id) => *def_id == type_,
-                    _ => false,
-                };
+            let saw_impl = impl_type == ty;
 
             if saw_impl { Some(trait_) } else { None }
         })
@@ -862,8 +927,6 @@ fn is_derive_trait_collision<T>(ns: &PerNS<Result<(Res, T), ResolutionFailure<'_
 
 impl<'a, 'tcx> DocVisitor for LinkCollector<'a, 'tcx> {
     fn visit_item(&mut self, item: &Item) {
-        use rustc_middle::ty::DefIdTree;
-
         let parent_node =
             item.def_id.as_def_id().and_then(|did| find_nearest_parent_module(self.cx.tcx, did));
         if parent_node.is_some() {
@@ -983,7 +1046,7 @@ fn from(err: AnchorFailure) -> Self {
 struct PreprocessingInfo {
     path_str: String,
     disambiguator: Option<Disambiguator>,
-    extra_fragment: Option<UrlFragment>,
+    extra_fragment: Option<String>,
     link_text: String,
 }
 
@@ -1069,7 +1132,7 @@ fn preprocess_link<'a>(
     Some(Ok(PreprocessingInfo {
         path_str,
         disambiguator,
-        extra_fragment: extra_fragment.map(|frag| UrlFragment::UserWritten(frag.to_owned())),
+        extra_fragment: extra_fragment.map(|frag| frag.to_owned()),
         link_text: link_text.to_owned(),
     }))
 }
@@ -1236,7 +1299,11 @@ fn resolve_link(
         };
 
         let verify = |kind: DefKind, id: DefId| {
-            let (kind, id) = self.kind_side_channel.take().unwrap_or((kind, id));
+            let (kind, id) = if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
+                (self.cx.tcx.def_kind(id), id)
+            } else {
+                (kind, id)
+            };
             debug!("intra-doc link to {} resolved to {:?} (id: {:?})", path_str, res, id);
 
             // Disallow e.g. linking to enums with `struct@`
@@ -1280,7 +1347,9 @@ fn resolve_link(
 
         match res {
             Res::Primitive(prim) => {
-                if let Some((kind, id)) = self.kind_side_channel.take() {
+                if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
+                    let kind = self.cx.tcx.def_kind(id);
+
                     // We're actually resolving an associated item of a primitive, so we need to
                     // verify the disambiguator (if any) matches the type of the associated item.
                     // This case should really follow the same flow as the `Res::Def` branch below,
@@ -1297,22 +1366,7 @@ fn resolve_link(
                         && item.def_id.is_local()
                         && !self.cx.tcx.features().intra_doc_pointers
                     {
-                        let span = super::source_span_for_markdown_range(
-                            self.cx.tcx,
-                            dox,
-                            &ori_link.range,
-                            &item.attrs,
-                        )
-                        .unwrap_or_else(|| item.attr_span(self.cx.tcx));
-
-                        rustc_session::parse::feature_err(
-                            &self.cx.tcx.sess.parse_sess,
-                            sym::intra_doc_pointers,
-                            span,
-                            "linking to associated items of raw pointers is experimental",
-                        )
-                        .note("rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does")
-                        .emit();
+                        self.report_rawptr_assoc_feature_gate(dox, &ori_link, item);
                     }
                 } else {
                     match disambiguator {
@@ -1339,6 +1393,20 @@ fn resolve_link(
         }
     }
 
+    fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &MarkdownLink, item: &Item) {
+        let span =
+            super::source_span_for_markdown_range(self.cx.tcx, dox, &ori_link.range, &item.attrs)
+                .unwrap_or_else(|| item.attr_span(self.cx.tcx));
+        rustc_session::parse::feature_err(
+            &self.cx.tcx.sess.parse_sess,
+            sym::intra_doc_pointers,
+            span,
+            "linking to associated items of raw pointers is experimental",
+        )
+        .note("rustdoc does not allow disambiguating between `*const` and `*mut`, and pointers are unstable until it does")
+        .emit();
+    }
+
     fn resolve_with_disambiguator_cached(
         &mut self,
         key: ResolutionInfo,
@@ -1349,7 +1417,6 @@ fn resolve_with_disambiguator_cached(
         if let Some(ref cached) = self.visited_links.get(&key) {
             match cached {
                 Some(cached) => {
-                    self.kind_side_channel.set(cached.side_channel);
                     return Some(cached.res.clone());
                 }
                 None if cache_resolution_failure => return None,
@@ -1366,13 +1433,7 @@ fn resolve_with_disambiguator_cached(
         // Cache only if resolved successfully - don't silence duplicate errors
         if let Some(res) = res {
             // Store result for the actual namespace
-            self.visited_links.insert(
-                key,
-                Some(CachedLink {
-                    res: res.clone(),
-                    side_channel: self.kind_side_channel.clone().into_inner(),
-                }),
-            );
+            self.visited_links.insert(key, Some(CachedLink { res: res.clone() }));
 
             Some(res)
         } else {
@@ -1434,7 +1495,7 @@ fn resolve_with_disambiguator(
                 let mut candidates = PerNS {
                     macro_ns: self
                         .resolve_macro(path_str, base_node)
-                        .map(|res| (res, extra_fragment.clone())),
+                        .map(|res| (res, extra_fragment.clone().map(UrlFragment::UserWritten))),
                     type_ns: match self.resolve(path_str, TypeNS, base_node, extra_fragment) {
                         Ok(res) => {
                             debug!("got res in TypeNS: {:?}", res);
@@ -1466,7 +1527,10 @@ fn resolve_with_disambiguator(
                                         // Shouldn't happen but who knows?
                                         Ok((res, Some(fragment)))
                                     }
-                                    (fragment, None) | (None, fragment) => Ok((res, fragment)),
+                                    (fragment, None) => Ok((res, fragment)),
+                                    (None, fragment) => {
+                                        Ok((res, fragment.map(UrlFragment::UserWritten)))
+                                    }
                                 }
                             }
                         }
@@ -1503,7 +1567,7 @@ fn resolve_with_disambiguator(
             }
             Some(MacroNS) => {
                 match self.resolve_macro(path_str, base_node) {
-                    Ok(res) => Some((res, extra_fragment.clone())),
+                    Ok(res) => Some((res, extra_fragment.clone().map(UrlFragment::UserWritten))),
                     Err(mut kind) => {
                         // `resolve_macro` only looks in the macro namespace. Try to give a better error if possible.
                         for ns in [TypeNS, ValueNS] {
@@ -2222,20 +2286,13 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str:
 fn handle_variant(
     cx: &DocContext<'_>,
     res: Res,
-    extra_fragment: &Option<UrlFragment>,
-) -> Result<(Res, Option<UrlFragment>), ErrorKind<'static>> {
-    use rustc_middle::ty::DefIdTree;
-
-    if extra_fragment.is_some() {
-        // NOTE: `res` can never be a primitive since this function is only called when `tcx.def_kind(res) == DefKind::Variant`.
-        return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res)));
-    }
+) -> Result<(Res, Option<ItemFragment>), ErrorKind<'static>> {
     cx.tcx
         .parent(res.def_id(cx.tcx))
         .map(|parent| {
             let parent_def = Res::Def(DefKind::Enum, parent);
             let variant = cx.tcx.expect_variant_res(res.as_hir_res().unwrap());
-            (parent_def, Some(UrlFragment::Variant(variant.ident.name)))
+            (parent_def, Some(ItemFragment(FragmentKind::Variant, variant.def_id)))
         })
         .ok_or_else(|| ResolutionFailure::NoParentItem.into())
 }
index 4cebf741e200271ce837e047fd81cc587c673e4b..31d6ac44a9460c732ee288d4750c8915dc363d13 100644 (file)
-use ast::visit;
-use rustc_ast as ast;
+use crate::clean;
+use crate::core::ResolverCaches;
+use crate::html::markdown::markdown_links;
+use crate::passes::collect_intra_doc_links::preprocess_link;
+
+use rustc_ast::visit::{self, AssocCtxt, Visitor};
+use rustc_ast::{self as ast, ItemKind};
+use rustc_ast_lowering::ResolverAstLowering;
 use rustc_hir::def::Namespace::TypeNS;
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
-use rustc_interface::interface;
-use rustc_span::Span;
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
+use rustc_resolve::Resolver;
+use rustc_session::config::Externs;
+use rustc_span::{Span, DUMMY_SP};
 
-use std::cell::RefCell;
 use std::mem;
-use std::rc::Rc;
-
-type Resolver = Rc<RefCell<interface::BoxedResolver>>;
-// Letting the resolver escape at the end of the function leads to inconsistencies between the
-// crates the TyCtxt sees and the resolver sees (because the resolver could load more crates
-// after escaping). Hopefully `IntraLinkCrateLoader` gets all the crates we need ...
-crate fn load_intra_link_crates(resolver: Resolver, krate: &ast::Crate) -> Resolver {
-    let mut loader = IntraLinkCrateLoader { current_mod: CRATE_DEF_ID, resolver };
-    // `walk_crate` doesn't visit the crate itself for some reason.
+
+crate fn early_resolve_intra_doc_links(
+    resolver: &mut Resolver<'_>,
+    krate: &ast::Crate,
+    externs: Externs,
+) -> ResolverCaches {
+    let mut loader = IntraLinkCrateLoader {
+        resolver,
+        current_mod: CRATE_DEF_ID,
+        all_traits: Default::default(),
+        all_trait_impls: Default::default(),
+    };
+
+    // Overridden `visit_item` below doesn't apply to the crate root,
+    // so we have to visit its attributes and exports separately.
     loader.load_links_in_attrs(&krate.attrs, krate.span);
     visit::walk_crate(&mut loader, krate);
-    loader.resolver
+    loader.fill_resolver_caches();
+
+    // FIXME: somehow rustdoc is still missing crates even though we loaded all
+    // the known necessary crates. Load them all unconditionally until we find a way to fix this.
+    // DO NOT REMOVE THIS without first testing on the reproducer in
+    // https://github.com/jyn514/objr/commit/edcee7b8124abf0e4c63873e8422ff81beb11ebb
+    for (extern_name, _) in externs.iter().filter(|(_, entry)| entry.add_prelude) {
+        let _ = loader.resolver.resolve_str_path_error(
+            DUMMY_SP,
+            extern_name,
+            TypeNS,
+            CRATE_DEF_ID.to_def_id(),
+        );
+    }
+
+    ResolverCaches {
+        all_traits: Some(loader.all_traits),
+        all_trait_impls: Some(loader.all_trait_impls),
+    }
 }
 
-struct IntraLinkCrateLoader {
+struct IntraLinkCrateLoader<'r, 'ra> {
+    resolver: &'r mut Resolver<'ra>,
     current_mod: LocalDefId,
-    resolver: Rc<RefCell<interface::BoxedResolver>>,
+    all_traits: Vec<DefId>,
+    all_trait_impls: Vec<DefId>,
 }
 
-impl IntraLinkCrateLoader {
-    fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
-        use crate::html::markdown::markdown_links;
-        use crate::passes::collect_intra_doc_links::preprocess_link;
+impl IntraLinkCrateLoader<'_, '_> {
+    fn fill_resolver_caches(&mut self) {
+        for cnum in self.resolver.cstore().crates_untracked() {
+            let all_traits = self.resolver.cstore().traits_in_crate_untracked(cnum);
+            let all_trait_impls = self.resolver.cstore().trait_impls_in_crate_untracked(cnum);
 
-        // FIXME: this probably needs to consider inlining
-        let attrs = crate::clean::Attributes::from_ast(attrs, None);
+            self.all_traits.extend(all_traits);
+            self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(def_id, _)| def_id));
+        }
+    }
+
+    fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
+        // FIXME: this needs to consider export inlining.
+        let attrs = clean::Attributes::from_ast(attrs, None);
         for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() {
-            debug!(?doc);
-            for link in markdown_links(doc.as_str()) {
-                debug!(?link.link);
+            let module_id = parent_module.unwrap_or(self.current_mod.to_def_id());
+
+            for link in markdown_links(&doc.as_str()) {
                 let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
                     x.path_str
                 } else {
                     continue;
                 };
-                self.resolver.borrow_mut().access(|resolver| {
-                    let _ = resolver.resolve_str_path_error(
-                        span,
-                        &path_str,
-                        TypeNS,
-                        parent_module.unwrap_or_else(|| self.current_mod.to_def_id()),
-                    );
-                });
+                let _ = self.resolver.resolve_str_path_error(span, &path_str, TypeNS, module_id);
             }
         }
     }
 }
 
-impl visit::Visitor<'_> for IntraLinkCrateLoader {
-    fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
-        self.load_links_in_attrs(&item.attrs, item.span);
-        visit::walk_foreign_item(self, item)
-    }
-
+impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> {
     fn visit_item(&mut self, item: &ast::Item) {
-        use rustc_ast_lowering::ResolverAstLowering;
-
-        if let ast::ItemKind::Mod(..) = item.kind {
-            let new_mod =
-                self.resolver.borrow_mut().access(|resolver| resolver.local_def_id(item.id));
-            let old_mod = mem::replace(&mut self.current_mod, new_mod);
+        if let ItemKind::Mod(..) = item.kind {
+            let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id));
 
             self.load_links_in_attrs(&item.attrs, item.span);
             visit::walk_item(self, item);
 
             self.current_mod = old_mod;
         } else {
+            match item.kind {
+                ItemKind::Trait(..) => {
+                    self.all_traits.push(self.resolver.local_def_id(item.id).to_def_id());
+                }
+                ItemKind::Impl(box ast::Impl { of_trait: Some(..), .. }) => {
+                    self.all_trait_impls.push(self.resolver.local_def_id(item.id).to_def_id());
+                }
+                _ => {}
+            }
             self.load_links_in_attrs(&item.attrs, item.span);
             visit::walk_item(self, item);
         }
     }
 
-    // NOTE: if doc-comments are ever allowed on function parameters, this will have to implement `visit_param` too.
-
-    fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: visit::AssocCtxt) {
+    fn visit_assoc_item(&mut self, item: &ast::AssocItem, ctxt: AssocCtxt) {
         self.load_links_in_attrs(&item.attrs, item.span);
         visit::walk_assoc_item(self, item, ctxt)
     }
 
-    fn visit_field_def(&mut self, field: &ast::FieldDef) {
-        self.load_links_in_attrs(&field.attrs, field.span);
-        visit::walk_field_def(self, field)
+    fn visit_foreign_item(&mut self, item: &ast::ForeignItem) {
+        self.load_links_in_attrs(&item.attrs, item.span);
+        visit::walk_foreign_item(self, item)
     }
 
     fn visit_variant(&mut self, v: &ast::Variant) {
         self.load_links_in_attrs(&v.attrs, v.span);
         visit::walk_variant(self, v)
     }
+
+    fn visit_field_def(&mut self, field: &ast::FieldDef) {
+        self.load_links_in_attrs(&field.attrs, field.span);
+        visit::walk_field_def(self, field)
+    }
+
+    // NOTE: if doc-comments are ever allowed on other nodes (e.g. function parameters),
+    // then this will have to implement other visitor methods too.
 }
index cc1d994dc99f03349272601f01bd828686bdf7a2..66ac612ea37c40d0011d8ca00598fb31c6f300c0 100644 (file)
 
     let mut new_items = Vec::new();
 
-    for &cnum in cx.tcx.crates(()).iter() {
-        for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() {
-            inline::build_impl(cx, None, did, None, &mut new_items);
+    // External trait impls.
+    cx.with_all_trait_impls(|cx, all_trait_impls| {
+        let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls");
+        for &impl_def_id in all_trait_impls.iter().skip_while(|def_id| def_id.is_local()) {
+            inline::build_impl(cx, None, impl_def_id, None, &mut new_items);
         }
-    }
+    });
 
     // Also try to inline primitive impls from other crates.
-    for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
-        if !def_id.is_local() {
-            cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
+    cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
+        for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() {
+            if !def_id.is_local() {
                 inline::build_impl(cx, None, def_id, None, &mut new_items);
 
                 // FIXME(eddyb) is this `doc(hidden)` check needed?
@@ -51,9 +53,9 @@
                     let impls = get_auto_trait_and_blanket_impls(cx, def_id);
                     new_items.extend(impls.filter(|i| cx.inlined.insert(i.def_id)));
                 }
-            });
+            }
         }
-    }
+    });
 
     let mut cleaner = BadImplStripper { prims, items: crate_items };
     let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
@@ -126,36 +128,33 @@ fn add_deref_target(
         }
     });
 
-    // `tcx.crates(())` doesn't include the local crate, and `tcx.all_trait_implementations`
-    // doesn't work with it anyway, so pull them from the HIR map instead
-    let mut extra_attrs = Vec::new();
-    for trait_did in cx.tcx.all_traits() {
-        for &impl_did in cx.tcx.hir().trait_impls(trait_did) {
-            let impl_did = impl_did.to_def_id();
-            cx.tcx.sess.prof.generic_activity("build_local_trait_impl").run(|| {
-                let mut parent = cx.tcx.parent(impl_did);
-                while let Some(did) = parent {
-                    extra_attrs.extend(
-                        cx.tcx
-                            .get_attrs(did)
-                            .iter()
-                            .filter(|attr| attr.has_name(sym::doc))
-                            .filter(|attr| {
-                                if let Some([attr]) = attr.meta_item_list().as_deref() {
-                                    attr.has_name(sym::cfg)
-                                } else {
-                                    false
-                                }
-                            })
-                            .cloned(),
-                    );
-                    parent = cx.tcx.parent(did);
-                }
-                inline::build_impl(cx, None, impl_did, Some(&extra_attrs), &mut new_items);
-                extra_attrs.clear();
-            });
+    // Local trait impls.
+    cx.with_all_trait_impls(|cx, all_trait_impls| {
+        let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
+        let mut attr_buf = Vec::new();
+        for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) {
+            let mut parent = cx.tcx.parent(impl_def_id);
+            while let Some(did) = parent {
+                attr_buf.extend(
+                    cx.tcx
+                        .get_attrs(did)
+                        .iter()
+                        .filter(|attr| attr.has_name(sym::doc))
+                        .filter(|attr| {
+                            if let Some([attr]) = attr.meta_item_list().as_deref() {
+                                attr.has_name(sym::cfg)
+                            } else {
+                                false
+                            }
+                        })
+                        .cloned(),
+                );
+                parent = cx.tcx.parent(did);
+            }
+            inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items);
+            attr_buf.clear();
         }
-    }
+    });
 
     if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind {
         items.extend(synth_impls);
index 675443b48a206d509cd0cdcf58ca84ce5ef85fea..7b07974ae01c67a54cb59905ecc12e26148ff3cd 100644 (file)
@@ -43,11 +43,10 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
             | clean::TraitAliasItem(..)
             | clean::MacroItem(..)
             | clean::ForeignTypeItem => {
-                if i.def_id.is_local() {
-                    if !self.access_levels.is_exported(i.def_id.expect_def_id()) {
-                        debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
-                        return None;
-                    }
+                if i.def_id.is_local() && !self.access_levels.is_exported(i.def_id.expect_def_id())
+                {
+                    debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
+                    return None;
                 }
             }
 
index 6809551fcfd9a2a3ad9bce09140248fdee7f319a..3282309b9df3e04dbea36d3427119c0610f16c0c 100644 (file)
@@ -173,7 +173,9 @@ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
 
         // If the enclosing item has a span coming from a proc macro, then we also don't want to include
         // the example.
-        let enclosing_item_span = tcx.hir().span_with_body(tcx.hir().get_parent_item(ex.hir_id));
+        let enclosing_item_span = tcx
+            .hir()
+            .span_with_body(tcx.hir().local_def_id_to_hir_id(tcx.hir().get_parent_item(ex.hir_id)));
         if enclosing_item_span.from_expansion() {
             trace!("Rejecting expr ({:?}) from macro item: {:?}", span, enclosing_item_span);
             return;
diff --git a/src/librustdoc/templates/STYLE.md b/src/librustdoc/templates/STYLE.md
new file mode 100644 (file)
index 0000000..fff65e3
--- /dev/null
@@ -0,0 +1,37 @@
+# Style for Templates
+
+This directory has templates in the [Tera templating language](teradoc), which is very
+similar to [Jinja2](jinjadoc) and [Django](djangodoc) templates, and also to [Askama](askamadoc).
+
+[teradoc]: https://tera.netlify.app/docs/#templates
+[jinjadoc]: https://jinja.palletsprojects.com/en/3.0.x/templates/
+[djangodoc]: https://docs.djangoproject.com/en/3.2/topics/templates/
+[askamadoc]: https://docs.rs/askama/0.10.5/askama/
+
+We want our rendered output to have as little unnecessary whitespace as
+possible, so that pages load quickly. To achieve that we use Tera's
+[whitespace control] features. At the end of most lines, we put an empty comment
+tag with the whitespace control characters: `{#- -#}`. This causes all
+whitespace between the end of the line and the beginning of the next, including
+indentation, to be omitted on render. Sometimes we want to preserve a single
+space. In those cases we put the space at the end of the line, followed by
+`{# -#}`, which is a directive to remove following whitespace but not preceding.
+We also use the whitespace control characters in most instances of tags with
+control flow, for example `{%- if foo -%}`.
+
+[whitespace control]: https://tera.netlify.app/docs/#whitespace-control
+
+We want our templates to be readable, so we use indentation and newlines
+liberally. We indent by four spaces after opening an HTML tag _or_ a Tera
+tag. In most cases an HTML tag should be followed by a newline, but if the
+tag has simple contents and fits with its close tag on a single line, the
+contents don't necessarily need a new line.
+
+Tera templates support quite sophisticated control flow. To keep our templates
+simple and understandable, we use only a subset: `if` and `for`. In particular
+we avoid [assignments in the template logic](assignments) and [Tera
+macros](macros). This also may make things easier if we switch to a different
+Jinja-style template system, like Askama, in the future.
+
+[assignments]: https://tera.netlify.app/docs/#assignments
+[macros]: https://tera.netlify.app/docs/#macros
diff --git a/src/librustdoc/templates/page.html b/src/librustdoc/templates/page.html
new file mode 100644 (file)
index 0000000..0280875
--- /dev/null
@@ -0,0 +1,140 @@
+<!DOCTYPE html> {#- -#}
+<html lang="en"> {#- -#}
+<head> {#- -#}
+    <meta charset="utf-8"> {#- -#}
+    <meta name="viewport" content="width=device-width, initial-scale=1.0"> {#- -#}
+    <meta name="generator" content="rustdoc"> {#- -#}
+    <meta name="description" content="{{page.description}}"> {#- -#}
+    <meta name="keywords" content="{{page.keywords}}"> {#- -#}
+    <title>{{page.title}}</title> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceSerif4-Regular.ttf.woff2"> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}FiraSans-Regular.woff2"> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}FiraSans-Medium.woff2"> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
+    <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
+    <link rel="stylesheet" type="text/css" {# -#}
+          href="{{static_root_path|safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
+    <link rel="stylesheet" type="text/css" {# -#}
+          href="{{static_root_path|safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
+          id="mainThemeStyle"> {#- -#}
+    {%- for theme in themes -%}
+        <link rel="stylesheet" type="text/css" {# -#}
+            href="{{static_root_path|safe}}{{theme}}{{page.resource_suffix}}.css" {# -#}
+        {%- if theme == "light" -%}
+            id="themeStyle"
+        {%- else -%}
+            disabled
+        {%- endif -%}
+        >
+    {%- endfor -%}
+    <script id="default-settings" {# -#}
+      {% for (k, v) in layout.default_settings %}
+        data-{{k}}="{{v}}"
+      {%- endfor -%}
+    ></script> {#- -#}
+    <script src="{{static_root_path|safe}}storage{{page.resource_suffix}}.js"></script> {#- -#}
+    <script src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
+    <script defer src="{{static_root_path|safe}}main{{page.resource_suffix}}.js"></script> {#- -#}
+    {%- for script in page.static_extra_scripts -%}
+    <script defer src="{{static_root_path|safe}}{{script}}.js"></script> {#- -#}
+    {% endfor %}
+    {%- if layout.scrape_examples_extension -%}
+    <script defer src="{{page.root_path|safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
+    {%- endif -%}
+    {%- for script in page.extra_scripts -%}
+    <script defer src="{{page.root_path|safe}}{{script}}.js"></script> {#- -#}
+    {% endfor %}
+    <noscript> {#- -#}
+        <link rel="stylesheet" {# -#}
+           href="{{static_root_path|safe}}noscript{{page.resource_suffix}}.css"> {#- -#}
+    </noscript> {#- -#}
+    {%- if layout.css_file_extension.is_some() -%}
+        <link rel="stylesheet" type="text/css" {# -#}
+            href="{{static_root_path|safe}}theme{{page.resource_suffix}}.css"> {#- -#}
+    {%- endif -%}
+    {%- if !layout.favicon.is_empty() -%}
+        <link rel="shortcut icon" href="{{layout.favicon}}"> {#- -#}
+    {%- else -%}
+        <link rel="alternate icon" type="image/png" {# -#}
+            href="{{static_root_path|safe}}favicon-16x16{{page.resource_suffix}}.png"> {#- -#}
+        <link rel="alternate icon" type="image/png" {# -#}
+            href="{{static_root_path|safe}}favicon-32x32{{page.resource_suffix}}.png"> {#- -#}
+        <link rel="icon" type="image/svg+xml" {# -#}
+            href="{{static_root_path|safe}}favicon{{page.resource_suffix}}.svg"> {#- -#}
+    {%- endif -%}
+    {{- layout.external_html.in_header|safe -}}
+</head> {#- -#}
+<body class="rustdoc {{page.css_class}}"> {#- -#}
+    <!--[if lte IE 11]> {#- -#}
+    <div class="warning"> {#- -#}
+        This old browser is unsupported and will most likely display funky things. {#- -#}
+    </div> {#- -#}
+    <![endif]--> {#- -#}
+    {{- layout.external_html.before_content|safe -}}
+    <nav class="sidebar"> {#- -#}
+        <div class="sidebar-menu" role="button">&#9776;</div> {#- -#}
+        <a class="sidebar-logo" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
+            <div class="logo-container"> {#- -#}
+                {%- if !layout.logo.is_empty()  %}
+                    <img src="{{layout.logo}}" alt="logo"> {#- -#}
+                {%- else -%}
+                    <img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
+                {%- endif -%}
+            </div>
+        </a> {#- -#}
+        {{- sidebar|safe -}}
+    </nav> {#- -#}
+    <main> {#- -#}
+        <div class="width-limiter"> {#- -#}
+            <div class="sub-container"> {#- -#}
+                <a class="sub-logo-container" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
+                    {%- if !layout.logo.is_empty()  %}
+                        <img src="{{layout.logo}}" alt="logo"> {#- -#}
+                    {%- else -%}
+                        <img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
+                    {%- endif -%}
+                </a> {#- -#}
+                <nav class="sub"> {#- -#}
+                    <div class="theme-picker"> {#- -#}
+                        <button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"> {#- -#}
+                            <img width="18" height="18" alt="Pick another theme!" {# -#}
+                             src="{{static_root_path|safe}}brush{{page.resource_suffix}}.svg"> {#- -#}
+                        </button> {#- -#}
+                        <div id="theme-choices" role="menu"></div> {#- -#}
+                    </div> {#- -#}
+                    <form class="search-form"> {#- -#}
+                        <div class="search-container"> {#- -#}
+                            <div>
+                                <input {# -#}
+                                    class="search-input" {# -#}
+                                    name="search" {# -#}
+                                    autocomplete="off" {# -#}
+                                    spellcheck="false" {# -#}
+                                    placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
+                                    type="search"> {#- -#}
+                            </div> {#- -#}
+                            <button type="button" id="help-button" title="help">?</button> {#- -#}
+                            <a id="settings-menu" href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
+                                <img width="18" height="18" alt="Change settings" {# -#}
+                                     src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
+                            </a> {#- -#}
+                        </div> {#- -#}
+                    </form> {#- -#}
+                </nav> {#- -#}
+            </div> {#- -#}
+            <section id="main-content" class="content">{{- content|safe -}}</section> {#- -#}
+            <section id="search" class="content hidden"></section> {#- -#}
+        </div> {#- -#}
+    </main> {#- -#}
+    {{- layout.external_html.after_content|safe -}}
+    <div id="rustdoc-vars" {# -#}
+         data-root-path="{{page.root_path|safe}}" {# -#}
+         data-current-crate="{{layout.krate}}" {# -#}
+         data-themes="{{themes|join(",") }}" {# -#}
+         data-resource-suffix="{{page.resource_suffix}}" {# -#}
+         data-rustdoc-version="{{rustdoc_version}}" {# -#}
+    > {#- -#}
+    </div>
+</body> {#- -#}
+</html> {#- -#}
diff --git a/src/librustdoc/templates/print_item.html b/src/librustdoc/templates/print_item.html
new file mode 100644 (file)
index 0000000..459b01a
--- /dev/null
@@ -0,0 +1,30 @@
+<div class="main-heading">
+    <h1 class="fqn"> {#- -#}
+        <span class="in-band"> {#- -#}
+            {{-typ-}}
+            {#- The breadcrumbs of the item path, like std::string -#}
+            {%- for component in path_components -%}
+            <a href="{{component.path|safe}}index.html">{{component.name}}</a>::<wbr>
+            {%- endfor -%}
+            <a class="{{item_type}}" href="#">{{name}}</a> {#- -#}
+            <button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#}
+                <img src="{{static_root_path|safe}}clipboard{{page.resource_suffix}}.svg" {# -#}
+                    width="19" height="18" {# -#}
+                    alt="Copy item path"> {#- -#}
+            </button> {#- -#}
+        </span> {#- -#}
+    </h1> {#- -#}
+    <span class="out-of-band"> {#- -#}
+        {% if !stability_since_raw.is_empty() %}
+        {{- stability_since_raw|safe -}} · {# -#}
+        {% endif %}
+        {%- match src_href -%}
+            {%- when Some with (href) -%}
+                <a class="srclink" href="{{href|safe}}" title="goto source code">source</a> · {# -#}
+            {%- else -%}
+        {%- endmatch -%}
+        <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs"> {#- -#}
+            [<span class="inner">&#x2212;</span>] {#- -#}
+        </a> {#- -#}
+    </span> {#- -#}
+</div>
index 8e29cb16a400f05006256455750af1474bed99f6..90cb5d586c2114a18dd2cccfd33e5e35f6d15a9d 100644 (file)
@@ -5,7 +5,6 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::definitions::DefPathData;
 use rustc_hir::Node;
 use rustc_hir::CRATE_HIR_ID;
 use rustc_middle::middle::privacy::AccessLevel;
@@ -43,12 +42,9 @@ impl Module<'_> {
 }
 
 // FIXME: Should this be replaced with tcx.def_path_str?
-fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<String> {
-    let crate_name = tcx.crate_name(did.krate).to_string();
-    let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| {
-        // Filter out extern blocks
-        (elem.data != DefPathData::ForeignMod).then(|| elem.data.to_string())
-    });
+fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<Symbol> {
+    let crate_name = tcx.crate_name(did.krate);
+    let relative = tcx.def_path(did).data.into_iter().filter_map(|elem| elem.data.get_opt_name());
     std::iter::once(crate_name).chain(relative).collect()
 }
 
@@ -71,7 +67,7 @@ fn def_id_to_path(tcx: TyCtxt<'_>, did: DefId) -> Vec<String> {
     inlining: bool,
     /// Are the current module and all of its parents public?
     inside_public_path: bool,
-    exact_paths: FxHashMap<DefId, Vec<String>>,
+    exact_paths: FxHashMap<DefId, Vec<Symbol>>,
 }
 
 impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
@@ -112,7 +108,7 @@ fn store_path(&mut self, did: DefId) {
         // is declared but also a reexport of itself producing two exports of the same
         // macro in the same module.
         let mut inserted = FxHashSet::default();
-        for export in self.cx.tcx.module_exports(CRATE_DEF_ID).unwrap_or(&[]) {
+        for export in self.cx.tcx.module_reexports(CRATE_DEF_ID).unwrap_or(&[]) {
             if let Res::Def(DefKind::Macro(_), def_id) = export.res {
                 if let Some(local_def_id) = def_id.as_local() {
                     if self.cx.tcx.has_attr(def_id, sym::macro_export) {
index ce94f06d574e17c2407a017925c4d17d3fd7d697..5bcec779bc0e7d130be976f1cb17ba9d660b13ed 100644 (file)
@@ -53,7 +53,7 @@ fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLev
             return;
         }
 
-        for item in self.tcx.item_children(def_id).iter() {
+        for item in self.tcx.module_children(def_id).iter() {
             if let Some(def_id) = item.res.opt_def_id() {
                 if self.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index)
                     || item.vis.is_public()
index 6b3dbcc81a470e5da84576d63fcfc19e3b1154cd..2abffbf977a9e8c6ca4174a08fe5c4d7781f0aac 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 6b3dbcc81a470e5da84576d63fcfc19e3b1154cd
+Subproject commit 2abffbf977a9e8c6ca4174a08fe5c4d7781f0aac
index 0c16b9ad3ab510fa70fa22c4886d28bb922debdd..bb0db9d3d8514bdfa0158316329075579ec626ef 100644 (file)
@@ -17,7 +17,7 @@ async fn async_fn_test() {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator$0"
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "async_fn$0"
 // CHECK:      {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]],
 // For brevity, we only check the struct name and members of the last variant.
 // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11,
index 39319a3ea722cbfea9603e354b70ada40cd13284..f456f7ffc0fba7f6b6ce4e8e8790a7c9643d0d88 100644 (file)
@@ -17,7 +17,7 @@ async fn async_fn_test() {
 // FIXME: No way to reliably check the filename.
 
 // CHECK-DAG:  [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test"
-// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{generator#0}", scope: [[ASYNC_FN]]
+// CHECK-DAG:  [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn#0}", scope: [[ASYNC_FN]]
 // CHECK:      [[VARIANT:!.*]] = !DICompositeType(tag: DW_TAG_variant_part, scope: [[ASYNC_FN]],
 // CHECK-NOT:  flags: DIFlagArtificial
 // CHECK-SAME: discriminator: [[DISC:![0-9]*]]
index a2571c2e532a73f80777b2a609546fb3ba4f9d16..ad41badf38169036d03b02a6a1fb599e0f86d583 100644 (file)
@@ -1,7 +1,7 @@
 // Checks that closures, constructors, and shims except
 // for a drop glue receive inline hint by default.
 //
-// compile-flags: -Cno-prepopulate-passes -Zsymbol-mangling-version=v0
+// compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0
 #![crate_type = "lib"]
 
 pub fn f() {
index 61d5fc93cd2ad5b7b985d15c07dbcecff0568fa4..ac9a02cce048127d459d8716b3aa0be29a4808f9 100644 (file)
@@ -37,7 +37,7 @@
 // Const generic parameter
 // gdb-command:info functions -q function_names::const_generic_fn.*
 // gdb-check:[...]static fn function_names::const_generic_fn_bool<false>();
-// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#fe3cfa0214ac55c7}>();
+// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#3fcd7c34c1555be6}>();
 // gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>();
 // gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>();
 
@@ -76,7 +76,7 @@
 // Const generic parameter
 // cdb-command:x a!function_names::const_generic_fn*
 // cdb-check:[...] a!function_names::const_generic_fn_bool<false> (void)
-// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$fe3cfa0214ac55c7> (void)
+// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$3fcd7c34c1555be6> (void)
 // cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void)
 // cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void)
 
index 1791c089cfa8bb6341c54d0beafcb907ecc44eb9..d57267adc6bdc86c3fabfc71619ecf04c6168ea3 100644 (file)
@@ -51,7 +51,11 @@ pub fn translate(&mut self, x: f32, y: f32) {
 pub mod fn_calls_methods_in_same_impl {
     use point::Point;
 
-    #[rustc_clean(cfg="cfail2")]
+    // The cached result should actually be loaded from disk
+    // (not just marked green) - for example, `DeadVisitor`
+    // always runs during compilation as a "pass", and loads
+    // the typeck results for bodies.
+    #[rustc_clean(cfg="cfail2", loaded_from_disk="typeck")]
     pub fn check() {
         let x = Point { x: 2.0, y: 2.0 };
         x.distance_from_origin();
diff --git a/src/test/incremental/hash-module-order.rs b/src/test/incremental/hash-module-order.rs
new file mode 100644 (file)
index 0000000..fe9af9e
--- /dev/null
@@ -0,0 +1,28 @@
+// revisions: rpass1 rpass2
+// compile-flags: -Z incremental-ignore-spans -Z query-dep-graph
+
+// Tests that module hashing depends on the order of the items
+// (since the order is exposed through `Mod.item_ids`).
+// Changing the order of items (while keeping `Span`s the same)
+// should still result in `hir_owner` being invalidated.
+// Note that it's possible to keep the spans unchanged using
+// a proc-macro (e.g. producing the module via `quote!`)
+// but we use `-Z incremental-ignore-spans` for simplicity
+
+#![feature(rustc_attrs)]
+
+#[cfg(rpass1)]
+#[rustc_clean(cfg="rpass1",except="hir_owner")]
+mod foo {
+    struct First;
+    struct Second;
+}
+
+#[cfg(rpass2)]
+#[rustc_clean(cfg="rpass2",except="hir_owner")]
+mod foo {
+    struct Second;
+    struct First;
+}
+
+fn main() {}
index b72ec404f672a575900678e11c1ea535e211e825..14d6fc87198c4e1dc356de6bce87198ec4165960 100644 (file)
@@ -400,7 +400,7 @@ trait TraitAddUnsafeModifier {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5")]
+#[rustc_clean(except="hir_owner", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddUnsafeModifier {
     #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
@@ -425,7 +425,7 @@ trait TraitAddExternModifier {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5")]
+#[rustc_clean(except="hir_owner", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddExternModifier {
     #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
index 4ae783a7f46ff7fcbd4002d33e5c819f2d83e3ae..1e53136563885e55fb82974d77d5c8d07db6af76 100644 (file)
@@ -30,7 +30,7 @@
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
 +                                          // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:44
-+                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[HASH]::BAR), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
++                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[HASH]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
 -         StorageDead(_4);                 // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35
index 705c2ed06b3824fb17b6a677e02f61a4cce81bb8..a012285c7ec887aca480837179f5cc75d3731608 100644 (file)
@@ -32,7 +32,7 @@
 -         _3 = [move _4];                  // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46
 -         _2 = &_3;                        // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
 +                                          // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:55
-+                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[HASH]::FOO), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
++                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[HASH]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
 -         StorageDead(_4);                 // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46
index 7fb954b8356cd28cfe7927c880ca9f0637c8ef61..7627ed5462396cbfa11be28a9ea700a0b738f4b2 100644 (file)
@@ -31,7 +31,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
-                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
index 7fb954b8356cd28cfe7927c880ca9f0637c8ef61..7627ed5462396cbfa11be28a9ea700a0b738f4b2 100644 (file)
@@ -31,7 +31,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
-                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _3 = _9;                         // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _2 = &raw const (*_3);           // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
           _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35
index 827a86c2376e8b5a61b7e7ef7b34286285c13e8e..e6220176778dcfa42d110f0a172e72c9f25e349c 100644 (file)
@@ -22,7 +22,7 @@
                                            // + val: Unevaluated(FOO, [], None)
                                            // mir::Constant
                                            // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[HASH]::main::FOO), const_param_did: None }, substs_: Some([]), promoted: None }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[HASH]::main::FOO), const_param_did: None }, substs: [], promoted: None }) }
           _2 = &raw const (*_3);           // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16
           _1 = move _2 as usize (Misc);    // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39
           StorageDead(_2);                 // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39
index 496b9718c6ad9b100dcd93b142c3148e475c91cc..d602e12a370a3e31d691625157fd4002bb26bd30 100644 (file)
@@ -17,7 +17,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/ref_deref.rs:5:6: 5:10
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _2 = _4;                         // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
 -         _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
 +         _1 = const 4_i32;                // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
index 07c3b0cd58f2d59bfd09a8bcae3a72c6d032d6f1..35916d90e564023fff1d7f5be3cd276496275662 100644 (file)
@@ -20,7 +20,7 @@
 +                                          // + val: Unevaluated(main, [], Some(promoted[0]))
 +                                          // mir::Constant
 +                                          // + span: $DIR/ref_deref.rs:5:6: 5:10
-+                                          // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
++                                          // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
 +         _2 = &(*_4);                     // scope 0 at $DIR/ref_deref.rs:5:6: 5:10
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref.rs:5:5: 5:10
 -         StorageDead(_3);                 // scope 0 at $DIR/ref_deref.rs:5:10: 5:11
index 2545b89c1d3ee9194900abecfe70f91a4eb060aa..39651884e775d1670cf32316fbee3efd07c33450 100644 (file)
@@ -17,7 +17,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/ref_deref_project.rs:5:6: 5:17
-                                           // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
           StorageDead(_2);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
index f728d55ba6ede0bf6be71244e033a10ddeef3393..501d72056795c4555acf98c7bfba13dc856bbd69 100644 (file)
@@ -20,7 +20,7 @@
 +                                          // + val: Unevaluated(main, [], Some(promoted[0]))
 +                                          // mir::Constant
 +                                          // + span: $DIR/ref_deref_project.rs:5:6: 5:17
-+                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
++                                          // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
 +         _2 = &((*_4).1: i32);            // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17
           _1 = (*_2);                      // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17
 -         StorageDead(_3);                 // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18
index 12c77e0b042a3b514db56b4e17fa0563f6b571c0..6a580278d5f12490a4438d21e33bc00f563919c5 100644 (file)
@@ -25,7 +25,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/slice_len.rs:5:6: 5:19
-                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           StorageLive(_10);                // scope 0 at $DIR/slice_len.rs:5:6: 5:19
index 12c77e0b042a3b514db56b4e17fa0563f6b571c0..6a580278d5f12490a4438d21e33bc00f563919c5 100644 (file)
@@ -25,7 +25,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/slice_len.rs:5:6: 5:19
-                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _4 = _9;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           _3 = _4;                         // scope 0 at $DIR/slice_len.rs:5:6: 5:19
           StorageLive(_10);                // scope 0 at $DIR/slice_len.rs:5:6: 5:19
index 37f6fc91cf95f69efb4f3d3d85c780aa5c9acf76..486fc7541c3af26ffd5306fdb543ad6ca7ef29cb 100644 (file)
@@ -38,7 +38,7 @@ fn bar() -> bool {
                                          // + val: Unevaluated(bar, [], Some(promoted[1]))
                                          // mir::Constant
                                          // + span: $DIR/inline-retag.rs:12:7: 12:9
-                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[HASH]::bar), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[1]) }) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[HASH]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) }
         Retag(_10);                      // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
         _4 = &(*_10);                    // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
         Retag(_4);                       // scope 1 at $DIR/inline-retag.rs:12:7: 12:9
@@ -52,7 +52,7 @@ fn bar() -> bool {
                                          // + val: Unevaluated(bar, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/inline-retag.rs:12:11: 12:14
-                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[HASH]::bar), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[HASH]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
         Retag(_9);                       // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
         _7 = &(*_9);                     // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
         Retag(_7);                       // scope 1 at $DIR/inline-retag.rs:12:11: 12:14
index 20e5191310cafb68b0bfe65774cd5ca15c260f5b..7938c0a23e8e9c5c14c9814a007d430e11f45fa9 100644 (file)
@@ -66,7 +66,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _8 = _20;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.0: &i32) = move _7;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.1: &i32) = move _8;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
index 20e5191310cafb68b0bfe65774cd5ca15c260f5b..7938c0a23e8e9c5c14c9814a007d430e11f45fa9 100644 (file)
@@ -66,7 +66,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _8 = _20;                        // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.0: &i32) = move _7;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_6.1: &i32) = move _8;          // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
index 04e4af70bb75e4fc77eb8e08f96a69b1ee296038..20771bf4231a0ee8daa2887ce1f0365961ff1d79 100644 (file)
@@ -87,7 +87,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _11 = _28;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
index 04e4af70bb75e4fc77eb8e08f96a69b1ee296038..20771bf4231a0ee8daa2887ce1f0365961ff1d79 100644 (file)
@@ -87,7 +87,7 @@
                                            // + val: Unevaluated(main, [], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
           _11 = _28;                       // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.0: &i32) = move _10;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           (_9.1: &i32) = move _11;         // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
index b8f44b7672a200561751085ed4f866762b5f7a2f..75d0e75f5b15d0dd8348f7b6ae67045e2d157020 100644 (file)
@@ -50,7 +50,7 @@
                                            // + val: Unevaluated(discriminant, [T], Some(promoted[2]))
                                            // mir::Constant
                                            // + span: $DIR/lower_intrinsics.rs:75:42: 75:44
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[2]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) }
           _7 = &(*_19);                    // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44
           _6 = &(*_7);                     // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44
 -         _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45
@@ -74,7 +74,7 @@
                                            // + val: Unevaluated(discriminant, [T], Some(promoted[1]))
                                            // mir::Constant
                                            // + span: $DIR/lower_intrinsics.rs:76:42: 76:45
-                                           // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[1]) }) }
+                                           // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) }
           _11 = &(*_18);                   // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45
           _10 = &(*_11);                   // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45
 -         _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46
@@ -98,7 +98,7 @@
                                            // + val: Unevaluated(discriminant, [T], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/lower_intrinsics.rs:77:42: 77:47
-                                           // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs_: Some([T]), promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) }
           _15 = &(*_17);                   // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47
           _14 = &(*_15);                   // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47
 -         _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77:48
index 0ef06da0cb758ae97d0d5a421073cae996c57a86..51425af4bdf9a22bfc9ac25f49ba4955af300c7a 100644 (file)
@@ -57,7 +57,7 @@ fn full_tested_match() -> () {
                                          // + val: Unevaluated(full_tested_match, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/match_false_edges.rs:16:14: 16:15
-                                         // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[HASH]::full_tested_match), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                         // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[HASH]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
         _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15
         _4 = &shallow _2;                // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27
         StorageLive(_7);                 // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27
index defb04db7decec41e2b6d45d036119e7c2bd78db..1db36c352ff3665b94a95662b3b8514f830d4b44 100644 (file)
@@ -127,7 +127,7 @@ fn array_casts() -> () {
                                          // + val: Unevaluated(array_casts, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
-                                         // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[HASH]::array_casts), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                         // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[HASH]::array_casts), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
         Retag(_35);                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         _18 = &(*_35);                   // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
         Retag(_18);                      // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
index 3f35f15a56d76d78bf4335c7cc452ba26a5c3a40..cffe723898777802efcaaec3fdf4ff6811f6b6e0 100644 (file)
@@ -153,7 +153,7 @@ fn main() -> () {
                                          // + val: Unevaluated(main, [], Some(promoted[0]))
                                          // mir::Constant
                                          // + span: $DIR/retag.rs:47:21: 47:23
-                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[HASH]::main), const_param_did: None }, substs_: Some([]), promoted: Some(promoted[0]) }) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
         Retag(_28);                      // scope 7 at $DIR/retag.rs:47:21: 47:23
         _23 = &(*_28);                   // scope 7 at $DIR/retag.rs:47:21: 47:23
         Retag(_23);                      // scope 7 at $DIR/retag.rs:47:21: 47:23
index 54526e8ef23b3df36886334fb91d74d2bebfaca3..4a9b3d70933e4980345c6429dcf84d821a1fd0b6 100644 (file)
@@ -8,8 +8,8 @@
 # and will probably get removed once `legacy` is gone.
 
 all:
-       $(RUSTC) a.rs --cfg x -C prefer-dynamic -Z symbol-mangling-version=legacy
-       $(RUSTC) b.rs -C prefer-dynamic -Z symbol-mangling-version=legacy
+       $(RUSTC) a.rs --cfg x -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=legacy
+       $(RUSTC) b.rs -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=legacy
        $(call RUN,b)
-       $(RUSTC) a.rs --cfg y -C prefer-dynamic -Z symbol-mangling-version=legacy
+       $(RUSTC) a.rs --cfg y -C prefer-dynamic -Z unstable-options -C symbol-mangling-version=legacy
        $(call FAIL,b)
index 9122e0406c2efc49ce6d7131de87b01d3b5264b5..094d6b3ebf5f8f6a41c32b343ebba175c85afcf2 100644 (file)
@@ -64,7 +64,7 @@ endif
 # if and when we allow `llvm-cov` to produce results for multiple files. Note, the path separators
 # appear to be normalized to `/` in those files, thankfully.)
 LLVM_COV_IGNORE_FILES=\
-       --ignore-filename-regex='(uses_crate.rs|uses_inline_crate.rs)'
+       --ignore-filename-regex='(uses_crate.rs|uses_inline_crate.rs|unused_mod.rs)'
 
 all: $(patsubst $(SOURCEDIR)/lib/%.rs,%,$(wildcard $(SOURCEDIR)/lib/*.rs)) $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs))
 
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.unused_mod.txt
new file mode 100644 (file)
index 0000000..82d6fcc
--- /dev/null
@@ -0,0 +1,4 @@
+    1|      0|pub fn never_called_function() {
+    2|      0|    println!("I am never called");
+    3|      0|}
+
diff --git a/src/test/run-make-fulldeps/coverage/lib/unused_mod_helper.rs b/src/test/run-make-fulldeps/coverage/lib/unused_mod_helper.rs
new file mode 100644 (file)
index 0000000..ae1cc15
--- /dev/null
@@ -0,0 +1,3 @@
+pub fn never_called_function() {
+    println!("I am never called");
+}
diff --git a/src/test/run-make-fulldeps/coverage/unused_mod.rs b/src/test/run-make-fulldeps/coverage/unused_mod.rs
new file mode 100644 (file)
index 0000000..679b4e5
--- /dev/null
@@ -0,0 +1,6 @@
+#[path = "lib/unused_mod_helper.rs"]
+mod unused_module;
+
+fn main() {
+    println!("hello world!");
+}
index c6b5efcb4cdd8269ff14e1370dbc9dacf47568b7..282cb2461f69a7b494f987af2fb7ab893e059dcb 100644 (file)
@@ -11,7 +11,7 @@
 
 -include ../../run-make-fulldeps/tools.mk
 
-COMMON_ARGS=-Cprefer-dynamic -Zshare-generics=yes -Ccodegen-units=1 -Zsymbol-mangling-version=v0
+COMMON_ARGS=-Cprefer-dynamic -Zshare-generics=yes -Ccodegen-units=1 -Csymbol-mangling-version=v0
 
 all:
        $(RUSTC) instance_provider_a.rs $(COMMON_ARGS) --crate-type=rlib
index e8e62efe01c140de3ddc5c462469aa06859ac20d..e2dc64d8ce2ddcce90949d447403a3424db38b99 100644 (file)
@@ -44,16 +44,78 @@ off:
        [ ! -f $(TMPDIR)/*.dwp ]
        [ ! -f $(TMPDIR)/*.dwo ]
 
-packed:
-       $(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options
+packed: packed-split packed-single
+
+packed-split:
+       $(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options -Zsplit-dwarf-kind=split
+       ls $(TMPDIR)/*.dwp
+       rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo
+
+packed-single:
+       $(RUSTC) foo.rs -g -C split-debuginfo=packed -Z unstable-options -Zsplit-dwarf-kind=single
        ls $(TMPDIR)/*.dwp
        ls $(TMPDIR)/*.dwo && exit 1 || exit 0
        rm -rf $(TMPDIR)/*.dwp
 
-unpacked:
-       $(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options
+packed-remapped: packed-remapped-split packed-remapped-single
+
+packed-remapped-split:
+       $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 \
+               -Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+
+packed-remapped-single:
+       $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 \
+               -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+
+packed-crosscrate: packed-crosscrate-split packed-crosscrate-single
+
+packed-crosscrate-split:
+       $(RUSTC) --crate-type lib -Z unstable-options -C split-debuginfo=packed \
+               -Zsplit-dwarf-kind=split -C debuginfo=2 -g bar.rs
+       ls $(TMPDIR)/*.rlib
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options -C split-debuginfo=packed \
+               -Zsplit-dwarf-kind=split -C debuginfo=2 -g main.rs
+       rm $(TMPDIR)/*.dwo
+       rm $(TMPDIR)/main.dwp
+       rm $(TMPDIR)/$(call BIN,main)
+
+packed-crosscrate-single:
+       $(RUSTC) --crate-type lib -Z unstable-options -C split-debuginfo=packed \
+               -Zsplit-dwarf-kind=single -C debuginfo=2 -g bar.rs
+       ls $(TMPDIR)/*.rlib
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       $(RUSTC) --extern bar=$(TMPDIR)/libbar.rlib -Z unstable-options -C split-debuginfo=packed \
+               -Zsplit-dwarf-kind=single -C debuginfo=2 -g main.rs
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+       rm $(TMPDIR)/main.dwp
+       rm $(TMPDIR)/$(call BIN,main)
+
+unpacked: unpacked-split unpacked-single unpacked-remapped-split unpacked-remapped-single
+
+unpacked-split:
+       $(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options -Zsplit-dwarf-kind=split
        ls $(TMPDIR)/*.dwp && exit 1 || exit 0
        ls $(TMPDIR)/*.dwo
-       rm -rf $(TMPDIR)/*.dwo
+       rm -rf $(TMPDIR)/*.dwp $(TMPDIR)/*.dwo
+
+unpacked-single:
+       $(RUSTC) foo.rs -g -C split-debuginfo=unpacked -Z unstable-options -Zsplit-dwarf-kind=single
+       ls $(TMPDIR)/*.dwp && exit 1 || exit 0
+       ls $(TMPDIR)/*.dwo && exit 1 || exit 0
+
+unpacked-remapped-split:
+       $(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 \
+               -Z split-dwarf-kind=split --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
+
+unpacked-remapped-single:
+       $(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 \
+               -Z split-dwarf-kind=single --remap-path-prefix $(TMPDIR)=/a foo.rs -g
+       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
 endif
 endif
diff --git a/src/test/run-make-fulldeps/split-debuginfo/bar.rs b/src/test/run-make-fulldeps/split-debuginfo/bar.rs
new file mode 100644 (file)
index 0000000..07dd071
--- /dev/null
@@ -0,0 +1,13 @@
+pub struct Bar {
+    x: u32,
+}
+
+impl Bar {
+    pub fn print(&self) {
+        println!("{}", self.x);
+    }
+}
+
+pub fn make_bar(x: u32) -> Bar {
+    Bar { x }
+}
index f328e4d9d04c31d0d70d16d21a07d1613be9d577..b058e540862343f7a2b2b791e78fdfc830dc65e3 100644 (file)
@@ -1 +1,15 @@
+pub struct Foo {
+    x: u32,
+}
+
+impl Foo {
+    pub fn print(&self) {
+        println!("{}", self.x);
+    }
+}
+
+pub fn make_foo(x: u32) -> Foo {
+    Foo { x }
+}
+
 fn main() {}
diff --git a/src/test/run-make-fulldeps/split-debuginfo/main.rs b/src/test/run-make-fulldeps/split-debuginfo/main.rs
new file mode 100644 (file)
index 0000000..21fa16e
--- /dev/null
@@ -0,0 +1,8 @@
+extern crate bar;
+
+use bar::{Bar, make_bar};
+
+fn main() {
+    let b = make_bar(3);
+    b.print();
+}
diff --git a/src/test/run-make-fulldeps/split-dwarf/Makefile b/src/test/run-make-fulldeps/split-dwarf/Makefile
deleted file mode 100644 (file)
index eef04c7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
--include ../tools.mk
-
-# only-linux
-
-all: packed remapped
-
-remapped:
-       $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 --remap-path-prefix $(TMPDIR)=/a foo.rs -g
-       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
-
-       $(RUSTC) -Z unstable-options -C split-debuginfo=unpacked -C debuginfo=2 --remap-path-prefix $(TMPDIR)=/a foo.rs -g
-       objdump -Wi $(TMPDIR)/foo | grep DW_AT_GNU_dwo_name | (! grep $(TMPDIR)) || exit 1
-
-packed:
-       $(RUSTC) -Z unstable-options -C split-debuginfo=packed -C debuginfo=2 foo.rs -g
-       rm $(TMPDIR)/foo.dwp
-       rm $(TMPDIR)/$(call BIN,foo)
diff --git a/src/test/run-make-fulldeps/split-dwarf/foo.rs b/src/test/run-make-fulldeps/split-dwarf/foo.rs
deleted file mode 100644 (file)
index f328e4d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-fn main() {}
index ca60be72cea468a6626d13b34d03f546deca3cc0..e6758287d8cb2e7a59446ef2a4a674eed0be0cca 100644 (file)
@@ -13,8 +13,10 @@ reload:
 assert-css: ("#toggle-all-docs", {"color": "rgb(0, 0, 0)"})
 assert-css: (".fqn .in-band a:nth-of-type(1)", {"color": "rgb(0, 0, 0)"})
 assert-css: (".fqn .in-band a:nth-of-type(2)", {"color": "rgb(173, 55, 138)"})
-assert-css: (".srclink", {"color": "rgb(0, 0, 0)"})
-assert-css: (".srclink", {"color": "rgb(0, 0, 0)"})
+assert-css: (".srclink", {"color": "rgb(56, 115, 173)"})
+
+move-cursor-to: ".main-heading .srclink"
+assert-css: (".srclink", {"text-decoration": "underline solid rgb(56, 115, 173)"})
 
 assert-css: ("#top-doc-prose-title", {"color": "rgb(0, 0, 0)"})
 
index b65c398405cf5e36c12c59047e09715b9f2a9dcb..712920b16a91babf02b44faa00719b5ec5bf0b5a 100644 (file)
@@ -1,7 +1,7 @@
 goto: file://|DOC_PATH|/test_docs/index.html
 // First, we check that the search results are hidden when the Escape key is pressed.
 write: (".search-input", "test")
-wait-for: "#search h1" // The search element is empty before the first search 
+wait-for: "#search h1" // The search element is empty before the first search 
 assert-attribute: ("#search", {"class": "content"})
 assert-attribute: ("#main-content", {"class": "content hidden"})
 press-key: "Escape"
index 87c512468e05fd9a1dcfd0fdc5a91028c8933c2a..9db75c59d948a8afee2126a5af6d10872c6af169 100644 (file)
@@ -15,7 +15,7 @@
 goto: file://|DOC_PATH|/test_docs/struct.HeavilyDocumentedStruct.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+assert-css: (".main-heading", {"border-bottom-width": "1px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -55,7 +55,7 @@ assert-css: ("h6#sub-sub-heading-for-struct-impl-item-doc", {"font-size": "15.2p
 goto: file://|DOC_PATH|/test_docs/enum.HeavilyDocumentedEnum.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+assert-css: (".main-heading", {"border-bottom-width": "1px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -115,7 +115,7 @@ assert-css: (".sidebar .others h3", {"border-bottom-width": "1px"}, ALL)
 goto: file://|DOC_PATH|/test_docs/union.HeavilyDocumentedUnion.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+assert-css: (".main-heading", {"border-bottom-width": "1px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -148,7 +148,7 @@ assert-css: ("h6#sub-heading-for-union-impl-item-doc", {"border-bottom-width": "
 goto: file://|DOC_PATH|/test_docs/macro.heavily_documented_macro.html
 
 assert-css: ("h1.fqn", {"font-size": "24px"})
-assert-css: ("h1.fqn", {"border-bottom-width": "1px"})
+assert-css: (".main-heading", {"border-bottom-width": "1px"})
 
 assert-css: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
diff --git a/src/test/rustdoc-gui/run-on-hover.goml b/src/test/rustdoc-gui/run-on-hover.goml
new file mode 100644 (file)
index 0000000..b8efa8e
--- /dev/null
@@ -0,0 +1,7 @@
+// Example code blocks sometimes have a "Run" button to run them on the
+// Playground. That button is hidden until the user hovers over the code block.
+// This test checks that it is hidden, and that it shows on hover.
+goto: file://|DOC_PATH|/test_docs/fn.foo.html
+assert-css: (".test-arrow", {"visibility": "hidden"})
+move-cursor-to: ".example-wrap"
+assert-css: (".test-arrow", {"visibility": "visible"})
diff --git a/src/test/rustdoc-gui/rust-logo.goml b/src/test/rustdoc-gui/rust-logo.goml
new file mode 100644 (file)
index 0000000..4a9dcf7
--- /dev/null
@@ -0,0 +1,78 @@
+// This test ensures that the correct style is applied to the rust logo in the sidebar.
+goto: file://|DOC_PATH|/test_docs/index.html
+
+// First we start with the dark theme.
+local-storage: {
+    "rustdoc-theme": "dark",
+    "rustdoc-preferred-dark-theme": "dark",
+    "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+    ".rust-logo",
+    {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// In the source view page now.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+
+local-storage: {
+    "rustdoc-theme": "dark",
+    "rustdoc-preferred-dark-theme": "dark",
+    "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+    ".rust-logo",
+    {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// Then with the ayu theme.
+local-storage: {
+    "rustdoc-theme": "ayu",
+    "rustdoc-preferred-dark-theme": "ayu",
+    "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+    ".rust-logo",
+    {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// In the source view page now.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+
+local-storage: {
+    "rustdoc-theme": "ayu",
+    "rustdoc-preferred-dark-theme": "ayu",
+    "rustdoc-use-system-theme": "false",
+}
+reload:
+
+assert-css: (
+    ".rust-logo",
+    {"filter": "drop-shadow(rgb(255, 255, 255) 1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px 1px 0px) drop-shadow(rgb(255, 255, 255) -1px 0px 0px) drop-shadow(rgb(255, 255, 255) 0px -1px 0px)"},
+)
+
+// And finally with the light theme.
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+reload:
+
+assert-css: (
+    ".rust-logo",
+    {"filter": "none"},
+)
+
+// In the source view page now.
+goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
+
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+reload:
+
+assert-css: (
+    ".rust-logo",
+    {"filter": "none"},
+)
index 7a8f8ca5311adf90a4ba46a13243115f901c775f..e5cdf3ea7a1699c3636e58c675bdb50f93122291 100644 (file)
@@ -5,14 +5,12 @@ write: (".search-input", "test")
 wait-for: "#titles"
 assert-text: ("#results .externcrate", "test_docs")
 
-goto: file://|DOC_PATH|/test_docs/index.html
+wait-for: "#crate-search"
 // We now want to change the crate filter.
 click: "#crate-search"
 // We select "lib2" option then press enter to change the filter.
 press-key: "ArrowDown"
 press-key: "Enter"
-// We now make the search again.
-write: (".search-input", "test")
 // Waiting for the search results to appear...
 wait-for: "#titles"
 // We check that there is no more "test_docs" appearing.
diff --git a/src/test/rustdoc-gui/src-font-size.goml b/src/test/rustdoc-gui/src-font-size.goml
new file mode 100644 (file)
index 0000000..b0b2f12
--- /dev/null
@@ -0,0 +1,12 @@
+// This test ensures that the "[src]" have the same font size as their headers
+// to avoid having some weird height difference in the background when the element
+// is selected.
+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)
+// 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 9b37703dded4b7acf9e494019ecc200c512ad997..f75de949292a1b151a5ddd234f3e64d1ac25c7f6 100644 (file)
@@ -1,5 +1,6 @@
 //! The point of this crate is to be able to have enough different "kinds" of
 //! documentation generated so we can test each different features.
+#![doc(html_playground_url="https://play.rust-lang.org/")]
 
 #![crate_name = "test_docs"]
 #![feature(rustdoc_internals)]
index b370dd012fae1d654cbbe592402e5fe9baa3f124..6e0ad8e0fa7fbcc48020e4bea2b82ae8ac393137 100644 (file)
@@ -1,12 +1,12 @@
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
 size: (433, 600)
 assert-attribute: (".top-doc", {"open": ""})
-click: (4, 280) // This is the position of the top doc comment toggle
+click: (4, 240) // This is the position of the top doc comment toggle
 assert-attribute-false: (".top-doc", {"open": ""})
-click: (4, 280)
+click: (4, 240)
 assert-attribute: (".top-doc", {"open": ""})
 // To ensure that the toggle isn't over the text, we check that the toggle isn't clicked.
-click: (3, 280)
+click: (3, 240)
 assert-attribute: (".top-doc", {"open": ""})
 
 // Assert the position of the toggle on the top doc block.
index eaa4c554d5a0fa9b2d9d9b4572faa9a7014ff9ed..e11aae21e3fa6367e9c914e02dba73fa52e2cd46 100644 (file)
@@ -1,10 +1,13 @@
 goto: file://|DOC_PATH|/test_docs/index.html
 assert-attribute: ("#main-content > details.top-doc", {"open": ""})
+assert-text: ("#toggle-all-docs", "[−]")
 click: "#toggle-all-docs"
 wait-for: 1000
 // This is now collapsed so there shouldn't be the "open" attribute on details.
 assert-attribute-false: ("#main-content > details.top-doc", {"open": ""})
+assert-text: ("#toggle-all-docs", "[+]")
 click: "#toggle-all-docs"
 wait-for: 1000
 // Not collapsed anymore so the "open" attribute should be back.
 assert-attribute: ("#main-content > details.top-doc", {"open": ""})
+assert-text: ("#toggle-all-docs", "[−]")
index 75159979e8890d10fd2368e5ec3eb88d2f17c0dd..587cbad68486422f1cb4d0ed487b1e011cac02d4 100644 (file)
@@ -28,7 +28,6 @@
 //! [unit::eq] //~ ERROR unresolved
 //! [tuple::eq] //~ ERROR unresolved
 //! [fn::eq] //~ ERROR unresolved
-//! [never::eq] //~ ERROR unresolved
 
 // FIXME(#78800): This breaks because it's a blanket impl
 // (I think? Might break for other reasons too.)
index 610c830560527035f65fe1d173ee235c134a94cf..4828a30446355d70b91c605165be598399076039 100644 (file)
@@ -53,17 +53,11 @@ error: unresolved link to `fn::eq`
 LL | //! [fn::eq]
    |      ^^^^^^ the builtin type `fn` has no associated item named `eq`
 
-error: unresolved link to `never::eq`
-  --> $DIR/non-path-primitives.rs:31:6
-   |
-LL | //! [never::eq]
-   |      ^^^^^^^^^ the builtin type `never` has no associated item named `eq`
-
 error: unresolved link to `reference::deref`
-  --> $DIR/non-path-primitives.rs:35:6
+  --> $DIR/non-path-primitives.rs:34:6
    |
 LL | //! [reference::deref]
    |      ^^^^^^^^^^^^^^^^ the builtin type `reference` has no associated item named `deref`
 
-error: aborting due to 9 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/test/rustdoc-ui/private-public-item-doc-test.rs b/src/test/rustdoc-ui/private-public-item-doc-test.rs
new file mode 100644 (file)
index 0000000..7cc62b3
--- /dev/null
@@ -0,0 +1,11 @@
+#![deny(rustdoc::private_doc_tests)]
+
+mod foo {
+    /// private doc test
+    ///
+    /// ```
+    /// assert!(false);
+    /// ```
+    //~^^^^^ ERROR documentation test in private item
+    pub fn bar() {}
+}
diff --git a/src/test/rustdoc-ui/private-public-item-doc-test.stderr b/src/test/rustdoc-ui/private-public-item-doc-test.stderr
new file mode 100644 (file)
index 0000000..f50dbd1
--- /dev/null
@@ -0,0 +1,18 @@
+error: documentation test in private item
+  --> $DIR/private-public-item-doc-test.rs:4:5
+   |
+LL | /     /// private doc test
+LL | |     ///
+LL | |     /// ```
+LL | |     /// assert!(false);
+LL | |     /// ```
+   | |___________^
+   |
+note: the lint level is defined here
+  --> $DIR/private-public-item-doc-test.rs:1:9
+   |
+LL | #![deny(rustdoc::private_doc_tests)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc-ui/public-reexported-item-doc-test.rs b/src/test/rustdoc-ui/public-reexported-item-doc-test.rs
new file mode 100644 (file)
index 0000000..b86a533
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+#![deny(rustdoc::private_doc_tests)]
+
+pub fn foo() {}
+
+mod private {
+    /// re-exported doc test
+    ///
+    /// ```
+    /// assert!(true);
+    /// ```
+    pub fn bar() {}
+}
+
+pub use private::bar;
index fe19dadbe0243113ffde82585b78e34123115ef8..94ade31b5e5f4ce4f12bc5c5a830dc0d7cd400da 100644 (file)
@@ -9,7 +9,7 @@
 
 }
 
-// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok : tt) *) {'
+// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok:tt)*) {'
 // @has - //pre '...'
 // @has - //pre '}'
 pub macro my_macro_2($($tok:tt)*) {
@@ -18,8 +18,8 @@
 
 // @has decl_macro/macro.my_macro_multi.html //pre 'pub macro my_macro_multi {'
 // @has - //pre '(_) => { ... },'
-// @has - //pre '($foo : ident.$bar : expr) => { ... },'
-// @has - //pre '($($foo : literal), +) => { ... },'
+// @has - //pre '($foo:ident . $bar:expr) => { ... },'
+// @has - //pre '($($foo:literal),+) => { ... },'
 // @has - //pre '}'
 pub macro my_macro_multi {
     (_) => {
@@ -33,7 +33,7 @@
     }
 }
 
-// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo : expr) {'
+// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo:expr) {'
 // @has - //pre '...'
 // @has - //pre '}'
 pub macro by_example_single {
 
 mod a {
     mod b {
-        // @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo : expr) {'
+        // @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo:expr) {'
         pub(in super) macro by_example_vis {
             ($foo:expr) => {}
         }
         mod c {
-            // @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo : expr) {'
+            // @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo:expr) {'
             pub(in a) macro by_example_vis_named {
                 ($foo:expr) => {}
             }
index 6189acb72542a613612d67d183886e28441e03ff..d32d3fc581f8aaca3d4edced4e69e49f270e8797 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"]' "[src]"
+// @has foo/trait.Iterator.html '//div[@id="method.zip"]//a[@class="srclink"]' "source"
 pub use std::iter::Iterator;
index 6a7dbb004a3626c29d5fc3d86fa3cda27c03bbff..359551ab78d1e060b2a484d98eceb2ecf33f488f 100644 (file)
@@ -5,8 +5,8 @@
 #[macro_use]
 extern crate external_macro_src;
 
-// @has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' '[src]'
+// @has foo/index.html '//a[@href="../src/foo/external-macro-src.rs.html#3-12"]' 'source'
 
 // @has foo/struct.Foo.html
-// @has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' '[src]'
+// @has - '//a[@href="../src/foo/external-macro-src.rs.html#12"]' 'source'
 make_foo!();
diff --git a/src/test/rustdoc/intra-doc/prim-associated-traits.rs b/src/test/rustdoc/intra-doc/prim-associated-traits.rs
new file mode 100644 (file)
index 0000000..8639a24
--- /dev/null
@@ -0,0 +1,46 @@
+#![feature(never_type)]
+use std::str::FromStr;
+
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f64.html#method.from_str"]' 'f64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f32.html#method.from_str"]' 'f32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.isize.html#method.from_str"]' 'isize::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i8.html#method.from_str"]' 'i8::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i16.html#method.from_str"]' 'i16::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i32.html#method.from_str"]' 'i32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i64.html#method.from_str"]' 'i64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i128.html#method.from_str"]' 'i128::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.usize.html#method.from_str"]' 'usize::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u8.html#method.from_str"]' 'u8::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u16.html#method.from_str"]' 'u16::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u32.html#method.from_str"]' 'u32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u64.html#method.from_str"]' 'u64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u128.html#method.from_str"]' 'u128::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.char.html#method.from_str"]' 'char::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.bool.html#method.from_str"]' 'bool::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.str.html#method.eq"]' 'str::eq()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.never.html#method.eq"]' 'never::eq()'
+/// [`f64::from_str()`] [`f32::from_str()`] [`isize::from_str()`] [`i8::from_str()`]
+/// [`i16::from_str()`] [`i32::from_str()`] [`i64::from_str()`] [`i128::from_str()`]
+/// [`u16::from_str()`] [`u32::from_str()`] [`u64::from_str()`] [`u128::from_str()`]
+/// [`usize::from_str()`] [`u8::from_str()`] [`char::from_str()`] [`bool::from_str()`]
+/// [`str::eq()`] [`never::eq()`]
+pub struct Number {
+    pub f_64: f64,
+    pub f_32: f32,
+    pub i_size: isize,
+    pub i_8: i8,
+    pub i_16: i16,
+    pub i_32: i32,
+    pub i_64: i64,
+    pub i_128: i128,
+    pub u_size: usize,
+    pub u_8: u8,
+    pub u_16: u16,
+    pub u_32: u32,
+    pub u_64: u64,
+    pub u_128: u128,
+    pub ch: char,
+    pub boolean: bool,
+    pub string: str,
+    pub n: !,
+}
index 653fd4c5e34e671e288d98fadca0254eb20cfeb4..ec007e36b726c8e8cd66a7090c6ac5b886aeb321 100644 (file)
@@ -1,8 +1,10 @@
 pub struct Foo;
 
-// @has issue_16265_1/traits/index.html '[src]'
+// @has issue_16265_1/traits/index.html 'source'
 pub mod traits {
     impl PartialEq for super::Foo {
-        fn eq(&self, _: &super::Foo) -> bool { true }
+        fn eq(&self, _: &super::Foo) -> bool {
+            true
+        }
     }
 }
index 00453a3633328a7f388f8eaf6f866b252e5b8569..d5cd18d9daf9d80449a6f6d73280fbe6978baaf1 100644 (file)
@@ -1,4 +1,4 @@
-// @has issue_16265_2/index.html '[src]'
+// @has issue_16265_2/index.html 'source'
 
 trait Y {}
-impl Y for Option<u32>{}
+impl Y for Option<u32> {}
index bd6f38e912338226d93b5f997f603f29f279158e..d5cb2c710cde891b4bcd85b12951ccfa87484899 100644 (file)
@@ -7,5 +7,5 @@
 extern crate issue_26606_macro;
 
 // @has issue_26606/constant.FOO.html
-// @has - '//a[@href="../src/issue_26606/issue-26606.rs.html#11"]' '[src]'
+// @has - '//a[@href="../src/issue_26606/issue-26606.rs.html#11"]' 'source'
 make_item!(FOO);
index 3761805b48b71ecc6f5c6f7b7faf1e7be99878d7..fc63ed343bda27cefb52a6258acb6b23c557af8e 100644 (file)
@@ -18,17 +18,18 @@ pub enum FooEnum {
     // @has - '//*[@id="variant.MixedHiddenFirst"]//code' 'MixedHiddenFirst(_, S)'
     // @count - '//*[@id="variant.MixedHiddenFirst.field.0"]' 0
     // @has - '//*[@id="variant.MixedHiddenFirst.field.1"]' '1: S'
-    MixedHiddenFirst(#[doc(hidden)] H, S),
+    MixedHiddenFirst(#[doc(hidden)] H, /** dox */ S),
     // @has - '//*[@id="variant.MixedHiddenLast"]//code' 'MixedHiddenLast(S, _)'
     // @has - '//*[@id="variant.MixedHiddenLast.field.0"]' '0: S'
     // @count - '//*[@id="variant.MixedHiddenLast.field.1"]' 0
-    MixedHiddenLast(S, #[doc(hidden)] H),
+    MixedHiddenLast(/** dox */ S, #[doc(hidden)] H),
     // @has - '//*[@id="variant.HiddenStruct"]//code' 'HiddenStruct'
     // @count - '//*[@id="variant.HiddenStruct.field.h"]' 0
     // @has - '//*[@id="variant.HiddenStruct.field.s"]' 's: S'
     HiddenStruct {
         #[doc(hidden)]
         h: H,
+        /// dox
         s: S,
     },
 }
diff --git a/src/test/rustdoc/macro-generated-macro.rs b/src/test/rustdoc/macro-generated-macro.rs
new file mode 100644 (file)
index 0000000..25d8bc3
--- /dev/null
@@ -0,0 +1,14 @@
+macro_rules! outer {
+    ($($matcher:tt)*) => {
+        #[macro_export]
+        macro_rules! inner {
+            (<= $($matcher)* =>) => {};
+        }
+    }
+}
+
+// @has macro_generated_macro/macro.inner.html //pre 'macro_rules! inner {'
+// @has - //pre '(<= type $($i : ident) :: * + $e : expr =>) => { ... };'
+outer!(type $($i:ident)::* + $e:expr);
+
+inner!(<= type foo::bar + x.sort() =>);
index 1cd454720e7d14250bc3fc07cb0e0be25f4dbcc9..ae0cf7a14789d78103c6cb4585ea36ab650153f7 100644 (file)
@@ -1,7 +1,7 @@
 // @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {'
 // @has - //pre '() => { ... };'
-// @has - //pre '($a : tt) => { ... };'
-// @has - //pre '($e : expr) => { ... };'
+// @has - //pre '($a:tt) => { ... };'
+// @has - //pre '($e:expr) => { ... };'
 #[macro_export]
 macro_rules! my_macro {
     () => [];
@@ -12,8 +12,8 @@ macro_rules! my_macro {
 // Check that exported macro defined in a module are shown at crate root.
 // @has macros/macro.my_sub_macro.html //pre 'macro_rules! my_sub_macro {'
 // @has - //pre '() => { ... };'
-// @has - //pre '($a : tt) => { ... };'
-// @has - //pre '($e : expr) => { ... };'
+// @has - //pre '($a:tt) => { ... };'
+// @has - //pre '($e:expr) => { ... };'
 mod sub {
     #[macro_export]
     macro_rules! my_sub_macro {
index 69d647a92e82b30090fe9328bf6a11232ea7edba..8ff114b993edbeb5cd285e76fbfc09c050137d96 100644 (file)
@@ -1,4 +1,4 @@
-<div class="docblock"><p>Hello world!
-Goodbye!
+<div class="docblock"><p>Hello world!</p>
+<p>Goodbye!
 Hello again!</p>
 </div>
\ No newline at end of file
diff --git a/src/test/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html b/src/test/rustdoc/mixing-doc-comments-and-attrs.S3_top-doc.html
new file mode 100644 (file)
index 0000000..a4ee4b1
--- /dev/null
@@ -0,0 +1,3 @@
+<div class="docblock"><p>Par 1</p>
+<p>Par 2</p>
+</div>
\ No newline at end of file
index 1aedd4d107c21ef3d972678088ef5a042a0c624f..a27c5ae6d0128c95d21a6f8dc791bfd8ca9542ad 100644 (file)
 #[doc = "Goodbye!"]
 /// Hello again!
 pub struct S2;
+
+// @has 'foo/struct.S3.html'
+// @snapshot S3_top-doc - '//details[@class="rustdoc-toggle top-doc"]/div[@class="docblock"]'
+/** Par 1
+*/ ///
+/// Par 2
+pub struct S3;
index 95f741807494cf8e8ba7b780ab2fb7d0783ecbd4..aea9b9f2b395dc1b85b63f0c891026607df629db 100644 (file)
@@ -5,7 +5,7 @@
 
 extern crate reexports;
 
-// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
+// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
 pub use reexports::addr_of;
 // @!has 'foo/macro.addr_of_crate.html'
 pub(crate) use reexports::addr_of_crate;
 
 pub mod outer {
     pub mod inner {
-        // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
+        // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
         pub use reexports::addr_of;
-        // @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place : expr) {'
+        // @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place:expr) {'
         pub(crate) use reexports::addr_of_crate;
-        // @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place : expr) {'
+        // @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place:expr) {'
         pub(super) use reexports::addr_of_super;
         // @!has 'foo/outer/inner/macro.addr_of_self.html'
         pub(self) use reexports::addr_of_self;
index 3b315308470356e4eae661fd59da051143927ad3..7abcbfb618122194125511eab7812079367b65e8 100644 (file)
@@ -4,7 +4,7 @@
 
 extern crate reexports;
 
-// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
+// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
 pub use reexports::addr_of;
 // @!has 'foo/macro.addr_of_crate.html'
 pub(crate) use reexports::addr_of_crate;
@@ -60,7 +60,7 @@
 
 pub mod outer {
     pub mod inner {
-        // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
+        // @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
         pub use reexports::addr_of;
         // @!has 'foo/outer/inner/macro.addr_of_crate.html'
         pub(crate) use reexports::addr_of_crate;
index f9ac836c9b18faa33fe5c4c2ac1340d9eca864b4..46b8778217d27fd5d8f4380865e05822495ce436 100644 (file)
@@ -2,11 +2,11 @@
 
 // @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"]' '[src]'
+// @!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"]' '[src]'
+// @!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"]' '[src]'
+// @has - '//div[@id="impl-Any"]//a[@class="srclink"]' 'source'
 pub struct Unsized {
     data: [u8],
 }
index 6de198453cd273d2fde91ceb7580d280a630987e..7e1cada4b9828c939d892e9e56505e1a83b9fa67 100644 (file)
@@ -2,7 +2,7 @@
 pub struct Foo {
     // @has - //pre "pub a: ()"
     pub a: (),
-    // @has - //pre "// some fields omitted"
+    // @has - //pre "/* private fields */"
     // @!has - //pre "b: ()"
     b: (),
     // @!has - //pre "c: usize"
@@ -16,7 +16,7 @@ pub struct Foo {
 pub struct Bar {
     // @has - //pre "pub a: ()"
     pub a: (),
-    // @!has - //pre "// some fields omitted"
+    // @!has - //pre "/* private fields */"
 }
 
 // @has structfields/enum.Qux.html
@@ -29,11 +29,11 @@ pub enum Qux {
         b: (),
         // @has - //pre "c: usize"
         c: usize,
-        // @has - //pre "// some fields omitted"
+        // @has - //pre "/* private fields */"
     },
 }
 
-// @has structfields/struct.Baz.html //pre "pub struct Baz { /* fields omitted */ }"
+// @has structfields/struct.Baz.html //pre "pub struct Baz { /* private fields */ }"
 pub struct Baz {
     x: u8,
     #[doc(hidden)]
index 5e56bb5819a104b55acc98780074265dfc32bd9f..6de35e3233b0573234b976f39636e7b3d8427a46 100644 (file)
@@ -1,6 +1,6 @@
 #![crate_name = "foo"]
 
-// @has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' '[src]'
+// @has foo/index.html '//a[@href="../src/foo/thread-local-src.rs.html#1-6"]' 'source'
 
-// @has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' '[src]'
+// @has foo/constant.FOO.html '//a[@href="../src/foo/thread-local-src.rs.html#6"]' 'source'
 thread_local!(pub static FOO: bool = false);
index 937646987dd4f2c5532bd4e562ef67d3fbac1347..c1df4613e3562ccd9dbc286bc2a098fcb8d36260 100644 (file)
@@ -55,7 +55,7 @@ pub union Union {
 
 // @has 'toggle_item_contents/struct.PrivStruct.html'
 // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0
-// @has - '//div[@class="docblock item-decl"]' 'fields omitted'
+// @has - '//div[@class="docblock item-decl"]' '/* private fields */'
 pub struct PrivStruct {
     a: usize,
     b: usize,
index 77116695690fc75366d3ef4ddbf62b28a70bf10a..a6367efba6121f1ee85c19b7f9b45ce029f6a086 100644 (file)
@@ -1,26 +1,26 @@
 #![crate_name = "quix"]
 pub trait Foo {
-    // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' '[src]'
+    // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#4"]' 'source'
     fn required();
 
-    // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' '[src]'
+    // @has quix/trait.Foo.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source'
     fn provided() {}
 }
 
 pub struct Bar;
 
 impl Foo for Bar {
-    // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' '[src]'
+    // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#14"]' 'source'
     fn required() {}
-    // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' '[src]'
+    // @has quix/struct.Bar.html '//a[@href="../src/quix/trait-src-link.rs.html#7"]' 'source'
 }
 
 pub struct Baz;
 
 impl Foo for Baz {
-    // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' '[src]'
+    // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#22"]' 'source'
     fn required() {}
 
-    // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' '[src]'
+    // @has quix/struct.Baz.html '//a[@href="../src/quix/trait-src-link.rs.html#25"]' 'source'
     fn provided() {}
 }
index 2e339fe82649d6ca67a422bf58cdb495bc959b0c..31426131bc2c1897312145ebd8d418413138468a 100644 (file)
@@ -24,6 +24,9 @@ pub struct Foo(
 // @has - '//*[@id="variant.BarVariant.field.0"]' '0: String'
 // @has - '//*[@id="variant.BarVariant.fields"]//*[@class="docblock"]' 'Hello docs'
 // @matches - '//*[@id="variant.FooVariant.fields"]/h4' '^Fields$'
+// @has - '//*[@id="variant.BazVariant.fields"]//*[@class="docblock"]' 'dox'
+// @has - '//*[@id="variant.OtherVariant.fields"]//*[@class="docblock"]' 'dox'
+// @!matches - '//*[@id="variant.QuuxVariant.fields"]/h4' '^Tuple Fields$'
 pub enum Bar {
     BarVariant(
         /// Hello docs
@@ -33,4 +36,15 @@ pub enum Bar {
        /// hello
        x: u32,
     },
+    BazVariant(
+        String,
+        /// dox
+        u32,
+    ),
+    OtherVariant(
+        /// dox
+        String,
+        u32,
+    ),
+    QuuxVariant(String),
 }
index 8918622773205d8262b0ed4e0c50a5d4d9e3a7f1..5a788eb1b1cae65bef324d681238905a357fa462 100644 (file)
@@ -2,7 +2,7 @@
 pub union U {
     // @has - //pre "pub a: u8"
     pub a: u8,
-    // @has - //pre "// some fields omitted"
+    // @has - //pre "/* private fields */"
     // @!has - //pre "b: u16"
     b: u16,
 }
diff --git a/src/test/rustdoc/where-clause-order.rs b/src/test/rustdoc/where-clause-order.rs
new file mode 100644 (file)
index 0000000..d0d89cb
--- /dev/null
@@ -0,0 +1,15 @@
+#![crate_name = "foo"]
+
+pub trait SomeTrait<Rhs = Self>
+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
+    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
+{}
index de0df0aae82d7aa5c997a30a24337f909d6e6488..ee668501ae78b859dbe461d7e5e483b9c8dd3759 100644 (file)
@@ -44,7 +44,7 @@ fn check_fn(
     ) {
         let item = match cx.tcx.hir().get(id) {
             Node::Item(item) => item,
-            _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id).expect_owner()),
+            _ => cx.tcx.hir().expect_item(cx.tcx.hir().get_parent_item(id)),
         };
 
         let allowed = |attr| pprust::attribute_to_string(attr).contains("allowed_attr");
index 66cd94d7a1b3730f224fdd13c3c44ca10ebb44ba..974a1d961a05e07c737a2873b8b147786d3a145c 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>>::bar::<ReStatic, char>}`
+    //[verbose]~| found fn item `fn() {<i8 as Foo<ReStatic, ReStatic, u32>>::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 b831f3b7a76d23aef2deaf317863be67d68ee0c8..cf480223da2b3a5496529e1f24fbde565e7b6e02 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>>::bar::<ReStatic, char>} defined here
+   |     --------------------------- fn() {<i8 as Foo<ReStatic, ReStatic, u32>>::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>>::bar::<ReStatic, char>}`
+                found fn item `fn() {<i8 as Foo<ReStatic, ReStatic, u32>>::bar::<ReStatic, char>}`
 help: use parentheses to call this function
    |
 LL |     let x: () = <i8 as Foo<'static, 'static,  u32>>::bar::<'static, char>();
index 22484ba6378d32af0660dc36c60bfec20a740313..ab70c5b91c65c73ea98911ac6569e712d82498a0 100644 (file)
@@ -1 +1 @@
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"id":0,"is_placeholder":false}
index ae56bef35ffe70497effb35bc69f15324a97cf0d..f3663d9953b8aeea7995f579a303ef22a1dedca8 100644 (file)
@@ -1 +1 @@
-{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null}
+{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"id":0,"is_placeholder":false}
diff --git a/src/test/ui/async-await/interior-with-const-generic-expr.rs b/src/test/ui/async-await/interior-with-const-generic-expr.rs
new file mode 100644 (file)
index 0000000..86ba758
--- /dev/null
@@ -0,0 +1,26 @@
+// edition:2018
+// run-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+#![allow(unused)]
+
+fn main() {
+    let x = test();
+}
+
+fn concat<const A: usize, const B: usize>(a: [f32; A], b: [f32; B]) -> [f32; A + B] {
+    todo!()
+}
+
+async fn reverse<const A: usize>(x: [f32; A]) -> [f32; A] {
+    todo!()
+}
+
+async fn test() {
+    let a = [0.0];
+    let b = [1.0, 2.0];
+    let ab = concat(a,b);
+    let ba = reverse(ab).await;
+    println!("{:?}", ba);
+}
diff --git a/src/test/ui/borrowck/issue-92015.rs b/src/test/ui/borrowck/issue-92015.rs
new file mode 100644 (file)
index 0000000..16d6517
--- /dev/null
@@ -0,0 +1,7 @@
+// Regression test for #92105.
+// ICE when mutating immutable reference from last statement of a block.
+
+fn main() {
+    let foo = Some(&0).unwrap();
+    *foo = 1; //~ ERROR cannot assign
+}
diff --git a/src/test/ui/borrowck/issue-92015.stderr b/src/test/ui/borrowck/issue-92015.stderr
new file mode 100644 (file)
index 0000000..32a65d3
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
+  --> $DIR/issue-92015.rs:6:5
+   |
+LL |     let foo = Some(&0).unwrap();
+   |         --- help: consider changing this to be a mutable reference: `&mut i32`
+LL |     *foo = 1;
+   |     ^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/src/test/ui/c-variadic/variadic-unreachable-arg-error.rs b/src/test/ui/c-variadic/variadic-unreachable-arg-error.rs
new file mode 100644 (file)
index 0000000..f60f6f3
--- /dev/null
@@ -0,0 +1,14 @@
+// check-pass
+
+#![feature(c_variadic)]
+
+extern "C" {
+    fn foo(f: isize, x: u8, ...);
+}
+
+fn main() {
+    unsafe {
+        // FIXME: Ideally we could give an unreachable warning
+        foo(1, loop {}, 1usize);
+    }
+}
index 7a4b21f02236568626f374e5d18b4f4354bfcc24..2bcbd792e3a834186f1a86a1eb420fe1e21ed468 100644 (file)
@@ -15,6 +15,7 @@ fn main() {
         //~^ NOTE: Capturing m[] -> MutBorrow
         //~| NOTE: Min Capture m[] -> MutBorrow
         m[1] += 40;
+        //~^ NOTE: Capturing m[] -> MutBorrow
     };
 
     c();
index 69ec53447b8a6bbf3043f4504b5e7d6b96fa1e3d..129b26456ce1d5a6fd6abed645cac3303100c3f4 100644 (file)
@@ -15,7 +15,7 @@ LL | |
 LL | |
 LL | |         m[0] += 10;
 ...  |
-LL | |         m[1] += 40;
+LL | |
 LL | |     };
    | |_____^
    |
@@ -24,6 +24,11 @@ note: Capturing m[] -> MutBorrow
    |
 LL |         m[0] += 10;
    |         ^
+note: Capturing m[] -> MutBorrow
+  --> $DIR/arrays-completely-captured.rs:17:9
+   |
+LL |         m[1] += 40;
+   |         ^
 
 error: Min Capture analysis includes:
   --> $DIR/arrays-completely-captured.rs:11:5
@@ -33,7 +38,7 @@ LL | |
 LL | |
 LL | |         m[0] += 10;
 ...  |
-LL | |         m[1] += 40;
+LL | |
 LL | |     };
    | |_____^
    |
index 9918802334ecc4d0bbe96faa6e19413f4d86fb70..6c65a7bf87b96c4aa6c4884175315f7092acb7d5 100644 (file)
@@ -15,6 +15,8 @@ fn arrays() {
     //~| ERROR: Min Capture analysis includes:
         let [a, b, .., e] = arr;
         //~^ NOTE: Capturing arr[Index] -> ByValue
+        //~| NOTE: Capturing arr[Index] -> ByValue
+        //~| NOTE: Capturing arr[Index] -> ByValue
         //~| NOTE: Min Capture arr[] -> ByValue
         assert_eq!(a, "A");
         assert_eq!(b, "B");
index b53adb5248161ef23cffb10c4cbd3101a0212d90..44fbe6d8158f221c07538151a3b2a0d4422fbf84 100644 (file)
@@ -8,7 +8,7 @@ LL |     let c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/destructure_patterns.rs:36:13
+  --> $DIR/destructure_patterns.rs:38:13
    |
 LL |     let c = #[rustc_capture_analysis]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     let c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/destructure_patterns.rs:56:13
+  --> $DIR/destructure_patterns.rs:58:13
    |
 LL |     let c = #[rustc_capture_analysis]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -42,6 +42,16 @@ note: Capturing arr[Index] -> ByValue
    |
 LL |         let [a, b, .., e] = arr;
    |                             ^^^
+note: Capturing arr[Index] -> ByValue
+  --> $DIR/destructure_patterns.rs:16:29
+   |
+LL |         let [a, b, .., e] = arr;
+   |                             ^^^
+note: Capturing arr[Index] -> ByValue
+  --> $DIR/destructure_patterns.rs:16:29
+   |
+LL |         let [a, b, .., e] = arr;
+   |                             ^^^
 
 error: Min Capture analysis includes:
   --> $DIR/destructure_patterns.rs:13:5
@@ -62,7 +72,7 @@ LL |         let [a, b, .., e] = arr;
    |                             ^^^
 
 error: First Pass analysis includes:
-  --> $DIR/destructure_patterns.rs:39:5
+  --> $DIR/destructure_patterns.rs:41:5
    |
 LL | /     || {
 LL | |
@@ -74,18 +84,18 @@ LL | |     };
    | |_____^
    |
 note: Capturing p[(0, 0)] -> MutBorrow
-  --> $DIR/destructure_patterns.rs:42:58
+  --> $DIR/destructure_patterns.rs:44:58
    |
 LL |         let Point { x: ref mut x, y: _, id: moved_id } = p;
    |                                                          ^
 note: Capturing p[(2, 0)] -> ByValue
-  --> $DIR/destructure_patterns.rs:42:58
+  --> $DIR/destructure_patterns.rs:44:58
    |
 LL |         let Point { x: ref mut x, y: _, id: moved_id } = p;
    |                                                          ^
 
 error: Min Capture analysis includes:
-  --> $DIR/destructure_patterns.rs:39:5
+  --> $DIR/destructure_patterns.rs:41:5
    |
 LL | /     || {
 LL | |
@@ -97,18 +107,18 @@ LL | |     };
    | |_____^
    |
 note: Min Capture p[(0, 0)] -> MutBorrow
-  --> $DIR/destructure_patterns.rs:42:58
+  --> $DIR/destructure_patterns.rs:44:58
    |
 LL |         let Point { x: ref mut x, y: _, id: moved_id } = p;
    |                                                          ^
 note: Min Capture p[(2, 0)] -> ByValue
-  --> $DIR/destructure_patterns.rs:42:58
+  --> $DIR/destructure_patterns.rs:44:58
    |
 LL |         let Point { x: ref mut x, y: _, id: moved_id } = p;
    |                                                          ^
 
 error: First Pass analysis includes:
-  --> $DIR/destructure_patterns.rs:59:5
+  --> $DIR/destructure_patterns.rs:61:5
    |
 LL | /     || {
 LL | |
@@ -120,23 +130,23 @@ LL | |     };
    | |_____^
    |
 note: Capturing t[(0, 0)] -> MutBorrow
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
 note: Capturing t[(1, 0)] -> ImmBorrow
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
 note: Capturing t[(2, 0),(0, 0)] -> ByValue
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
 
 error: Min Capture analysis includes:
-  --> $DIR/destructure_patterns.rs:59:5
+  --> $DIR/destructure_patterns.rs:61:5
    |
 LL | /     || {
 LL | |
@@ -148,17 +158,17 @@ LL | |     };
    | |_____^
    |
 note: Min Capture t[(0, 0)] -> MutBorrow
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
 note: Min Capture t[(1, 0)] -> ImmBorrow
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
 note: Min Capture t[(2, 0),(0, 0)] -> ByValue
-  --> $DIR/destructure_patterns.rs:62:54
+  --> $DIR/destructure_patterns.rs:64:54
    |
 LL |         let (ref mut x, ref ref_str, (moved_s, _)) = t;
    |                                                      ^
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.rs
new file mode 100644 (file)
index 0000000..46b5484
--- /dev/null
@@ -0,0 +1,25 @@
+// edition:2021
+
+// Test that we point to the correct location that results a union being captured.
+// Union is special because it can't be disjointly captured.
+
+union A {
+    y: u32,
+    x: (),
+}
+
+fn main() {
+    let mut a = A { y: 1 };
+    let mut c = || {
+    //~^ borrow of `a.y` occurs here
+        let _ = unsafe { &a.y };
+        let _ = &mut a;
+        //~^ borrow occurs due to use in closure
+        let _ = unsafe { &mut a.y };
+    };
+    a.y = 1;
+    //~^ cannot assign to `a.y` because it is borrowed [E0506]
+    //~| assignment to borrowed `a.y` occurs here
+    c();
+    //~^ borrow later used here
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/union.stderr
new file mode 100644 (file)
index 0000000..7c34e23
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0506]: cannot assign to `a.y` because it is borrowed
+  --> $DIR/union.rs:20:5
+   |
+LL |     let mut c = || {
+   |                 -- borrow of `a.y` occurs here
+...
+LL |         let _ = &mut a;
+   |                      - borrow occurs due to use in closure
+...
+LL |     a.y = 1;
+   |     ^^^^^^^ assignment to borrowed `a.y` occurs here
+...
+LL |     c();
+   |     - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0506`.
index f6775b3a3a5ac4a827db7e9f11250545df437de0..22eae744b80806b57b3d9ceff67e23f95d3d265a 100644 (file)
@@ -40,6 +40,7 @@ fn main() {
         //~| NOTE: Min Capture p[(1, 0)] -> MutBorrow
         c2();
         println!("{}", p.y);
+        //~^ NOTE: Capturing p[(1, 0)] -> ImmBorrow
     };
 
     c1();
index 013bc74e67e1ecdf2d09a4b5d7eb3486e7900521..a50d0c6a182bc5f393668d272012648120311532 100644 (file)
@@ -58,7 +58,7 @@ LL | |
 LL | |
 LL | |         println!("{}", p.x);
 ...  |
-LL | |         println!("{}", p.y);
+LL | |
 LL | |     };
    | |_____^
    |
@@ -72,6 +72,11 @@ note: Capturing p[(1, 0)] -> MutBorrow
    |
 LL |         || p.y += incr;
    |            ^^^
+note: Capturing p[(1, 0)] -> ImmBorrow
+  --> $DIR/nested-closure.rs:42:24
+   |
+LL |         println!("{}", p.y);
+   |                        ^^^
 
 error: Min Capture analysis includes:
   --> $DIR/nested-closure.rs:22:5
@@ -81,7 +86,7 @@ LL | |
 LL | |
 LL | |         println!("{}", p.x);
 ...  |
-LL | |         println!("{}", p.y);
+LL | |
 LL | |     };
    | |_____^
    |
index 7d472ad020f29444667b73af854a43dce327b785..3ed780f51c73b6b6f4a54130faccad04c9afbdfc 100644 (file)
@@ -48,6 +48,7 @@ struct Foo { x: String, y: u16 }
     //~^ ERROR: First Pass analysis includes:
     //~| ERROR: Min Capture analysis includes:
         let z1: &String = &foo.x;
+        //~^ NOTE: Capturing foo[] -> ImmBorrow
         let z2: &mut u16 = &mut foo.y;
         //~^ NOTE: Capturing foo[] -> MutBorrow
         //~| NOTE: Min Capture foo[] -> MutBorrow
index 405f66210aa55f43abfd4b6a9b610ecc0c54ea37..580061ebc6ed900c675df833ae6988d13f564d40 100644 (file)
@@ -17,7 +17,7 @@ LL |     let mut c = #[rustc_capture_analysis]
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
 
 error[E0658]: attributes on expressions are experimental
-  --> $DIR/repr_packed.rs:78:13
+  --> $DIR/repr_packed.rs:79:13
    |
 LL |     let c = #[rustc_capture_analysis]
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,8 +83,13 @@ LL | |         println!("({}, {})", z1, z2);
 LL | |     };
    | |_____^
    |
+note: Capturing foo[] -> ImmBorrow
+  --> $DIR/repr_packed.rs:50:28
+   |
+LL |         let z1: &String = &foo.x;
+   |                            ^^^^^
 note: Capturing foo[] -> MutBorrow
-  --> $DIR/repr_packed.rs:51:33
+  --> $DIR/repr_packed.rs:52:33
    |
 LL |         let z2: &mut u16 = &mut foo.y;
    |                                 ^^^^^
@@ -102,13 +107,13 @@ LL | |     };
    | |_____^
    |
 note: Min Capture foo[] -> MutBorrow
-  --> $DIR/repr_packed.rs:51:33
+  --> $DIR/repr_packed.rs:52:33
    |
 LL |         let z2: &mut u16 = &mut foo.y;
    |                                 ^^^^^
 
 error: First Pass analysis includes:
-  --> $DIR/repr_packed.rs:81:5
+  --> $DIR/repr_packed.rs:82:5
    |
 LL | /     || {
 LL | |
@@ -120,18 +125,18 @@ LL | |     };
    | |_____^
    |
 note: Capturing foo[] -> ImmBorrow
-  --> $DIR/repr_packed.rs:84:24
+  --> $DIR/repr_packed.rs:85:24
    |
 LL |         println!("{}", foo.x);
    |                        ^^^^^
 note: Capturing foo[(0, 0)] -> ByValue
-  --> $DIR/repr_packed.rs:88:18
+  --> $DIR/repr_packed.rs:89:18
    |
 LL |         let _z = foo.x;
    |                  ^^^^^
 
 error: Min Capture analysis includes:
-  --> $DIR/repr_packed.rs:81:5
+  --> $DIR/repr_packed.rs:82:5
    |
 LL | /     || {
 LL | |
@@ -143,7 +148,7 @@ LL | |     };
    | |_____^
    |
 note: Min Capture foo[] -> ByValue
-  --> $DIR/repr_packed.rs:84:24
+  --> $DIR/repr_packed.rs:85:24
    |
 LL |         println!("{}", foo.x);
    |                        ^^^^^ foo[] used here
diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-8.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-8.rs
new file mode 100644 (file)
index 0000000..1d7fa78
--- /dev/null
@@ -0,0 +1,3 @@
+// compile-flags: --cfg )
+// error-pattern: invalid `--cfg` argument: `)` (expected `key` or `key="value"`)
+fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-8.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-8.stderr
new file mode 100644 (file)
index 0000000..7bb1814
--- /dev/null
@@ -0,0 +1,2 @@
+error: invalid `--cfg` argument: `)` (expected `key` or `key="value"`)
+
diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs
new file mode 100644 (file)
index 0000000..56b88a4
--- /dev/null
@@ -0,0 +1,12 @@
+// To avoid having to `or` gate `_` as an expr.
+#![feature(generic_arg_infer)]
+
+fn foo() -> [u8; _] {
+    //~^ ERROR the const placeholder `_` is not allowed within types on item signatures for generics
+    // FIXME(generic_arg_infer): this error message should say in the return type or sth like that.
+    [0; 3]
+}
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr b/src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr
new file mode 100644 (file)
index 0000000..eaa12b4
--- /dev/null
@@ -0,0 +1,9 @@
+error[E0121]: the const placeholder `_` is not allowed within types on item signatures for generics
+  --> $DIR/array-in-sig.rs:4:18
+   |
+LL | fn foo() -> [u8; _] {
+   |                  ^ not allowed in type signatures
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs b/src/test/ui/const-generics/generic_arg_infer/array-repeat-expr.rs
new file mode 100644 (file)
index 0000000..d3e53d7
--- /dev/null
@@ -0,0 +1,13 @@
+// run-pass
+
+// To avoid having to `or` gate `_` as an expr.
+#![feature(generic_arg_infer)]
+
+fn foo() -> [u8; 3] {
+    let x: [u8; _] = [0; _];
+    x
+}
+
+fn main() {
+    assert_eq!([0; _], foo());
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs
new file mode 100644 (file)
index 0000000..29aa0f5
--- /dev/null
@@ -0,0 +1,22 @@
+#![feature(generic_arg_infer)]
+
+struct All<'a, T, const N: usize> {
+  v: &'a T,
+}
+
+struct BadInfer<_>;
+//~^ ERROR expected identifier
+//~| ERROR parameter `_` is never used
+
+fn all_fn<'a, T, const N: usize>() {}
+
+fn bad_infer_fn<_>() {}
+//~^ ERROR expected identifier
+
+
+fn main() {
+  let a: All<_, _, _>;
+  all_fn();
+  let v: [u8; _];
+  let v: [u8; 10] = [0; _];
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr b/src/test/ui/const-generics/generic_arg_infer/infer-arg-test.stderr
new file mode 100644 (file)
index 0000000..e6d0c74
--- /dev/null
@@ -0,0 +1,24 @@
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/infer-arg-test.rs:7:17
+   |
+LL | struct BadInfer<_>;
+   |                 ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/infer-arg-test.rs:13:17
+   |
+LL | fn bad_infer_fn<_>() {}
+   |                 ^ expected identifier, found reserved identifier
+
+error[E0392]: parameter `_` is never used
+  --> $DIR/infer-arg-test.rs:7:17
+   |
+LL | struct BadInfer<_>;
+   |                 ^ unused parameter
+   |
+   = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `_` to be a const parameter, use `const _: usize` instead
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/const-generics/generic_arg_infer/infer_arg_and_const_arg.rs b/src/test/ui/const-generics/generic_arg_infer/infer_arg_and_const_arg.rs
new file mode 100644 (file)
index 0000000..23c8d75
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+#![feature(generic_arg_infer)]
+
+struct Foo<const N: bool, const M: u8>;
+struct Bar<const N: u8, const M: u32>;
+
+fn main() {
+    let _: Foo<true, _> = Foo::<_, 1>;
+    let _: Foo<_, 1> = Foo::<true, _>;
+    let _: Bar<1, _> = Bar::<_, 300>;
+    let _: Bar<_, 300> = Bar::<1, _>;
+}
index f074a65313f12e3156ed9f8983d039eb031e7ae8..3a2b291d7ba1f127fd71bdbb95c4c8d3ed2c9a6c 100644 (file)
@@ -4,13 +4,6 @@ error[E0770]: the type of const parameters must not depend on other generic para
 LL | fn foo<const N: usize, const A: [u8; N]>() {}
    |                                      ^ the type must not depend on the parameter `N`
 
-error[E0308]: mismatched types
-  --> $DIR/issue-62878.rs:10:15
-   |
-LL |     foo::<_, {[1]}>();
-   |               ^^^ expected `usize`, found array `[{integer}; 1]`
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
-Some errors have detailed explanations: E0308, E0770.
-For more information about an error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0770`.
index 38f5ff77b56a9ac1e5d7a37e3bbbb1744f84ade1..578ce765b2fb82048309f1be5ef325f467ed28c2 100644 (file)
@@ -7,6 +7,5 @@
 //[min]~| ERROR `[u8; _]` is forbidden as the type of a const generic parameter
 
 fn main() {
-    foo::<_, {[1]}>();
-    //[full]~^ ERROR mismatched types
+    foo::<_, { [1] }>();
 }
diff --git a/src/test/ui/consts/const-block-const-bound.rs b/src/test/ui/consts/const-block-const-bound.rs
new file mode 100644 (file)
index 0000000..3bfc759
--- /dev/null
@@ -0,0 +1,17 @@
+#![allow(unused)]
+#![feature(const_fn_trait_bound, const_trait_impl, inline_const)]
+
+const fn f<T: ~const Drop>(x: T) {}
+
+struct UnconstDrop;
+
+impl Drop for UnconstDrop {
+    fn drop(&mut self) {}
+}
+
+fn main() {
+    const {
+        f(UnconstDrop);
+        //~^ ERROR the trait bound `UnconstDrop: Drop` is not satisfied
+    }
+}
diff --git a/src/test/ui/consts/const-block-const-bound.stderr b/src/test/ui/consts/const-block-const-bound.stderr
new file mode 100644 (file)
index 0000000..0e6e426
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `UnconstDrop: Drop` is not satisfied
+  --> $DIR/const-block-const-bound.rs:14:11
+   |
+LL |         f(UnconstDrop);
+   |         - ^^^^^^^^^^^ the trait `Drop` is not implemented for `UnconstDrop`
+   |         |
+   |         required by a bound introduced by this call
+   |
+note: required by a bound in `f`
+  --> $DIR/const-block-const-bound.rs:4:15
+   |
+LL | const fn f<T: ~const Drop>(x: T) {}
+   |               ^^^^^^^^^^^ required by this bound in `f`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | fn main() where UnconstDrop: Drop {
+   |           +++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
index c17f02d58f325d57d073a7167baac194cca4de9d..49eede4794b37728d65ff03f6b9c4cf62412512a 100644 (file)
@@ -1,5 +1,35 @@
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/feature-gate-generic_arg_infer.rs:11:27
+   |
+LL |     let _x: [u8; 3] = [0; _];
+   |                           ^
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/feature-gate-generic_arg_infer.rs:11:27
+   |
+LL |     let _x: [u8; 3] = [0; _];
+   |                           ^ `_` not allowed here
+
+error[E0658]: using `_` for array lengths is unstable
+  --> $DIR/feature-gate-generic_arg_infer.rs:14:18
+   |
+LL |     let _y: [u8; _] = [0; 3];
+   |                  ^
+   |
+   = note: see issue #85077 <https://github.com/rust-lang/rust/issues/85077> for more information
+   = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
+
+error: in expressions, `_` can only be used on the left-hand side of an assignment
+  --> $DIR/feature-gate-generic_arg_infer.rs:14:18
+   |
+LL |     let _y: [u8; _] = [0; 3];
+   |                  ^ `_` not allowed here
+
 error[E0747]: type provided when a constant was expected
-  --> $DIR/feature-gate-generic_arg_infer.rs:11:20
+  --> $DIR/feature-gate-generic_arg_infer.rs:20:20
    |
 LL |     let _x = foo::<_>([1,2]);
    |                    ^
@@ -7,6 +37,7 @@ LL |     let _x = foo::<_>([1,2]);
    = help: const arguments cannot yet be inferred with `_`
    = help: add `#![feature(generic_arg_infer)]` to the crate attributes to enable
 
-error: aborting due to previous error
+error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0747`.
+Some errors have detailed explanations: E0658, E0747.
+For more information about an error, try `rustc --explain E0658`.
index 4729773b12ef04d9c8f9186313209b881f9aec1c..afd14b7843e20fd169c52d1d71c962672980fe84 100644 (file)
@@ -7,7 +7,17 @@
   [0; N]
 }
 
+fn bar() {
+    let _x: [u8; 3] = [0; _];
+    //[normal]~^ ERROR: using `_` for array lengths is unstable
+    //[normal]~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment
+    let _y: [u8; _] = [0; 3];
+    //[normal]~^ ERROR: using `_` for array lengths is unstable
+    //[normal]~| ERROR: in expressions, `_` can only be used on the left-hand side of an assignment
+}
+
 fn main() {
     let _x = foo::<_>([1,2]);
     //[normal]~^ ERROR: type provided when a constant was expected
+    let _y = bar();
 }
index 20e61303e36aafe41b64d7772c5f3a3c8cc89b01..41fb1456f869e7f68ef344f6f9cf73b0b045e180 100644 (file)
@@ -1,87 +1,3 @@
-error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/feature-gate-in_band_lifetimes.rs:50:14
-   |
-LL | impl MyTrait<'a> for Y<&'a u8> {
-   |     -        ^^ undeclared lifetime
-   |     |
-   |     help: consider introducing lifetime `'a` here: `<'a>`
-   |
-   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
-
-error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/feature-gate-in_band_lifetimes.rs:50:25
-   |
-LL | impl MyTrait<'a> for Y<&'a u8> {
-   |     -                   ^^ undeclared lifetime
-   |     |
-   |     help: consider introducing lifetime `'a` here: `<'a>`
-   |
-   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
-
-error[E0261]: use of undeclared lifetime name `'a`
-  --> $DIR/feature-gate-in_band_lifetimes.rs:53:31
-   |
-LL |     fn my_lifetime(&self) -> &'a u8 { self.0 }
-   |                               ^^ undeclared lifetime
-   |
-   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
-help: consider introducing lifetime `'a` here
-   |
-LL | impl<'a> MyTrait<'a> for Y<&'a u8> {
-   |     ++++
-help: consider introducing lifetime `'a` here
-   |
-LL |     fn my_lifetime<'a>(&self) -> &'a u8 { self.0 }
-   |                   ++++
-
-error[E0261]: use of undeclared lifetime name `'b`
-  --> $DIR/feature-gate-in_band_lifetimes.rs:55:27
-   |
-LL |     fn any_lifetime() -> &'b u8 { &0 }
-   |                           ^^ undeclared lifetime
-   |
-   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
-help: consider introducing lifetime `'b` here
-   |
-LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
-   |     ++++
-help: consider introducing lifetime `'b` here
-   |
-LL |     fn any_lifetime<'b>() -> &'b u8 { &0 }
-   |                    ++++
-
-error[E0261]: use of undeclared lifetime name `'b`
-  --> $DIR/feature-gate-in_band_lifetimes.rs:57:27
-   |
-LL |     fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
-   |                           ^^ undeclared lifetime
-   |
-   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
-help: consider introducing lifetime `'b` here
-   |
-LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
-   |     ++++
-help: consider introducing lifetime `'b` here
-   |
-LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
-   |                         ++++
-
-error[E0261]: use of undeclared lifetime name `'b`
-  --> $DIR/feature-gate-in_band_lifetimes.rs:57:40
-   |
-LL |     fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
-   |                                        ^^ undeclared lifetime
-   |
-   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
-help: consider introducing lifetime `'b` here
-   |
-LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
-   |     ++++
-help: consider introducing lifetime `'b` here
-   |
-LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
-   |                         ++++
-
 error[E0261]: use of undeclared lifetime name `'x`
   --> $DIR/feature-gate-in_band_lifetimes.rs:3:12
    |
@@ -178,6 +94,90 @@ help: consider introducing lifetime `'a` here
 LL |     fn inner<'a>(&self) -> &'a u8 {
    |             ++++
 
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/feature-gate-in_band_lifetimes.rs:50:14
+   |
+LL | impl MyTrait<'a> for Y<&'a u8> {
+   |     -        ^^ undeclared lifetime
+   |     |
+   |     help: consider introducing lifetime `'a` here: `<'a>`
+   |
+   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
+
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/feature-gate-in_band_lifetimes.rs:50:25
+   |
+LL | impl MyTrait<'a> for Y<&'a u8> {
+   |     -                   ^^ undeclared lifetime
+   |     |
+   |     help: consider introducing lifetime `'a` here: `<'a>`
+   |
+   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
+
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/feature-gate-in_band_lifetimes.rs:53:31
+   |
+LL |     fn my_lifetime(&self) -> &'a u8 { self.0 }
+   |                               ^^ undeclared lifetime
+   |
+   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
+help: consider introducing lifetime `'a` here
+   |
+LL | impl<'a> MyTrait<'a> for Y<&'a u8> {
+   |     ++++
+help: consider introducing lifetime `'a` here
+   |
+LL |     fn my_lifetime<'a>(&self) -> &'a u8 { self.0 }
+   |                   ++++
+
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/feature-gate-in_band_lifetimes.rs:55:27
+   |
+LL |     fn any_lifetime() -> &'b u8 { &0 }
+   |                           ^^ undeclared lifetime
+   |
+   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
+   |     ++++
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn any_lifetime<'b>() -> &'b u8 { &0 }
+   |                    ++++
+
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/feature-gate-in_band_lifetimes.rs:57:27
+   |
+LL |     fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
+   |                           ^^ undeclared lifetime
+   |
+   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
+   |     ++++
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
+   |                         ++++
+
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/feature-gate-in_band_lifetimes.rs:57:40
+   |
+LL |     fn borrowed_lifetime(&'b self) -> &'b u8 { &*self.0 }
+   |                                        ^^ undeclared lifetime
+   |
+   = help: if you want to experiment with in-band lifetime bindings, add `#![feature(in_band_lifetimes)]` to the crate attributes
+help: consider introducing lifetime `'b` here
+   |
+LL | impl<'b> MyTrait<'a> for Y<&'a u8> {
+   |     ++++
+help: consider introducing lifetime `'b` here
+   |
+LL |     fn borrowed_lifetime<'b>(&'b self) -> &'b u8 { &*self.0 }
+   |                         ++++
+
 error[E0261]: use of undeclared lifetime name `'b`
   --> $DIR/feature-gate-in_band_lifetimes.rs:43:27
    |
index e0e0acadb3776b0b81fd8fc7683db8e08f403b96..f647380ef9bc4dd7182fb2638ac7ca8ad87abfca 100644 (file)
@@ -38,11 +38,27 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:6
    |
 LL | impl Fn<()> for Foo {
-   |      ^^^^^^ help: use parenthetical notation instead: `Fn() -> ()`
+   |      ^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
+error[E0183]: manual implementations of `Fn` are experimental
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:6
+   |
+LL | impl Fn<()> for Foo {
+   |      ^^^^^^ manual implementations of `Fn` are experimental
+   |
+   = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
+
+error[E0183]: manual implementations of `FnOnce` are experimental
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6
+   |
+LL | impl FnOnce() for Foo1 {
+   |      ^^^^^^^^ manual implementations of `FnOnce` are experimental
+   |
+   = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
+
 error[E0229]: associated type bindings are not allowed here
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:6
    |
@@ -53,49 +69,33 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje
   --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:6
    |
 LL | impl FnMut<()> for Bar {
-   |      ^^^^^^^^^ help: use parenthetical notation instead: `FnMut() -> ()`
-   |
-   = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
-   = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
-
-error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6
-   |
-LL | impl FnOnce<()> for Baz {
-   |      ^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce() -> ()`
+   |      ^^^^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0183]: manual implementations of `Fn` are experimental
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:9:1
-   |
-LL | impl Fn<()> for Foo {
-   | ^^^^^^^^^^^^^^^^^^^ manual implementations of `Fn` are experimental
-   |
-   = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
-
 error[E0183]: manual implementations of `FnMut` are experimental
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:1
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:23:6
    |
 LL | impl FnMut<()> for Bar {
-   | ^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnMut` are experimental
+   |      ^^^^^^^^^ manual implementations of `FnMut` are experimental
    |
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
-error[E0183]: manual implementations of `FnOnce` are experimental
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:16:1
+error[E0658]: the precise format of `Fn`-family traits' type parameters is subject to change
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6
    |
-LL | impl FnOnce() for Foo1 {
-   | ^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
+LL | impl FnOnce<()> for Baz {
+   |      ^^^^^^^^^^
    |
+   = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0183]: manual implementations of `FnOnce` are experimental
-  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:1
+  --> $DIR/feature-gate-unboxed-closures-manual-impls.rs:30:6
    |
 LL | impl FnOnce<()> for Baz {
-   | ^^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
+   |      ^^^^^^^^^^ manual implementations of `FnOnce` are experimental
    |
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
index 8c5f87964561fba6f1e2bff9f1adce139af6d8a6..a763c28de602b65931251f923dad642119057d14 100644 (file)
@@ -11,16 +11,16 @@ error[E0658]: the precise format of `Fn`-family traits' type parameters is subje
   --> $DIR/feature-gate-unboxed-closures.rs:5:6
    |
 LL | impl FnOnce<(u32, u32)> for Test {
-   |      ^^^^^^^^^^^^^^^^^^ help: use parenthetical notation instead: `FnOnce(u32, u32) -> ()`
+   |      ^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #29625 <https://github.com/rust-lang/rust/issues/29625> for more information
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
 error[E0183]: manual implementations of `FnOnce` are experimental
-  --> $DIR/feature-gate-unboxed-closures.rs:5:1
+  --> $DIR/feature-gate-unboxed-closures.rs:5:6
    |
 LL | impl FnOnce<(u32, u32)> for Test {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
+   |      ^^^^^^^^^^^^^^^^^^ manual implementations of `FnOnce` are experimental
    |
    = help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
 
diff --git a/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs
new file mode 100644 (file)
index 0000000..2ac3ca2
--- /dev/null
@@ -0,0 +1,12 @@
+// Regression test for issue #91370.
+
+extern {
+    //~^ `extern` blocks define existing foreign functions
+    fn f() {
+        //~^ incorrect function inside `extern` block
+        //~| cannot have a body
+        impl Copy for u8 {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr
new file mode 100644 (file)
index 0000000..4fb2f8c
--- /dev/null
@@ -0,0 +1,21 @@
+error: incorrect function inside `extern` block
+  --> $DIR/issue-91370-foreign-fn-block-impl.rs:5:8
+   |
+LL |   extern {
+   |   ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body
+LL |
+LL |       fn f() {
+   |  ________^___-
+   | |        |
+   | |        cannot have a body
+LL | |
+LL | |
+LL | |         impl Copy for u8 {}
+LL | |     }
+   | |_____- help: remove the invalid body: `;`
+   |
+   = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
+   = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/generic-associated-types/issue-89352.rs b/src/test/ui/generic-associated-types/issue-89352.rs
new file mode 100644 (file)
index 0000000..d9c656d
--- /dev/null
@@ -0,0 +1,32 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+use std::marker::PhantomData;
+
+pub trait GenAssoc<T> {
+    type Iter<'at>;
+    fn iter(&self) -> Self::Iter<'_>;
+    fn reborrow<'longt: 'shortt, 'shortt>(iter: Self::Iter<'longt>) -> Self::Iter<'shortt>;
+}
+
+pub struct Wrapper<'a, T: 'a, A: GenAssoc<T>> {
+    a: A::Iter<'a>,
+    _p: PhantomData<T>,
+}
+
+impl<'ai, T: 'ai, A: GenAssoc<T>> GenAssoc<T> for Wrapper<'ai, T, A>
+where
+    A::Iter<'ai>: Clone,
+{
+    type Iter<'b> = ();
+    fn iter<'s>(&'s self) -> Self::Iter<'s> {
+        let a = A::reborrow::<'ai, 's>(self.a.clone());
+    }
+
+    fn reborrow<'long: 'short, 'short>(iter: Self::Iter<'long>) -> Self::Iter<'short> {
+        ()
+    }
+}
+
+fn main() {}
index 37b3a6155d5aee89a1cb8854944039e2c4991fad..fcc53b4ede0cb65ceacc59a96c18bcdfdf0214d8 100644 (file)
@@ -189,4 +189,17 @@ trait Trait: 'static {
     fn make_assoc(_: &u32) -> Self::Assoc<'_>;
 }
 
+// We ignore `'static` lifetimes for any lints
+trait StaticReturn<'a> {
+    type Y<'b>;
+    fn foo(&self) -> Self::Y<'static>;
+}
+
+// Same as above, but with extra method that takes GAT - just make sure this works
+trait StaticReturnAndTakes<'a> {
+    type Y<'b>;
+    fn foo(&self) -> Self::Y<'static>;
+    fn bar<'b>(&self, arg: Self::Y<'b>);
+}
+
 fn main() {}
diff --git a/src/test/ui/inference/char-as-str-multi.rs b/src/test/ui/inference/char-as-str-multi.rs
new file mode 100644 (file)
index 0000000..21bbc6f
--- /dev/null
@@ -0,0 +1,6 @@
+// When a MULTI-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
+}
diff --git a/src/test/ui/inference/char-as-str-multi.stderr b/src/test/ui/inference/char-as-str-multi.stderr
new file mode 100644 (file)
index 0000000..c3ba17a
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/char-as-str-multi.rs:5:19
+   |
+LL |     let _: char = "foo";
+   |            ----   ^^^^^ expected `char`, found `&str`
+   |            |
+   |            expected due to this
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/inference/char-as-str-single.fixed b/src/test/ui/inference/char-as-str-single.fixed
new file mode 100644 (file)
index 0000000..e401492
--- /dev/null
@@ -0,0 +1,11 @@
+// When a SINGLE-character string literal is used where a char should be,
+// suggest changing to single quotes.
+
+// Testing both single-byte and multi-byte characters, as we should handle both.
+
+// run-rustfix
+
+fn main() {
+    let _: char = 'a'; //~ ERROR mismatched types
+    let _: char = '人'; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/inference/char-as-str-single.rs b/src/test/ui/inference/char-as-str-single.rs
new file mode 100644 (file)
index 0000000..4f23cea
--- /dev/null
@@ -0,0 +1,11 @@
+// When a SINGLE-character string literal is used where a char should be,
+// suggest changing to single quotes.
+
+// Testing both single-byte and multi-byte characters, as we should handle both.
+
+// run-rustfix
+
+fn main() {
+    let _: char = "a"; //~ ERROR mismatched types
+    let _: char = "人"; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/inference/char-as-str-single.stderr b/src/test/ui/inference/char-as-str-single.stderr
new file mode 100644 (file)
index 0000000..29075c1
--- /dev/null
@@ -0,0 +1,29 @@
+error[E0308]: mismatched types
+  --> $DIR/char-as-str-single.rs:9:19
+   |
+LL |     let _: char = "a";
+   |            ----   ^^^ expected `char`, found `&str`
+   |            |
+   |            expected due to this
+   |
+help: if you meant to write a `char` literal, use single quotes
+   |
+LL |     let _: char = 'a';
+   |                   ~~~
+
+error[E0308]: mismatched types
+  --> $DIR/char-as-str-single.rs:10:19
+   |
+LL |     let _: char = "人";
+   |            ----   ^^^^ expected `char`, found `&str`
+   |            |
+   |            expected due to this
+   |
+help: if you meant to write a `char` literal, use single quotes
+   |
+LL |     let _: char = '人';
+   |                   ~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/inference/infer-arg-test.rs b/src/test/ui/inference/infer-arg-test.rs
deleted file mode 100644 (file)
index 1b67ccd..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#![feature(generic_arg_infer)]
-
-struct All<'a, T, const N: usize> {
-  v: &'a T,
-}
-
-struct BadInfer<_>;
-//~^ ERROR expected identifier
-//~| ERROR parameter `_` is never used
-
-fn all_fn<'a, T, const N: usize>() {}
-
-fn bad_infer_fn<_>() {}
-//~^ ERROR expected identifier
-
-
-fn main() {
-  let a: All<_, _, _>;
-  all_fn();
-  let v: [u8; _];
-  //~^ ERROR in expressions
-  let v: [u8; 10] = [0; _];
-  //~^ ERROR in expressions
-}
diff --git a/src/test/ui/inference/infer-arg-test.stderr b/src/test/ui/inference/infer-arg-test.stderr
deleted file mode 100644 (file)
index 30e171e..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-error: expected identifier, found reserved identifier `_`
-  --> $DIR/infer-arg-test.rs:7:17
-   |
-LL | struct BadInfer<_>;
-   |                 ^ expected identifier, found reserved identifier
-
-error: expected identifier, found reserved identifier `_`
-  --> $DIR/infer-arg-test.rs:13:17
-   |
-LL | fn bad_infer_fn<_>() {}
-   |                 ^ expected identifier, found reserved identifier
-
-error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/infer-arg-test.rs:20:15
-   |
-LL |   let v: [u8; _];
-   |               ^ `_` not allowed here
-
-error: in expressions, `_` can only be used on the left-hand side of an assignment
-  --> $DIR/infer-arg-test.rs:22:25
-   |
-LL |   let v: [u8; 10] = [0; _];
-   |                         ^ `_` not allowed here
-
-error[E0392]: parameter `_` is never used
-  --> $DIR/infer-arg-test.rs:7:17
-   |
-LL | struct BadInfer<_>;
-   |                 ^ unused parameter
-   |
-   = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `_` to be a const parameter, use `const _: usize` instead
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0392`.
diff --git a/src/test/ui/inference/str-as-char.fixed b/src/test/ui/inference/str-as-char.fixed
new file mode 100644 (file)
index 0000000..09f3dec
--- /dev/null
@@ -0,0 +1,8 @@
+// When a char literal is used where a str should be,
+// suggest changing to double quotes.
+
+// run-rustfix
+
+fn main() {
+    let _: &str = "a"; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/inference/str-as-char.rs b/src/test/ui/inference/str-as-char.rs
new file mode 100644 (file)
index 0000000..7092a61
--- /dev/null
@@ -0,0 +1,8 @@
+// When a char literal is used where a str should be,
+// suggest changing to double quotes.
+
+// run-rustfix
+
+fn main() {
+    let _: &str = 'a'; //~ ERROR mismatched types
+}
diff --git a/src/test/ui/inference/str-as-char.stderr b/src/test/ui/inference/str-as-char.stderr
new file mode 100644 (file)
index 0000000..ebbe7c8
--- /dev/null
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/str-as-char.rs:7:19
+   |
+LL |     let _: &str = 'a';
+   |            ----   ^^^ expected `&str`, found `char`
+   |            |
+   |            expected due to this
+   |
+help: if you meant to write a `str` literal, use double quotes
+   |
+LL |     let _: &str = "a";
+   |                   ~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
index 03e4718f5dfef880bba58ea20411f1ee116c14fc..2d29f0592e14bf6d41098f880d3591e37e3bff90 100644 (file)
@@ -2,9 +2,12 @@ error[E0308]: mismatched types
   --> $DIR/infinite-autoderef.rs:20:13
    |
 LL |         x = Box::new(x);
-   |             ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
-   |             |
-   |             cyclic type of infinite size
+   |             ^^^^^^^^^^^ cyclic type of infinite size
+   |
+help: consider unboxing the value
+   |
+LL |         x = *Box::new(x);
+   |             +
 
 error[E0055]: reached the recursion limit while auto-dereferencing `Foo`
   --> $DIR/infinite-autoderef.rs:25:5
index d126e1bf0b5348aace18b668f194ffaa4ae8c957..e065e17c280f9ae5946707807d13dbdd13c51abd 100644 (file)
@@ -12,6 +12,11 @@ error[E0308]: mismatched types
    |
 LL |     let v: Vec(&str) = vec!['1', '2'];
    |                             ^^^ expected `&str`, found `char`
+   |
+help: if you meant to write a `str` literal, use double quotes
+   |
+LL |     let v: Vec(&str) = vec!["1", '2'];
+   |                             ~~~
 
 error: aborting due to 2 previous errors
 
index aa43d06c99b0101d8387d74209455aa89a5e7742..928a65938b7cee539a25b1aa31f9ecc0ab76a7d1 100644 (file)
@@ -5,8 +5,7 @@ struct Foo {
 
     impl<T> Drop for Foo<T> {
         //~^ ERROR this struct takes 0 generic arguments but 1 generic argument
-        //~| ERROR the type parameter `T` is not constrained by the impl trait, self type, or predicates
         fn drop(&mut self) {}
     }
 }
-fn main() { }
+fn main() {}
index 094da64d76d4d252df3da36b9555b843c275012e..4d8eb6360e640f4e0c77e599d720c7194024c067 100644 (file)
@@ -23,13 +23,7 @@ note: struct defined here, with 0 generic parameters
 LL |     struct Foo {
    |            ^^^
 
-error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
-  --> $DIR/issue-3214.rs:6:10
-   |
-LL |     impl<T> Drop for Foo<T> {
-   |          ^ unconstrained type parameter
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0107, E0207, E0401.
+Some errors have detailed explanations: E0107, E0401.
 For more information about an error, try `rustc --explain E0107`.
index e4e9705b07db5e59cf61369e83427b85590f279c..52ee1db5b157113d3a3a1ea2c83582d3ad80b3e8 100644 (file)
@@ -5,7 +5,6 @@ LL |     let _result = &mut Some(42).as_deref_mut();
    |                                 ^^^^^^^^^^^^ method cannot be called on `Option<{integer}>` due to unsatisfied trait bounds
    |
    = note: the following trait bounds were not satisfied:
-           `{integer}: DerefMut`
            `{integer}: Deref`
 
 error: aborting due to previous error
index 98a7091dd0583c8a0f27efae8e7ecac5483e59e8..018557881ef77edb45ee41dce7eba85273a2c6aa 100644 (file)
@@ -5,7 +5,6 @@ LL |     let _result = &mut Ok(42).as_deref_mut();
    |                               ^^^^^^^^^^^^ method cannot be called on `Result<{integer}, _>` due to unsatisfied trait bounds
    |
    = note: the following trait bounds were not satisfied:
-           `{integer}: DerefMut`
            `{integer}: Deref`
 
 error: aborting due to previous error
index df8368da0a09a0a1fcab45e6ffce638f487492cf..b315ef05190719647ef94a7014e147bbb4366391 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-// compile-flags: -Zsymbol-mangling-version=v0
+// compile-flags: -Csymbol-mangling-version=v0
 
 pub fn f<T: ?Sized>() {}
 pub trait Frob<T: ?Sized> {}
diff --git a/src/test/ui/lint/lint-pub-unreachable-for-nested-glob.rs b/src/test/ui/lint/lint-pub-unreachable-for-nested-glob.rs
new file mode 100644 (file)
index 0000000..2df6d08
--- /dev/null
@@ -0,0 +1,28 @@
+// check-pass
+
+#![deny(unreachable_pub)]
+
+pub use self::m1::*;
+
+mod m1 {
+    pub use self::m2::*;
+
+    mod m2 {
+        pub struct Item1;
+        pub struct Item2;
+    }
+}
+
+
+pub use self::o1::{ Item42, Item24 };
+
+mod o1 {
+    pub use self::o2::{ Item42, Item24 };
+
+    mod o2 {
+        pub struct Item42;
+        pub struct Item24;
+    }
+}
+
+fn main() {}
index 9b4a9c2cf811d5393423b65a3e4e20514647ef3e..db5d3cab0bd8a905ccba171a66b61d44e71654c4 100644 (file)
@@ -39,4 +39,12 @@ fn main() {
     ]);
     concat_bytes!(5u16); //~ ERROR cannot concatenate numeric literals
     concat_bytes!([5u16]); //~ ERROR numeric literal is not a `u8`
+    concat_bytes!([3; ()]); //~ ERROR repeat count is not a positive number
+    concat_bytes!([3; -2]); //~ ERROR repeat count is not a positive number
+    concat_bytes!([pie; -2]); //~ ERROR repeat count is not a positive number
+    concat_bytes!([pie; 2]); //~ ERROR expected a byte literal
+    concat_bytes!([2.2; 0]); //~ ERROR cannot concatenate float literals
+    concat_bytes!([5.5; ()]); //~ ERROR repeat count is not a positive number
+    concat_bytes!([[1, 2, 3]; 3]); //~ ERROR cannot concatenate doubly nested array
+    concat_bytes!([[42; 2]; 3]); //~ ERROR cannot concatenate doubly nested array
 }
index 1fc2d5c4843a027f53b4543be64a40c66261c8b3..d6cd1a3d178b0b4312b5a992ccc17227ad39fc03 100644 (file)
@@ -127,5 +127,55 @@ error: numeric literal is not a `u8`
 LL |     concat_bytes!([5u16]);
    |                    ^^^^
 
-error: aborting due to 20 previous errors
+error: repeat count is not a positive number
+  --> $DIR/concat-bytes-error.rs:42:23
+   |
+LL |     concat_bytes!([3; ()]);
+   |                       ^^
+
+error: repeat count is not a positive number
+  --> $DIR/concat-bytes-error.rs:43:23
+   |
+LL |     concat_bytes!([3; -2]);
+   |                       ^^
+
+error: repeat count is not a positive number
+  --> $DIR/concat-bytes-error.rs:44:25
+   |
+LL |     concat_bytes!([pie; -2]);
+   |                         ^^
+
+error: expected a byte literal
+  --> $DIR/concat-bytes-error.rs:45:20
+   |
+LL |     concat_bytes!([pie; 2]);
+   |                    ^^^
+   |
+   = note: only byte literals (like `b"foo"`, `b's'`, and `[3, 4, 5]`) can be passed to `concat_bytes!()`
+
+error: cannot concatenate float literals
+  --> $DIR/concat-bytes-error.rs:46:20
+   |
+LL |     concat_bytes!([2.2; 0]);
+   |                    ^^^
+
+error: repeat count is not a positive number
+  --> $DIR/concat-bytes-error.rs:47:25
+   |
+LL |     concat_bytes!([5.5; ()]);
+   |                         ^^
+
+error: cannot concatenate doubly nested array
+  --> $DIR/concat-bytes-error.rs:48:20
+   |
+LL |     concat_bytes!([[1, 2, 3]; 3]);
+   |                    ^^^^^^^^^
+
+error: cannot concatenate doubly nested array
+  --> $DIR/concat-bytes-error.rs:49:20
+   |
+LL |     concat_bytes!([[42; 2]; 3]);
+   |                    ^^^^^^^
+
+error: aborting due to 28 previous errors
 
index 5415cf3fe2235b260012a377725596898bf09b77..fd8f99417ec985d548e2e02c094e1e1b447cbfde 100644 (file)
@@ -3,5 +3,15 @@
 
 fn main() {
     assert_eq!(concat_bytes!(), &[]);
-    assert_eq!(concat_bytes!(b'A', b"BC", [68, b'E', 70]), b"ABCDEF");
+    assert_eq!(
+        concat_bytes!(b'A', b"BC", [68, b'E', 70], [b'G'; 1], [72; 2], [73u8; 3], [65; 0]),
+        b"ABCDEFGHHIII",
+    );
+    assert_eq!(
+        concat_bytes!(
+            concat_bytes!(b"AB", b"CD"),
+            concat_bytes!(b"EF", b"GH"),
+        ),
+        b"ABCDEFGH",
+    );
 }
index 36e01a7508f3408926fae60cd88713a9667ba2e1..004ab386b3ff071d6a10b72f2c0337d023eee37d 100644 (file)
@@ -603,7 +603,7 @@ pub impl Struct {}
         stringify_item!(
             impl<T> Struct<T> {}
         ),
-        "impl <T> Struct<T> {}", // FIXME
+        "impl<T> Struct<T> {}",
     );
     assert_eq!(
         stringify_item!(
@@ -611,6 +611,12 @@ pub impl Trait for Struct {}
         ),
         "pub impl Trait for Struct {}",
     );
+    assert_eq!(
+        stringify_item!(
+            impl<T> const Trait for T {}
+        ),
+        "impl<T> const Trait for T {}",
+    );
     assert_eq!(
         stringify_item!(
             impl ~const Struct {}
@@ -661,9 +667,9 @@ fn test_pat() {
     assert_eq!(stringify_pat!(ref mut _x @ _), "ref mut _x @ _");
 
     // PatKind::Struct
-    assert_eq!(stringify_pat!(Struct {}), "Struct {  }"); // FIXME
-    assert_eq!(stringify_pat!(Struct::<u8> {}), "Struct::<u8> {  }");
-    assert_eq!(stringify_pat!(Struct::<'static> {}), "Struct::<'static> {  }");
+    assert_eq!(stringify_pat!(Struct {}), "Struct {}");
+    assert_eq!(stringify_pat!(Struct::<u8> {}), "Struct::<u8> {}");
+    assert_eq!(stringify_pat!(Struct::<'static> {}), "Struct::<'static> {}");
     assert_eq!(stringify_pat!(Struct { x }), "Struct { x }");
     assert_eq!(stringify_pat!(Struct { x: _x }), "Struct { x: _x }");
     assert_eq!(stringify_pat!(Struct { .. }), "Struct { .. }");
@@ -672,7 +678,7 @@ fn test_pat() {
     #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/5151
     assert_eq!(
         stringify_pat!(<Struct as Trait>::Type {}),
-        "<Struct as Trait>::Type {  }",
+        "<Struct as Trait>::Type {}",
     );
 
     // PatKind::TupleStruct
index 1ac8274ffd5dbc41de7af64561cdb609ea799696..2bd1b3b9454a6606f98da129e2c876fda550bc29 100644 (file)
@@ -1,14 +1,14 @@
-error: arbitrary expressions aren't allowed in patterns
+error[E0425]: cannot find value `a` in this scope
   --> $DIR/expr_before_ident_pat.rs:12:12
    |
 LL |     funny!(a, a);
-   |            ^
+   |            ^ not found in this scope
 
-error[E0425]: cannot find value `a` in this scope
+error: arbitrary expressions aren't allowed in patterns
   --> $DIR/expr_before_ident_pat.rs:12:12
    |
 LL |     funny!(a, a);
-   |            ^ not found in this scope
+   |            ^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs b/src/test/ui/mir/drop-elaboration-after-borrowck-error.rs
new file mode 100644 (file)
index 0000000..c44dd51
--- /dev/null
@@ -0,0 +1,25 @@
+// Regression test for issue 81708 and issue 91816 where running a drop
+// elaboration on a MIR which failed borrowck lead to an ICE.
+
+static A: () = {
+    let a: [String; 1];
+    //~^ ERROR destructors cannot be evaluated at compile-time
+    a[0] = String::new();
+    //~^ ERROR destructors cannot be evaluated at compile-time
+    //~| ERROR use of possibly-uninitialized variable
+};
+
+struct B<T>([T; 1]);
+
+impl<T> B<T> {
+    pub const fn f(mut self, other: T) -> Self {
+        let _this = self;
+        //~^ ERROR destructors cannot be evaluated at compile-time
+        self.0[0] = other;
+        //~^ ERROR destructors cannot be evaluated at compile-time
+        //~| ERROR use of moved value
+        self
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr b/src/test/ui/mir/drop-elaboration-after-borrowck-error.stderr
new file mode 100644 (file)
index 0000000..80d5fc7
--- /dev/null
@@ -0,0 +1,57 @@
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:7:5
+   |
+LL |     a[0] = String::new();
+   |     ^^^^
+   |     |
+   |     statics cannot evaluate destructors
+   |     value is dropped here
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:5:9
+   |
+LL |     let a: [String; 1];
+   |         ^ statics cannot evaluate destructors
+...
+LL | };
+   | - value is dropped here
+
+error[E0381]: use of possibly-uninitialized variable: `a`
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:7:5
+   |
+LL |     a[0] = String::new();
+   |     ^^^^ use of possibly-uninitialized `a`
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:18:9
+   |
+LL |         self.0[0] = other;
+   |         ^^^^^^^^^
+   |         |
+   |         constant functions cannot evaluate destructors
+   |         value is dropped here
+
+error[E0493]: destructors cannot be evaluated at compile-time
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:16:13
+   |
+LL |         let _this = self;
+   |             ^^^^^ constant functions cannot evaluate destructors
+...
+LL |     }
+   |     - value is dropped here
+
+error[E0382]: use of moved value: `self.0`
+  --> $DIR/drop-elaboration-after-borrowck-error.rs:18:9
+   |
+LL |     pub const fn f(mut self, other: T) -> Self {
+   |                    -------- move occurs because `self` has type `B<T>`, which does not implement the `Copy` trait
+LL |         let _this = self;
+   |                     ---- value moved here
+LL |
+LL |         self.0[0] = other;
+   |         ^^^^^^^^^ value used here after move
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0381, E0382, E0493.
+For more information about an error, try `rustc --explain E0381`.
index f85c10d78c54dda7cc7152a56e332f3ae7f53cb0..6303c6e6a5db11404e1850fbf09dc214c61cfcc4 100644 (file)
@@ -3,5 +3,5 @@
 fn main() {
     let a: Result<(), Foo> = Ok(());
     a.unwrap();
-    //~^ ERROR the method
+    //~^ ERROR `Foo` doesn't implement `Debug`
 }
index 596b7bfe79c5c56ed7d60abd088da1ad98d344e9..dc73bcd6e4d050aa27835b524445d3bdbd85e3dd 100644 (file)
@@ -1,19 +1,17 @@
-error[E0599]: the method `unwrap` exists for enum `Result<(), Foo>`, but its trait bounds were not satisfied
+error[E0277]: `Foo` doesn't implement `Debug`
   --> $DIR/method-help-unsatisfied-bound.rs:5:7
    |
-LL | struct Foo;
-   | ----------- doesn't satisfy `Foo: Debug`
-...
 LL |     a.unwrap();
-   |       ^^^^^^ method cannot be called on `Result<(), Foo>` due to unsatisfied trait bounds
+   |       ^^^^^^ `Foo` cannot be formatted using `{:?}`
    |
-   = note: the following trait bounds were not satisfied:
-           `Foo: Debug`
-help: consider annotating `Foo` with `#[derive(Debug)]`
-   |
-LL | #[derive(Debug)]
+   = help: the trait `Debug` is not implemented for `Foo`
+   = note: add `#[derive(Debug)]` to `Foo` or manually `impl Debug for Foo`
+note: required by a bound in `Result::<T, E>::unwrap`
+  --> $SRC_DIR/core/src/result.rs:LL:COL
    |
+LL |         E: fmt::Debug,
+   |            ^^^^^^^^^^ required by this bound in `Result::<T, E>::unwrap`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0599`.
+For more information about this error, try `rustc --explain E0277`.
index 983d6a06afada75c7edffd8500d13cacbf15bc7b..459198eec5a8e50c55919233daf59655e84e721f 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::boxed::Box<(dyn Anything + '_#2r)>,
+               extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#2r), std::alloc::Global>,
                (),
            ]
    = 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::boxed::Box<(dyn Anything + '_#2r)>,
+               extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#2r), std::alloc::Global>,
                (),
            ]
    = 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::boxed::Box<(dyn Anything + '_#3r)>,
+               extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#3r), std::alloc::Global>,
                (),
            ]
    = 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::boxed::Box<(dyn Anything + '_#3r)>,
+               extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn Anything + '_#3r), std::alloc::Global>,
                (),
            ]
    = note: number of external vids: 4
index 88d73e7a729a92f5826d545af0bcf947c986f650..6e8b3021d330c9139fb1a6519c28558b3441ba89 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::boxed::Box<(dyn std::fmt::Debug + '_#2r)>,
+               extern "rust-call" fn((std::boxed::Box<T, std::alloc::Global>,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r), std::alloc::Global>,
                (),
            ]
    = note: number of external vids: 3
index 939271832e3df82409f06542f61524184324117a..c80e61b451116b7e45cd140bb377aec86fc9470e 100644 (file)
@@ -1,8 +1,9 @@
+// check-pass
 // aux-build:empty-struct.rs
 
 #[no_link]
 extern crate empty_struct;
 
 fn main() {
-    empty_struct::XEmpty1; //~ ERROR cannot find value `XEmpty1` in crate `empty_struct`
+    empty_struct::XEmpty1 {};
 }
diff --git a/src/test/ui/no-link.stderr b/src/test/ui/no-link.stderr
deleted file mode 100644 (file)
index 66a74ff..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0425]: cannot find value `XEmpty1` in crate `empty_struct`
-  --> $DIR/no-link.rs:7:19
-   |
-LL |     empty_struct::XEmpty1;
-   |                   ^^^^^^^ not found in `empty_struct`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0425`.
index dcbfc81b4d51928f25c43cf3f06c4dd1434002fc..b68c3fa5bcc9c478240e2e8af4260a3867765f4e 100644 (file)
@@ -2,9 +2,12 @@ error[E0308]: mismatched types
   --> $DIR/occurs-check-2.rs:7:9
    |
 LL |     f = Box::new(g);
-   |         ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
-   |         |
-   |         cyclic type of infinite size
+   |         ^^^^^^^^^^^ cyclic type of infinite size
+   |
+help: consider unboxing the value
+   |
+LL |     f = *Box::new(g);
+   |         +
 
 error: aborting due to previous error
 
index 3e1ef2e719ad570a6d2f497a8293873cbc7f050a..fdbbdc3abb377b68ffc65520a8a6324dc6d9a8cb 100644 (file)
@@ -2,9 +2,12 @@ error[E0308]: mismatched types
   --> $DIR/occurs-check.rs:5:9
    |
 LL |     f = Box::new(f);
-   |         ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
-   |         |
-   |         cyclic type of infinite size
+   |         ^^^^^^^^^^^ cyclic type of infinite size
+   |
+help: consider unboxing the value
+   |
+LL |     f = *Box::new(f);
+   |         +
 
 error: aborting due to previous error
 
index 35ecfc0b27158720d8e493fcb31efd2ef1c62724..c34e00bab7cdd8ec23bf823e16d416822a0a16a5 100644 (file)
@@ -14,8 +14,8 @@
 
 // NOTE(eddyb) output differs between symbol mangling schemes
 // revisions: legacy v0
-// [legacy] compile-flags: -Zsymbol-mangling-version=legacy
-//     [v0] compile-flags: -Zsymbol-mangling-version=v0
+// [legacy] compile-flags: -Zunstable-options -Csymbol-mangling-version=legacy
+//     [v0] compile-flags: -Csymbol-mangling-version=v0
 
 fn main() {
     panic!()
diff --git a/src/test/ui/panics/panic-handler-chain-update-hook.rs b/src/test/ui/panics/panic-handler-chain-update-hook.rs
new file mode 100644 (file)
index 0000000..4dd08ba
--- /dev/null
@@ -0,0 +1,36 @@
+// run-pass
+// needs-unwind
+#![allow(stable_features)]
+
+// ignore-emscripten no threads support
+
+#![feature(std_panic)]
+#![feature(panic_update_hook)]
+
+use std::sync::atomic::{AtomicUsize, Ordering};
+use std::panic;
+use std::thread;
+
+static A: AtomicUsize = AtomicUsize::new(0);
+static B: AtomicUsize = AtomicUsize::new(0);
+static C: AtomicUsize = AtomicUsize::new(0);
+
+fn main() {
+    panic::set_hook(Box::new(|_| { A.fetch_add(1, Ordering::SeqCst); }));
+    panic::update_hook(|prev, info| {
+        B.fetch_add(1, Ordering::SeqCst);
+        prev(info);
+    });
+    panic::update_hook(|prev, info| {
+        C.fetch_add(1, Ordering::SeqCst);
+        prev(info);
+    });
+
+    let _ = thread::spawn(|| {
+        panic!();
+    }).join();
+
+    assert_eq!(1, A.load(Ordering::SeqCst));
+    assert_eq!(1, B.load(Ordering::SeqCst));
+    assert_eq!(1, C.load(Ordering::SeqCst));
+}
index fd01337296fb73aad9c357c641b5b72f8d1fe23d..39ffe86dd496b97482f9bc5ef706fed1fb8032f5 100644 (file)
@@ -1,3 +1,7 @@
+// This test has been spuriously failing a lot recently (#92000).
+// Ignore it until the underlying issue is fixed.
+// ignore-test
+
 // Regression test for #87481: short backtrace formatting cut off the entire stack trace.
 
 // Codegen-units is specified here so that we can replicate a typical rustc invocation which
diff --git a/src/test/ui/pattern/issue-92074-macro-ice.rs b/src/test/ui/pattern/issue-92074-macro-ice.rs
new file mode 100644 (file)
index 0000000..039d3b3
--- /dev/null
@@ -0,0 +1,36 @@
+pub enum En {
+    A(Vec<u8>)
+}
+
+fn get_usize() -> usize {
+    0
+}
+
+macro_rules! force_expr {
+    ($e:expr) => { $e }
+}
+
+macro_rules! force_pat {
+    ($a:expr, $b:expr) => { $a..=$b }
+}
+
+macro_rules! make_vec {
+    () => { force_expr!(Vec::new()) } //~ ERROR arbitrary expressions aren't allowed
+}
+
+macro_rules! make_pat {
+    () => { force_pat!(get_usize(), get_usize()) }
+    //~^ ERROR arbitrary expressions aren't allowed
+    //~| ERROR arbitrary expressions aren't allowed
+}
+
+#[allow(unreachable_code)]
+fn f() -> Result<(), impl core::fmt::Debug> {
+    let x: En = loop {};
+
+    assert!(matches!(x, En::A(make_vec!())));
+    assert!(matches!(5, make_pat!()));
+    Ok::<(), &'static str>(())
+}
+
+fn main() {}
diff --git a/src/test/ui/pattern/issue-92074-macro-ice.stderr b/src/test/ui/pattern/issue-92074-macro-ice.stderr
new file mode 100644 (file)
index 0000000..b340aff
--- /dev/null
@@ -0,0 +1,35 @@
+error: arbitrary expressions aren't allowed in patterns
+  --> $DIR/issue-92074-macro-ice.rs:18:25
+   |
+LL |     () => { force_expr!(Vec::new()) }
+   |                         ^^^^^^^^^^
+...
+LL |     assert!(matches!(x, En::A(make_vec!())));
+   |                               ----------- in this macro invocation
+   |
+   = note: this error originates in the macro `make_vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: arbitrary expressions aren't allowed in patterns
+  --> $DIR/issue-92074-macro-ice.rs:22:24
+   |
+LL |     () => { force_pat!(get_usize(), get_usize()) }
+   |                        ^^^^^^^^^^^
+...
+LL |     assert!(matches!(5, make_pat!()));
+   |                         ----------- in this macro invocation
+   |
+   = note: this error originates in the macro `make_pat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: arbitrary expressions aren't allowed in patterns
+  --> $DIR/issue-92074-macro-ice.rs:22:37
+   |
+LL |     () => { force_pat!(get_usize(), get_usize()) }
+   |                                     ^^^^^^^^^^^
+...
+LL |     assert!(matches!(5, make_pat!()));
+   |                         ----------- in this macro invocation
+   |
+   = note: this error originates in the macro `make_pat` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
index b0b39dbd3df61c630e009bd35c93c4ba435a8cb2..e1030858814e0978786c1c3329d17e1c3d4601f5 100644 (file)
@@ -1,5 +1,5 @@
 // build-pass
-// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
 
 fn foo(f: impl Fn()) {
     let x = |_: ()| ();
index ba75f6c5a1099dc7530965e56ea94e28b9357d30..62164ff94850814edb44e2dab8de115fae01142e 100644 (file)
@@ -1,5 +1,5 @@
 // build-pass
-// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
 
 fn foo(f: impl Fn()) {
     // Mutate an upvar from `x` so that it implements `FnMut`.
index e9761ad0bcb20653d44bf470cde48ceb7258054e..7a364882fb8fd5d56afddb878037679624199703 100644 (file)
@@ -1,5 +1,5 @@
 // build-pass
-// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
 
 fn foo(f: impl Fn()) {
     // Move a non-copy type into `x` so that it implements `FnOnce`.
index 7614aa83fcd1541fecd0734b45719e383bb6b6e1..27d59ec8899800cf9c3861eb734cfd2fed847f27 100644 (file)
@@ -1,5 +1,5 @@
 // build-pass
-// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+// compile-flags:-Zpolymorphize=on -Csymbol-mangling-version=v0
 
 fn y_uses_f(f: impl Fn()) {
     let x = |_: ()| ();
index d97bae183d9c21712d1be11eef2fba9285a62e52..6277a902fa213c9d2fe10567a4d279f32bd1d6af 100644 (file)
@@ -1,5 +1,5 @@
 // build-pass
-// compile-flags: -Zpolymorphize=on -Zsymbol-mangling-version=v0
+// compile-flags: -Zpolymorphize=on -Csymbol-mangling-version=v0
 
 pub(crate) struct Foo<'a, I, E>(I, &'a E);
 
diff --git a/src/test/ui/privacy/auxiliary/issue-92755.rs b/src/test/ui/privacy/auxiliary/issue-92755.rs
new file mode 100644 (file)
index 0000000..6f85273
--- /dev/null
@@ -0,0 +1,17 @@
+mod machine {
+    pub struct A {
+        pub b: B,
+    }
+    pub struct B {}
+    impl B {
+        pub fn f(&self) {}
+    }
+}
+
+pub struct Context {
+    pub a: machine::A,
+}
+
+pub fn ctx() -> Context {
+    todo!();
+}
diff --git a/src/test/ui/privacy/issue-92755.rs b/src/test/ui/privacy/issue-92755.rs
new file mode 100644 (file)
index 0000000..4955915
--- /dev/null
@@ -0,0 +1,10 @@
+// aux-build:issue-92755.rs
+// build-pass
+
+// Thank you @tmiasko for providing the content of this test!
+
+extern crate issue_92755;
+
+fn main() {
+    issue_92755::ctx().a.b.f();
+}
index 83266abfa06e67dd7ea6a028f78779a05e4a1bf5..2c3610fb24d4e952e72299ca597ea1e8b6760b4d 100644 (file)
@@ -1,3 +1,16 @@
+// > Suggest `return`ing tail expressions that match return type
+// >
+// > Some newcomers are confused by the behavior of tail expressions,
+// > interpreting that "leaving out the `;` makes it the return value".
+// > To help them go in the right direction, suggest using `return` instead
+// > when applicable.
+// (original commit description for this test)
+//
+// This test was amended to also serve as a regression test for #92308, where
+// this suggestion would not trigger with async functions.
+//
+// edition:2018
+
 fn main() {
     let _ = foo(true);
 }
@@ -5,6 +18,15 @@ fn main() {
 fn foo(x: bool) -> Result<f64, i32> {
     if x {
         Err(42) //~ ERROR mismatched types
+                //| HELP you might have meant to return this value
+    }
+    Ok(42.0)
+}
+
+async fn bar(x: bool) -> Result<f64, i32> {
+    if x {
+        Err(42) //~ ERROR mismatched types
+                //| HELP you might have meant to return this value
     }
     Ok(42.0)
 }
index 87ef18878d6f195fe664b7364eb8cc411dc5ad0b..dec1cbc4624ef5bece1d9262d612b21663ccb1e7 100644 (file)
@@ -1,9 +1,10 @@
 error[E0308]: mismatched types
-  --> $DIR/tail-expr-as-potential-return.rs:7:9
+  --> $DIR/tail-expr-as-potential-return.rs:28:9
    |
 LL | /     if x {
 LL | |         Err(42)
    | |         ^^^^^^^ expected `()`, found enum `Result`
+LL | |                 //| HELP you might have meant to return this value
 LL | |     }
    | |_____- expected this to be `()`
    |
@@ -14,6 +15,23 @@ help: you might have meant to return this value
 LL |         return Err(42);
    |         ++++++        +
 
-error: aborting due to previous error
+error[E0308]: mismatched types
+  --> $DIR/tail-expr-as-potential-return.rs:20:9
+   |
+LL | /     if x {
+LL | |         Err(42)
+   | |         ^^^^^^^ expected `()`, found enum `Result`
+LL | |                 //| HELP you might have meant to return this value
+LL | |     }
+   | |_____- expected this to be `()`
+   |
+   = note: expected unit type `()`
+                   found enum `Result<_, {integer}>`
+help: you might have meant to return this value
+   |
+LL |         return Err(42);
+   |         ++++++        +
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.rs
new file mode 100644 (file)
index 0000000..cccb856
--- /dev/null
@@ -0,0 +1,17 @@
+#![feature(const_fn_trait_bound)]
+#![feature(const_trait_impl)]
+
+pub trait Tr {
+    #[default_method_body_is_const]
+    fn a(&self) {}
+
+    #[default_method_body_is_const]
+    fn b(&self) {
+        ().a()
+        //~^ ERROR calls in constant functions are limited
+    }
+}
+
+impl Tr for () {}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-same-trait-ck.stderr
new file mode 100644 (file)
index 0000000..91f4d2f
--- /dev/null
@@ -0,0 +1,9 @@
+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
+   |
+LL |         ().a()
+   |         ^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0015`.
index 74caae8645c1d01e70d24307132e147ed9d459a9..5a964c5d5cc6693e1667e60a7e1f647b42da75be 100644 (file)
@@ -38,9 +38,12 @@ error[E0308]: mismatched types
   --> $DIR/coerce-suggestions.rs:17:9
    |
 LL |     f = Box::new(f);
-   |         ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
-   |         |
-   |         cyclic type of infinite size
+   |         ^^^^^^^^^^^ cyclic type of infinite size
+   |
+help: consider unboxing the value
+   |
+LL |     f = *Box::new(f);
+   |         +
 
 error[E0308]: mismatched types
   --> $DIR/coerce-suggestions.rs:21:9
index 672fe8dccf773ee44af63e0d7f0ce633a5a6bfec..bf335868643ca25b03b5862f43689eaf1d74c4d1 100644 (file)
@@ -29,12 +29,10 @@ impl Foo for FooTypeForMethod {
     //~^ ERROR E0046
     type bar = u64;
     //~^ ERROR E0325
-    //~| ERROR E0437
     const MY_CONST: u32 = 1;
 }
 
-impl Debug for FooTypeForMethod {
-}
-//~^^ ERROR E0046
+impl Debug for FooTypeForMethod {}
+//~^ ERROR E0046
 
-fn main () {}
+fn main() {}
index de200ca0721cad5e00d91f103ae950dc9f7ba4e3..82ef13f3362d461a9eeee3f3c542059a2e9f4921 100644 (file)
@@ -1,9 +1,3 @@
-error[E0437]: type `bar` is not a member of trait `Foo`
-  --> $DIR/impl-wrong-item-for-trait.rs:30:5
-   |
-LL |     type bar = u64;
-   |     ^^^^^^^^^^^^^^^ not a member of trait `Foo`
-
 error[E0323]: item `bar` is an associated const, which doesn't match its trait `Foo`
   --> $DIR/impl-wrong-item-for-trait.rs:12:5
    |
@@ -13,15 +7,6 @@ LL |     fn bar(&self);
 LL |     const bar: u64 = 1;
    |     ^^^^^^^^^^^^^^^^^^^ does not match trait
 
-error[E0046]: not all trait items implemented, missing: `bar`
-  --> $DIR/impl-wrong-item-for-trait.rs:10:1
-   |
-LL |     fn bar(&self);
-   |     -------------- `bar` from trait
-...
-LL | impl Foo for FooConstForMethod {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation
-
 error[E0324]: item `MY_CONST` is an associated method, which doesn't match its trait `Foo`
   --> $DIR/impl-wrong-item-for-trait.rs:22:5
    |
@@ -31,15 +16,6 @@ LL |     const MY_CONST: u32;
 LL |     fn MY_CONST() {}
    |     ^^^^^^^^^^^^^^^^ does not match trait
 
-error[E0046]: not all trait items implemented, missing: `MY_CONST`
-  --> $DIR/impl-wrong-item-for-trait.rs:19:1
-   |
-LL |     const MY_CONST: u32;
-   |     -------------------- `MY_CONST` from trait
-...
-LL | impl Foo for FooMethodForConst {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `MY_CONST` in implementation
-
 error[E0325]: item `bar` is an associated type, which doesn't match its trait `Foo`
   --> $DIR/impl-wrong-item-for-trait.rs:30:5
    |
@@ -49,6 +25,24 @@ LL |     fn bar(&self);
 LL |     type bar = u64;
    |     ^^^^^^^^^^^^^^^ does not match trait
 
+error[E0046]: not all trait items implemented, missing: `bar`
+  --> $DIR/impl-wrong-item-for-trait.rs:10:1
+   |
+LL |     fn bar(&self);
+   |     -------------- `bar` from trait
+...
+LL | impl Foo for FooConstForMethod {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation
+
+error[E0046]: not all trait items implemented, missing: `MY_CONST`
+  --> $DIR/impl-wrong-item-for-trait.rs:19:1
+   |
+LL |     const MY_CONST: u32;
+   |     -------------------- `MY_CONST` from trait
+...
+LL | impl Foo for FooMethodForConst {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `MY_CONST` in implementation
+
 error[E0046]: not all trait items implemented, missing: `bar`
   --> $DIR/impl-wrong-item-for-trait.rs:28:1
    |
@@ -59,14 +53,14 @@ LL | impl Foo for FooTypeForMethod {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `bar` in implementation
 
 error[E0046]: not all trait items implemented, missing: `fmt`
-  --> $DIR/impl-wrong-item-for-trait.rs:36:1
+  --> $DIR/impl-wrong-item-for-trait.rs:35:1
    |
-LL | impl Debug for FooTypeForMethod {
+LL | impl Debug for FooTypeForMethod {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation
    |
    = help: implement the missing item: `fn fmt(&self, _: &mut Formatter<'_>) -> Result<(), std::fmt::Error> { todo!() }`
 
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0046, E0323, E0324, E0325, E0437.
+Some errors have detailed explanations: E0046, E0323, E0324, E0325.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/src/test/ui/stability-attribute/generics-default-stability-trait.rs b/src/test/ui/stability-attribute/generics-default-stability-trait.rs
new file mode 100644 (file)
index 0000000..d436088
--- /dev/null
@@ -0,0 +1,33 @@
+// aux-build:unstable_generic_param.rs
+#![feature(unstable_default6)]
+
+extern crate unstable_generic_param;
+
+use unstable_generic_param::*;
+
+struct R;
+
+impl Trait1 for S {
+    fn foo() -> () { () } // ok
+}
+
+struct S;
+
+impl Trait1<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
+    fn foo() -> usize { 0 }
+}
+
+impl Trait1<isize> for S { //~ ERROR use of unstable library feature 'unstable_default'
+    fn foo() -> isize { 0 }
+}
+
+impl Trait2<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
+    fn foo() -> usize { 0 }
+}
+
+impl Trait3<usize> for S {
+    fn foo() -> usize { 0 } // ok
+}
+
+fn main() {
+}
diff --git a/src/test/ui/stability-attribute/generics-default-stability-trait.stderr b/src/test/ui/stability-attribute/generics-default-stability-trait.stderr
new file mode 100644 (file)
index 0000000..03e61b7
--- /dev/null
@@ -0,0 +1,27 @@
+error[E0658]: use of unstable library feature 'unstable_default'
+  --> $DIR/generics-default-stability-trait.rs:16:13
+   |
+LL | impl Trait1<usize> for S {
+   |             ^^^^^
+   |
+   = help: add `#![feature(unstable_default)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'unstable_default'
+  --> $DIR/generics-default-stability-trait.rs:20:13
+   |
+LL | impl Trait1<isize> for S {
+   |             ^^^^^
+   |
+   = help: add `#![feature(unstable_default)]` to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'unstable_default'
+  --> $DIR/generics-default-stability-trait.rs:24:13
+   |
+LL | impl Trait2<usize> for S {
+   |             ^^^^^
+   |
+   = help: add `#![feature(unstable_default)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
index 67f2334efc88e53ca5a46cdfdde177030159b072..c5132861f855c07463965259b8e8eb7739cd9acd 100644 (file)
@@ -13,18 +13,6 @@ fn foo() -> () { () } // ok
 
 struct S;
 
-impl Trait1<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
-    fn foo() -> usize { 0 }
-}
-
-impl Trait1<isize> for S { //~ ERROR use of unstable library feature 'unstable_default'
-    fn foo() -> isize { 0 }
-}
-
-impl Trait2<usize> for S { //~ ERROR use of unstable library feature 'unstable_default'
-    fn foo() -> usize { 0 }
-}
-
 impl Trait3<usize> for S {
     fn foo() -> usize { 0 } // ok
 }
index bc59844f77c8b80fee37bd70e692cdab785d7295..2a9d34a15c4924cba69ddc9c8e616f69d06721eb 100644 (file)
@@ -1,29 +1,5 @@
-error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:16:13
-   |
-LL | impl Trait1<usize> for S {
-   |             ^^^^^
-   |
-   = help: add `#![feature(unstable_default)]` to the crate attributes to enable
-
-error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:20:13
-   |
-LL | impl Trait1<isize> for S {
-   |             ^^^^^
-   |
-   = help: add `#![feature(unstable_default)]` to the crate attributes to enable
-
-error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:24:13
-   |
-LL | impl Trait2<usize> for S {
-   |             ^^^^^
-   |
-   = help: add `#![feature(unstable_default)]` to the crate attributes to enable
-
 warning: use of deprecated struct `unstable_generic_param::Struct4`: test
-  --> $DIR/generics-default-stability.rs:83:29
+  --> $DIR/generics-default-stability.rs:71:29
    |
 LL |     let _: Struct4<isize> = Struct4 { field: 1 };
    |                             ^^^^^^^
@@ -31,217 +7,217 @@ LL |     let _: Struct4<isize> = Struct4 { field: 1 };
    = note: `#[warn(deprecated)]` on by default
 
 warning: use of deprecated struct `unstable_generic_param::Struct4`: test
-  --> $DIR/generics-default-stability.rs:83:12
+  --> $DIR/generics-default-stability.rs:71:12
    |
 LL |     let _: Struct4<isize> = Struct4 { field: 1 };
    |            ^^^^^^^
 
 warning: use of deprecated struct `unstable_generic_param::Struct4`: test
-  --> $DIR/generics-default-stability.rs:88:12
+  --> $DIR/generics-default-stability.rs:76:12
    |
 LL |     let _: Struct4 = STRUCT4;
    |            ^^^^^^^
 
 warning: use of deprecated struct `unstable_generic_param::Struct4`: test
-  --> $DIR/generics-default-stability.rs:89:12
+  --> $DIR/generics-default-stability.rs:77:12
    |
 LL |     let _: Struct4<usize> = STRUCT4;
    |            ^^^^^^^
 
 warning: use of deprecated struct `unstable_generic_param::Struct4`: test
-  --> $DIR/generics-default-stability.rs:90:29
+  --> $DIR/generics-default-stability.rs:78:29
    |
 LL |     let _: Struct4<isize> = Struct4 { field: 0 };
    |                             ^^^^^^^
 
 warning: use of deprecated struct `unstable_generic_param::Struct4`: test
-  --> $DIR/generics-default-stability.rs:90:12
+  --> $DIR/generics-default-stability.rs:78:12
    |
 LL |     let _: Struct4<isize> = Struct4 { field: 0 };
    |            ^^^^^^^
 
 warning: use of deprecated struct `unstable_generic_param::Struct5`: test
-  --> $DIR/generics-default-stability.rs:96:29
+  --> $DIR/generics-default-stability.rs:84:29
    |
 LL |     let _: Struct5<isize> = Struct5 { field: 1 };
    |                             ^^^^^^^
 
 warning: use of deprecated struct `unstable_generic_param::Struct5`: test
-  --> $DIR/generics-default-stability.rs:96:12
+  --> $DIR/generics-default-stability.rs:84:12
    |
 LL |     let _: Struct5<isize> = Struct5 { field: 1 };
    |            ^^^^^^^
 
 warning: use of deprecated struct `unstable_generic_param::Struct5`: test
-  --> $DIR/generics-default-stability.rs:101:12
+  --> $DIR/generics-default-stability.rs:89:12
    |
 LL |     let _: Struct5 = STRUCT5;
    |            ^^^^^^^
 
 warning: use of deprecated struct `unstable_generic_param::Struct5`: test
-  --> $DIR/generics-default-stability.rs:102:12
+  --> $DIR/generics-default-stability.rs:90:12
    |
 LL |     let _: Struct5<usize> = STRUCT5;
    |            ^^^^^^^
 
 warning: use of deprecated struct `unstable_generic_param::Struct5`: test
-  --> $DIR/generics-default-stability.rs:104:29
+  --> $DIR/generics-default-stability.rs:92:29
    |
 LL |     let _: Struct5<isize> = Struct5 { field: 0 };
    |                             ^^^^^^^
 
 warning: use of deprecated struct `unstable_generic_param::Struct5`: test
-  --> $DIR/generics-default-stability.rs:104:12
+  --> $DIR/generics-default-stability.rs:92:12
    |
 LL |     let _: Struct5<isize> = Struct5 { field: 0 };
    |            ^^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias4`: test
-  --> $DIR/generics-default-stability.rs:159:28
+  --> $DIR/generics-default-stability.rs:147:28
    |
 LL |     let _: Alias4<isize> = Alias4::Some(1);
    |                            ^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias4`: test
-  --> $DIR/generics-default-stability.rs:159:12
+  --> $DIR/generics-default-stability.rs:147:12
    |
 LL |     let _: Alias4<isize> = Alias4::Some(1);
    |            ^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias4`: test
-  --> $DIR/generics-default-stability.rs:163:12
+  --> $DIR/generics-default-stability.rs:151:12
    |
 LL |     let _: Alias4 = ALIAS4;
    |            ^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias4`: test
-  --> $DIR/generics-default-stability.rs:164:12
+  --> $DIR/generics-default-stability.rs:152:12
    |
 LL |     let _: Alias4<usize> = ALIAS4;
    |            ^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias4`: test
-  --> $DIR/generics-default-stability.rs:165:28
+  --> $DIR/generics-default-stability.rs:153:28
    |
 LL |     let _: Alias4<isize> = Alias4::Some(0);
    |                            ^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias4`: test
-  --> $DIR/generics-default-stability.rs:165:12
+  --> $DIR/generics-default-stability.rs:153:12
    |
 LL |     let _: Alias4<isize> = Alias4::Some(0);
    |            ^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias5`: test
-  --> $DIR/generics-default-stability.rs:170:28
+  --> $DIR/generics-default-stability.rs:158:28
    |
 LL |     let _: Alias5<isize> = Alias5::Some(1);
    |                            ^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias5`: test
-  --> $DIR/generics-default-stability.rs:170:12
+  --> $DIR/generics-default-stability.rs:158:12
    |
 LL |     let _: Alias5<isize> = Alias5::Some(1);
    |            ^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias5`: test
-  --> $DIR/generics-default-stability.rs:174:12
+  --> $DIR/generics-default-stability.rs:162:12
    |
 LL |     let _: Alias5 = ALIAS5;
    |            ^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias5`: test
-  --> $DIR/generics-default-stability.rs:175:12
+  --> $DIR/generics-default-stability.rs:163:12
    |
 LL |     let _: Alias5<usize> = ALIAS5;
    |            ^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias5`: test
-  --> $DIR/generics-default-stability.rs:177:28
+  --> $DIR/generics-default-stability.rs:165:28
    |
 LL |     let _: Alias5<isize> = Alias5::Some(0);
    |                            ^^^^^^
 
 warning: use of deprecated type alias `unstable_generic_param::Alias5`: test
-  --> $DIR/generics-default-stability.rs:177:12
+  --> $DIR/generics-default-stability.rs:165:12
    |
 LL |     let _: Alias5<isize> = Alias5::Some(0);
    |            ^^^^^^
 
 warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test
-  --> $DIR/generics-default-stability.rs:231:34
+  --> $DIR/generics-default-stability.rs:219:34
    |
 LL |     let _: Enum4<isize> = Enum4::Some(1);
    |                                  ^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum4`: test
-  --> $DIR/generics-default-stability.rs:231:12
+  --> $DIR/generics-default-stability.rs:219:12
    |
 LL |     let _: Enum4<isize> = Enum4::Some(1);
    |            ^^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum4`: test
-  --> $DIR/generics-default-stability.rs:235:12
+  --> $DIR/generics-default-stability.rs:223:12
    |
 LL |     let _: Enum4 = ENUM4;
    |            ^^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum4`: test
-  --> $DIR/generics-default-stability.rs:236:12
+  --> $DIR/generics-default-stability.rs:224:12
    |
 LL |     let _: Enum4<usize> = ENUM4;
    |            ^^^^^
 
 warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test
-  --> $DIR/generics-default-stability.rs:237:34
+  --> $DIR/generics-default-stability.rs:225:34
    |
 LL |     let _: Enum4<isize> = Enum4::Some(0);
    |                                  ^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum4`: test
-  --> $DIR/generics-default-stability.rs:237:12
+  --> $DIR/generics-default-stability.rs:225:12
    |
 LL |     let _: Enum4<isize> = Enum4::Some(0);
    |            ^^^^^
 
 warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test
-  --> $DIR/generics-default-stability.rs:242:34
+  --> $DIR/generics-default-stability.rs:230:34
    |
 LL |     let _: Enum5<isize> = Enum5::Some(1);
    |                                  ^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum5`: test
-  --> $DIR/generics-default-stability.rs:242:12
+  --> $DIR/generics-default-stability.rs:230:12
    |
 LL |     let _: Enum5<isize> = Enum5::Some(1);
    |            ^^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum5`: test
-  --> $DIR/generics-default-stability.rs:246:12
+  --> $DIR/generics-default-stability.rs:234:12
    |
 LL |     let _: Enum5 = ENUM5;
    |            ^^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum5`: test
-  --> $DIR/generics-default-stability.rs:247:12
+  --> $DIR/generics-default-stability.rs:235:12
    |
 LL |     let _: Enum5<usize> = ENUM5;
    |            ^^^^^
 
 warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test
-  --> $DIR/generics-default-stability.rs:249:34
+  --> $DIR/generics-default-stability.rs:237:34
    |
 LL |     let _: Enum5<isize> = Enum5::Some(0);
    |                                  ^^^^
 
 warning: use of deprecated enum `unstable_generic_param::Enum5`: test
-  --> $DIR/generics-default-stability.rs:249:12
+  --> $DIR/generics-default-stability.rs:237:12
    |
 LL |     let _: Enum5<isize> = Enum5::Some(0);
    |            ^^^^^
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:35:20
+  --> $DIR/generics-default-stability.rs:23:20
    |
 LL |     let _: Struct1<isize> = Struct1 { field: 1 };
    |                    ^^^^^
@@ -249,7 +225,7 @@ LL |     let _: Struct1<isize> = Struct1 { field: 1 };
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:39:20
+  --> $DIR/generics-default-stability.rs:27:20
    |
 LL |     let _: Struct1<usize> = STRUCT1;
    |                    ^^^^^
@@ -257,7 +233,7 @@ LL |     let _: Struct1<usize> = STRUCT1;
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:40:20
+  --> $DIR/generics-default-stability.rs:28:20
    |
 LL |     let _: Struct1<isize> = Struct1 { field: 0 };
    |                    ^^^^^
@@ -265,7 +241,7 @@ LL |     let _: Struct1<isize> = Struct1 { field: 0 };
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:69:27
+  --> $DIR/generics-default-stability.rs:57:27
    |
 LL |     let _: Struct3<isize, usize> = STRUCT3;
    |                           ^^^^^
@@ -273,7 +249,7 @@ LL |     let _: Struct3<isize, usize> = STRUCT3;
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:71:27
+  --> $DIR/generics-default-stability.rs:59:27
    |
 LL |     let _: Struct3<isize, isize> = Struct3 { field1: 0, field2: 0 };
    |                           ^^^^^
@@ -281,7 +257,7 @@ LL |     let _: Struct3<isize, isize> = Struct3 { field1: 0, field2: 0 };
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:72:27
+  --> $DIR/generics-default-stability.rs:60:27
    |
 LL |     let _: Struct3<usize, usize> = Struct3 { field1: 0, field2: 0 };
    |                           ^^^^^
@@ -289,7 +265,7 @@ LL |     let _: Struct3<usize, usize> = Struct3 { field1: 0, field2: 0 };
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:96:20
+  --> $DIR/generics-default-stability.rs:84:20
    |
 LL |     let _: Struct5<isize> = Struct5 { field: 1 };
    |                    ^^^^^
@@ -297,7 +273,7 @@ LL |     let _: Struct5<isize> = Struct5 { field: 1 };
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:102:20
+  --> $DIR/generics-default-stability.rs:90:20
    |
 LL |     let _: Struct5<usize> = STRUCT5;
    |                    ^^^^^
@@ -305,7 +281,7 @@ LL |     let _: Struct5<usize> = STRUCT5;
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:104:20
+  --> $DIR/generics-default-stability.rs:92:20
    |
 LL |     let _: Struct5<isize> = Struct5 { field: 0 };
    |                    ^^^^^
@@ -313,7 +289,7 @@ LL |     let _: Struct5<isize> = Struct5 { field: 0 };
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:112:19
+  --> $DIR/generics-default-stability.rs:100:19
    |
 LL |     let _: Alias1<isize> = Alias1::Some(1);
    |                   ^^^^^
@@ -321,7 +297,7 @@ LL |     let _: Alias1<isize> = Alias1::Some(1);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:116:19
+  --> $DIR/generics-default-stability.rs:104:19
    |
 LL |     let _: Alias1<usize> = ALIAS1;
    |                   ^^^^^
@@ -329,7 +305,7 @@ LL |     let _: Alias1<usize> = ALIAS1;
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:117:19
+  --> $DIR/generics-default-stability.rs:105:19
    |
 LL |     let _: Alias1<isize> = Alias1::Some(0);
    |                   ^^^^^
@@ -337,7 +313,7 @@ LL |     let _: Alias1<isize> = Alias1::Some(0);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:145:26
+  --> $DIR/generics-default-stability.rs:133:26
    |
 LL |     let _: Alias3<isize, usize> = ALIAS3;
    |                          ^^^^^
@@ -345,7 +321,7 @@ LL |     let _: Alias3<isize, usize> = ALIAS3;
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:147:26
+  --> $DIR/generics-default-stability.rs:135:26
    |
 LL |     let _: Alias3<isize, isize> = Alias3::Ok(0);
    |                          ^^^^^
@@ -353,7 +329,7 @@ LL |     let _: Alias3<isize, isize> = Alias3::Ok(0);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:148:26
+  --> $DIR/generics-default-stability.rs:136:26
    |
 LL |     let _: Alias3<usize, usize> = Alias3::Ok(0);
    |                          ^^^^^
@@ -361,7 +337,7 @@ LL |     let _: Alias3<usize, usize> = Alias3::Ok(0);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:170:19
+  --> $DIR/generics-default-stability.rs:158:19
    |
 LL |     let _: Alias5<isize> = Alias5::Some(1);
    |                   ^^^^^
@@ -369,7 +345,7 @@ LL |     let _: Alias5<isize> = Alias5::Some(1);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:175:19
+  --> $DIR/generics-default-stability.rs:163:19
    |
 LL |     let _: Alias5<usize> = ALIAS5;
    |                   ^^^^^
@@ -377,7 +353,7 @@ LL |     let _: Alias5<usize> = ALIAS5;
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:177:19
+  --> $DIR/generics-default-stability.rs:165:19
    |
 LL |     let _: Alias5<isize> = Alias5::Some(0);
    |                   ^^^^^
@@ -385,7 +361,7 @@ LL |     let _: Alias5<isize> = Alias5::Some(0);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:184:18
+  --> $DIR/generics-default-stability.rs:172:18
    |
 LL |     let _: Enum1<isize> = Enum1::Some(1);
    |                  ^^^^^
@@ -393,7 +369,7 @@ LL |     let _: Enum1<isize> = Enum1::Some(1);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:188:18
+  --> $DIR/generics-default-stability.rs:176:18
    |
 LL |     let _: Enum1<usize> = ENUM1;
    |                  ^^^^^
@@ -401,7 +377,7 @@ LL |     let _: Enum1<usize> = ENUM1;
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:189:18
+  --> $DIR/generics-default-stability.rs:177:18
    |
 LL |     let _: Enum1<isize> = Enum1::Some(0);
    |                  ^^^^^
@@ -409,7 +385,7 @@ LL |     let _: Enum1<isize> = Enum1::Some(0);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:217:25
+  --> $DIR/generics-default-stability.rs:205:25
    |
 LL |     let _: Enum3<isize, usize> = ENUM3;
    |                         ^^^^^
@@ -417,7 +393,7 @@ LL |     let _: Enum3<isize, usize> = ENUM3;
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:219:25
+  --> $DIR/generics-default-stability.rs:207:25
    |
 LL |     let _: Enum3<isize, isize> = Enum3::Ok(0);
    |                         ^^^^^
@@ -425,7 +401,7 @@ LL |     let _: Enum3<isize, isize> = Enum3::Ok(0);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:220:25
+  --> $DIR/generics-default-stability.rs:208:25
    |
 LL |     let _: Enum3<usize, usize> = Enum3::Ok(0);
    |                         ^^^^^
@@ -433,7 +409,7 @@ LL |     let _: Enum3<usize, usize> = Enum3::Ok(0);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:242:18
+  --> $DIR/generics-default-stability.rs:230:18
    |
 LL |     let _: Enum5<isize> = Enum5::Some(1);
    |                  ^^^^^
@@ -441,7 +417,7 @@ LL |     let _: Enum5<isize> = Enum5::Some(1);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:247:18
+  --> $DIR/generics-default-stability.rs:235:18
    |
 LL |     let _: Enum5<usize> = ENUM5;
    |                  ^^^^^
@@ -449,7 +425,7 @@ LL |     let _: Enum5<usize> = ENUM5;
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'unstable_default'
-  --> $DIR/generics-default-stability.rs:249:18
+  --> $DIR/generics-default-stability.rs:237:18
    |
 LL |     let _: Enum5<isize> = Enum5::Some(0);
    |                  ^^^^^
@@ -457,7 +433,7 @@ LL |     let _: Enum5<isize> = Enum5::Some(0);
    = help: add `#![feature(unstable_default)]` to the crate attributes to enable
 
 error[E0658]: use of unstable library feature 'box_alloc_param'
-  --> $DIR/generics-default-stability.rs:256:24
+  --> $DIR/generics-default-stability.rs:244:24
    |
 LL |     let _: Box1<isize, System> = Box1::new(1);
    |                        ^^^^^^
@@ -465,29 +441,29 @@ LL |     let _: Box1<isize, System> = Box1::new(1);
    = help: add `#![feature(box_alloc_param)]` to the crate attributes to enable
 
 warning: use of deprecated field `unstable_generic_param::Struct4::field`: test
-  --> $DIR/generics-default-stability.rs:83:39
+  --> $DIR/generics-default-stability.rs:71:39
    |
 LL |     let _: Struct4<isize> = Struct4 { field: 1 };
    |                                       ^^^^^^^^
 
 warning: use of deprecated field `unstable_generic_param::Struct4::field`: test
-  --> $DIR/generics-default-stability.rs:90:39
+  --> $DIR/generics-default-stability.rs:78:39
    |
 LL |     let _: Struct4<isize> = Struct4 { field: 0 };
    |                                       ^^^^^^^^
 
 warning: use of deprecated field `unstable_generic_param::Struct5::field`: test
-  --> $DIR/generics-default-stability.rs:96:39
+  --> $DIR/generics-default-stability.rs:84:39
    |
 LL |     let _: Struct5<isize> = Struct5 { field: 1 };
    |                                       ^^^^^^^^
 
 warning: use of deprecated field `unstable_generic_param::Struct5::field`: test
-  --> $DIR/generics-default-stability.rs:104:39
+  --> $DIR/generics-default-stability.rs:92:39
    |
 LL |     let _: Struct5<isize> = Struct5 { field: 0 };
    |                                       ^^^^^^^^
 
-error: aborting due to 31 previous errors; 40 warnings emitted
+error: aborting due to 28 previous errors; 40 warnings emitted
 
 For more information about this error, try `rustc --explain E0658`.
index 9b9e70a675fb1119725baa0152398e0587d6e005..e79be2f6127c1fb840e2f134cff6c6a93ab6c0e8 100644 (file)
@@ -8,7 +8,7 @@ fn foo(x: Ty) -> Ty {
         Ty::Unit => Ty::Unit,
         Ty::List(elem) => foo(elem),
         //~^ ERROR mismatched types
-        //~| HELP try dereferencing the `Box`
+        //~| HELP consider unboxing the value
         //~| HELP try wrapping
     }
 }
index e865b993a4c178bb128935eef88c7afaf6a286ae..9a31dc89197e36209a295f4c8e319761ee1448c9 100644 (file)
@@ -6,7 +6,7 @@ LL |         Ty::List(elem) => foo(elem),
    |
    = note: expected enum `Ty`
             found struct `Box<Ty>`
-help: try dereferencing the `Box`
+help: consider unboxing the value
    |
 LL |         Ty::List(elem) => foo(*elem),
    |                               +
diff --git a/src/test/ui/suggestions/while-let-typo.rs b/src/test/ui/suggestions/while-let-typo.rs
new file mode 100644 (file)
index 0000000..dbbcdee
--- /dev/null
@@ -0,0 +1,9 @@
+fn main() {
+    let foo = Some(0);
+    let bar = None;
+    while Some(x) = foo {} //~ ERROR cannot find value `x` in this scope
+    while Some(foo) = bar {}
+    while 3 = foo {} //~ ERROR mismatched types
+    while Some(3) = foo {} //~ ERROR invalid left-hand side of assignment
+    while x = 5 {} //~ ERROR cannot find value `x` in this scope
+}
diff --git a/src/test/ui/suggestions/while-let-typo.stderr b/src/test/ui/suggestions/while-let-typo.stderr
new file mode 100644 (file)
index 0000000..7cc2ed3
--- /dev/null
@@ -0,0 +1,45 @@
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/while-let-typo.rs:4:16
+   |
+LL |     while Some(x) = foo {}
+   |                ^ not found in this scope
+   |
+help: you might have meant to use pattern matching
+   |
+LL |     while let Some(x) = foo {}
+   |           +++
+
+error[E0425]: cannot find value `x` in this scope
+  --> $DIR/while-let-typo.rs:8:11
+   |
+LL |     while x = 5 {}
+   |           ^ not found in this scope
+   |
+help: you might have meant to use pattern matching
+   |
+LL |     while let x = 5 {}
+   |           +++
+
+error[E0308]: mismatched types
+  --> $DIR/while-let-typo.rs:6:11
+   |
+LL |     while 3 = foo {}
+   |           ^^^^^^^ expected `bool`, found `()`
+
+error[E0070]: invalid left-hand side of assignment
+  --> $DIR/while-let-typo.rs:7:19
+   |
+LL |     while Some(3) = foo {}
+   |                -  ^
+   |                |
+   |                cannot assign to this expression
+   |
+help: you might have meant to use pattern destructuring
+   |
+LL |     while let Some(3) = foo {}
+   |           +++
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0070, E0308, E0425.
+For more information about an error, try `rustc --explain E0070`.
index a6fbe98e6ed4194d3e851e3f24fbf9776ca5ebaf..65a63262810feadb45b9da166693f60a4ce545e6 100644 (file)
@@ -1,7 +1,7 @@
 // build-fail
 // revisions: legacy v0
-//[legacy]compile-flags: -Z symbol-mangling-version=legacy
-    //[v0]compile-flags: -Z symbol-mangling-version=v0
+//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
+    //[v0]compile-flags: -C symbol-mangling-version=v0
 
 #![feature(rustc_attrs)]
 
index d44c8f0abaec81d10b4c71b4db398b718b43782f..5c40c391a9e0b621bac86c75fb113e52d2280fd4 100644 (file)
@@ -1,5 +1,5 @@
 // build-fail
-// compile-flags: -Z symbol-mangling-version=v0 --crate-name=c
+// compile-flags: -C symbol-mangling-version=v0 --crate-name=c
 // normalize-stderr-test: "c\[.*?\]" -> "c[HASH]"
 #![feature(rustc_attrs)]
 
index 300f6510380f416876bdf7fd907a2b7f26804bd4..619b34f2559a80040db39929bdc65a21c5ad0c92 100644 (file)
@@ -1,5 +1,5 @@
 // build-fail
-// compile-flags: -Z symbol-mangling-version=v0 --crate-name=c
+// compile-flags: -C symbol-mangling-version=v0 --crate-name=c
 // normalize-stderr-test: "c\[.*?\]" -> "c[HASH]"
 #![feature(adt_const_params, rustc_attrs)]
 #![allow(incomplete_features)]
index 73de48fed6c60cbd50002af0e2d98682a72e88e4..df09ba494a74f76ebaef9f2be76998e345d82103 100644 (file)
@@ -1,5 +1,5 @@
 // build-fail
-// compile-flags: -Z symbol-mangling-version=v0 --crate-name=c
+// compile-flags: -C symbol-mangling-version=v0 --crate-name=c
 
 // NOTE(eddyb) we need `core` for `core::option::Option`, normalize away its
 // disambiguator hash, which can/should change (including between stage{1,2}).
index 2d136e6a99a831f5badae45f34e16b27e54abbd3..1242126e0cceee01cc897bf72e969b761c2b113e 100644 (file)
@@ -1,7 +1,7 @@
 // check-pass
 // revisions: legacy v0
-//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib
-//[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
+//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy --crate-type=lib
+//[v0]compile-flags: -C symbol-mangling-version=v0 --crate-type=lib
 
 // `char`
 pub struct Char<const F: char>;
index f20cb1c01fd7350df3a39fa50d2f3c4fe99ca2d1..86f0a8b0bef4dfc8c47c9d198c2aa7e1abde2336 100644 (file)
@@ -1,7 +1,7 @@
 // build-fail
 // revisions: legacy v0
-//[legacy]compile-flags: -Z symbol-mangling-version=legacy
-    //[v0]compile-flags: -Z symbol-mangling-version=v0
+//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
+    //[v0]compile-flags: -C symbol-mangling-version=v0
 //[legacy]normalize-stderr-test: "h[\w]{16}E?\)" -> "<SYMBOL_HASH>)"
 
 #![feature(auto_traits, rustc_attrs)]
index 57114ca1f15822308d5814de83361a9589f4a942..ab0a3a7df1d15ec1ca717defcf8133e86387b940 100644 (file)
@@ -1,7 +1,7 @@
 // build-fail
 // revisions: legacy v0
-//[legacy]compile-flags: -Z symbol-mangling-version=legacy
-    //[v0]compile-flags: -Z symbol-mangling-version=v0
+//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
+    //[v0]compile-flags: -C symbol-mangling-version=v0
 
 #![feature(rustc_attrs)]
 
index d1bc152af5c609c6c672efcbb00ccd2c2d8efa35..4a1f5a21263dd309fc1a6cd7b5c111f1c59206bf 100644 (file)
@@ -1,7 +1,7 @@
 // build-fail
 // revisions: legacy v0
-//[legacy]compile-flags: -Z symbol-mangling-version=legacy
-//[v0]compile-flags: -Z symbol-mangling-version=v0
+//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy
+//[v0]compile-flags: -C symbol-mangling-version=v0
 //[legacy]normalize-stderr-test: "h[\w{16}]+" -> "SYMBOL_HASH"
 
 #![feature(rustc_attrs)]
index c2e9f92f7b539c28635ee83de38d80185607619d..932057b659081e53602983322fb3b4bf00b5319e 100644 (file)
@@ -1,7 +1,7 @@
 // check-pass
 // revisions: legacy v0
-//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib
-//[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
+//[legacy]compile-flags: -Z unstable-options -C symbol-mangling-version=legacy --crate-type=lib
+//[v0]compile-flags: -C symbol-mangling-version=v0 --crate-type=lib
 
 
 pub struct Bar<const F: bool>;
index 502afebcb5ae8ea69c252312fb8672e5cb7b2394..5bcbc08413fe10b83cf5c364bf2cc9cbc0e19823 100644 (file)
@@ -2,7 +2,7 @@
 
 // build-fail
 // revisions: v0
-//[v0]compile-flags: -Z symbol-mangling-version=v0
+//[v0]compile-flags: -C symbol-mangling-version=v0
 //[v0]normalize-stderr-test: "core\[.*?\]" -> "core[HASH]"
 
 #![feature(rustc_attrs)]
index 65d90678040d5ff094278cde42b3bb483ad2d067..34d4d9eaded8ac167dc6bcbc7ec23c415dc37e68 100644 (file)
@@ -6,7 +6,7 @@ LL |     want_foo(b);
    |
    = note: expected struct `Foo`
               found struct `Box<Foo>`
-help: try dereferencing the `Box`
+help: consider unboxing the value
    |
 LL |     want_foo(*b);
    |              +
diff --git a/src/test/ui/traits/pointee-deduction.rs b/src/test/ui/traits/pointee-deduction.rs
new file mode 100644 (file)
index 0000000..f888246
--- /dev/null
@@ -0,0 +1,22 @@
+// run-pass
+
+#![feature(ptr_metadata)]
+
+use std::alloc::Layout;
+use std::ptr::Pointee;
+
+trait Foo {
+    type Bar;
+}
+
+impl Foo for () {
+    type Bar = ();
+}
+
+struct Wrapper1<T: Foo>(<T as Foo>::Bar);
+struct Wrapper2<T: Foo>(<Wrapper1<T> as Pointee>::Metadata);
+
+fn main() {
+    let _: Wrapper2<()> = Wrapper2(());
+    let _ = Layout::new::<Wrapper2<()>>();
+}
index 579067340e85cb72df1cb5775ab0d5df604afdf9..cee8186dd8f8c432c3a2ccf10f49ae3822e120f5 100644 (file)
@@ -15,9 +15,5 @@ impl<W> Trait<W> for () {}
 
 fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
     //~^ ERROR non-defining opaque type use in defining scope
-    //~| ERROR non-defining opaque type use in defining scope
-    //~| ERROR non-defining opaque type use in defining scope
-    //~| ERROR `T` is part of concrete type but not used in parameter list
-    //~| ERROR `T` is part of concrete type but not used in parameter list
     ()
 }
index a77c0000f12e1a0571b4a3710747e7104226243f..03e696fe8980376392a3df6e8219d9ae3dbd03fc 100644 (file)
@@ -1,34 +1,8 @@
-error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/bound_reduction2.rs:16:60
-   |
-LL |   fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
-   |  ____________________________________________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     ()
-LL | | }
-   | |_^
-
-error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias
-  --> $DIR/bound_reduction2.rs:16:60
-   |
-LL |   fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
-   |  ____________________________________________________________^
-LL | |
-LL | |
-LL | |
-...  |
-LL | |     ()
-LL | | }
-   | |_^
-
 error: non-defining opaque type use in defining scope
-  --> $DIR/bound_reduction2.rs:16:1
+  --> $DIR/bound_reduction2.rs:16:46
    |
 LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                                              ^^^^^^^^^^^^^
    |
 note: used non-generic type `<T as TraitWithAssoc>::Assoc` for generic parameter
   --> $DIR/bound_reduction2.rs:9:10
@@ -36,35 +10,11 @@ note: used non-generic type `<T as TraitWithAssoc>::Assoc` for generic parameter
 LL | type Foo<V> = impl Trait<V>;
    |          ^
 
-error: non-defining opaque type use in defining scope
-  --> $DIR/bound_reduction2.rs:16:1
-   |
-LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: used non-generic type `_` for generic parameter
-  --> $DIR/bound_reduction2.rs:9:10
-   |
-LL | type Foo<V> = impl Trait<V>;
-   |          ^
-
-error: non-defining opaque type use in defining scope
-  --> $DIR/bound_reduction2.rs:16:1
-   |
-LL | fn foo_desugared<T: TraitWithAssoc>(_: T) -> Foo<T::Assoc> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: used non-generic type `_` for generic parameter
-  --> $DIR/bound_reduction2.rs:9:10
-   |
-LL | type Foo<V> = impl Trait<V>;
-   |          ^
-
 error: could not find defining uses
   --> $DIR/bound_reduction2.rs:9:15
    |
 LL | type Foo<V> = impl Trait<V>;
    |               ^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error: aborting due to 2 previous errors
 
index 8c9cb742fac91f12814c64af1ed4806180b25a04..a4ccae4eb7ed99e7b5b49de3479f78aa5db2f44b 100644 (file)
@@ -10,5 +10,29 @@ error: higher-ranked subtype error
 LL |         |x| x
    |         ^^^^^
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/issue-57611-trait-alias.rs:17:16
+   |
+LL |     type Bar = impl Baz<Self, Self>;
+   |                ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
+   |
+   = note: expected type `for<'r> Fn<(&'r X,)>`
+              found type `Fn<(&'static X,)>`
+note: this closure does not fulfill the lifetime requirements
+  --> $DIR/issue-57611-trait-alias.rs:21:9
+   |
+LL |         |x| x
+   |         ^^^^^
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/issue-57611-trait-alias.rs:17:16
+   |
+LL |     type Bar = impl Baz<Self, Self>;
+   |                ^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
+   |
+   = note: closure with signature `fn(&'static X) -> &'static X` must implement `FnOnce<(&'0 X,)>`, for any lifetime `'0`...
+   = note: ...but it actually implements `FnOnce<(&'static X,)>`
+
+error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
index 340acff34f2ab76fd47e23f6a1792a37a95d500b..dedafd85cfd61d3d397f60d8caf2d59d527d0346 100644 (file)
@@ -11,6 +11,6 @@ anyhow = "1.0.32"
 flate2 = "1.0.16"
 tar = "0.4.29"
 sha2 = "0.9.1"
-rayon = "1.3.1"
+rayon = "1.5.1"
 hex = "0.4.2"
 num_cpus = "1.13.0"
index fcef61230c3b6213b6b0d233a36ba4ebd1649ec3..06b9d31743210b788b130c8a484c2838afa6fc27 160000 (submodule)
@@ -1 +1 @@
-Subproject commit fcef61230c3b6213b6b0d233a36ba4ebd1649ec3
+Subproject commit 06b9d31743210b788b130c8a484c2838afa6fc27
index 688473f2f9bfcee25d3d1f7484967cbcd1ec3154..f3dd9275a42be6cd00a326912009fa3cb8a4df66 100644 (file)
@@ -2,9 +2,12 @@
 uitest = "test --test compile-test"
 dev = "run --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --"
 lintcheck = "run --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml  -- "
-collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored"
+collect-metadata = "test --test dogfood --features internal -- run_metadata_collection_lint --ignored"
 
 [build]
 # -Zbinary-dep-depinfo allows us to track which rlib files to use for compiling UI tests
 rustflags = ["-Zunstable-options", "-Zbinary-dep-depinfo"]
 target-dir = "target"
+
+[unstable]
+binary-dep-depinfo = true
index 3d8c39408a924b5601d27262e8cb91811cfc8456..116ae031bb719d7b8a6b62223308a01289c09e1a 100644 (file)
@@ -49,17 +49,17 @@ jobs:
         echo "LD_LIBRARY_PATH=${SYSROOT}/lib${LD_LIBRARY_PATH+:${LD_LIBRARY_PATH}}" >> $GITHUB_ENV
 
     - name: Build
-      run: cargo build --features deny-warnings,internal-lints,metadata-collector-lint
+      run: cargo build --features deny-warnings,internal
 
     - name: Test
-      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
+      run: cargo test --features deny-warnings,internal
 
     - name: Test clippy_lints
-      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
+      run: cargo test --features deny-warnings,internal
       working-directory: clippy_lints
 
     - name: Test clippy_utils
-      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
+      run: cargo test --features deny-warnings,internal
       working-directory: clippy_utils
 
     - name: Test rustc_tools_util
@@ -70,14 +70,6 @@ jobs:
       run: cargo test --features deny-warnings
       working-directory: clippy_dev
 
-    - name: Test cargo-clippy
-      run: ../target/debug/cargo-clippy
-      working-directory: clippy_workspace_tests
-
-    - name: Test cargo-clippy --fix
-      run: ../target/debug/cargo-clippy clippy --fix
-      working-directory: clippy_workspace_tests
-
     - name: Test clippy-driver
       run: bash .github/driver.sh
       env:
index 8b644aa28176b6e4fc44de9dcf81b3c8cd09dc58..989667037c1cb4e23a0dcb0e2802023258510e4f 100644 (file)
@@ -112,17 +112,22 @@ jobs:
         echo "$SYSROOT/bin" >> $GITHUB_PATH
 
     - name: Build
-      run: cargo build --features deny-warnings,internal-lints,metadata-collector-lint
+      run: cargo build --features deny-warnings,internal
 
     - name: Test
-      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
+      if: runner.os == 'Linux'
+      run: cargo test --features deny-warnings,internal
+
+    - name: Test
+      if: runner.os != 'Linux'
+      run: cargo test --features deny-warnings,internal -- --skip dogfood
 
     - name: Test clippy_lints
-      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
+      run: cargo test --features deny-warnings,internal
       working-directory: clippy_lints
 
     - name: Test clippy_utils
-      run: cargo test --features deny-warnings,internal-lints,metadata-collector-lint
+      run: cargo test --features deny-warnings,internal
       working-directory: clippy_utils
 
     - name: Test rustc_tools_util
@@ -133,14 +138,6 @@ jobs:
       run: cargo test --features deny-warnings
       working-directory: clippy_dev
 
-    - name: Test cargo-clippy
-      run: ../target/debug/cargo-clippy
-      working-directory: clippy_workspace_tests
-
-    - name: Test cargo-clippy --fix
-      run: ../target/debug/cargo-clippy clippy --fix
-      working-directory: clippy_workspace_tests
-
     - name: Test clippy-driver
       run: bash .github/driver.sh
       env:
index e82a0ec4765bb25b5a284ffe75bce721e0d5cd1b..3e50c45a9b63ec8922446ef907cb10e220a33772 100644 (file)
@@ -19,7 +19,6 @@ out
 /target
 /clippy_lints/target
 /clippy_utils/target
-/clippy_workspace_tests/target
 /clippy_dev/target
 /lintcheck/target
 /rustc_tools_util/target
index 27bac4718b6c3b0c6705c7fcfb0578fd77dd372e..8f4da9a382792a31443c9a81c6db1794ff2a04d1 100644 (file)
@@ -2887,6 +2887,7 @@ Released 2018-09-13
 [`blocks_in_if_conditions`]: https://rust-lang.github.io/rust-clippy/master/index.html#blocks_in_if_conditions
 [`bool_assert_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_assert_comparison
 [`bool_comparison`]: https://rust-lang.github.io/rust-clippy/master/index.html#bool_comparison
+[`borrow_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_as_ptr
 [`borrow_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrow_interior_mutable_const
 [`borrowed_box`]: https://rust-lang.github.io/rust-clippy/master/index.html#borrowed_box
 [`box_collection`]: https://rust-lang.github.io/rust-clippy/master/index.html#box_collection
@@ -3070,6 +3071,7 @@ Released 2018-09-13
 [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
 [`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
 [`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
+[`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
 [`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
 [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
 [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
@@ -3253,6 +3255,7 @@ Released 2018-09-13
 [`should_implement_trait`]: https://rust-lang.github.io/rust-clippy/master/index.html#should_implement_trait
 [`similar_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#similar_names
 [`single_char_add_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str
+[`single_char_lifetime_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_lifetime_names
 [`single_char_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern
 [`single_component_path_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_component_path_imports
 [`single_element_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#single_element_loop
index 8661a86775887285bc953c4ec7afbbb68a313830..e445889a58f77d7b4db6354b2ad7aa3c4a5a9e3f 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.59"
+version = "0.1.60"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -47,7 +47,9 @@ itertools = "0.10"
 quote = "1.0"
 serde = { version = "1.0", features = ["derive"] }
 syn = { version = "1.0", features = ["full"] }
+futures = "0.3"
 parking_lot = "0.11.2"
+tokio = { version = "1", features = ["io-util"] }
 
 [build-dependencies]
 rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
@@ -55,8 +57,7 @@ rustc_tools_util = { version = "0.2", path = "rustc_tools_util" }
 [features]
 deny-warnings = ["clippy_lints/deny-warnings"]
 integration = ["tempfile"]
-internal-lints = ["clippy_lints/internal-lints"]
-metadata-collector-lint = ["internal-lints", "clippy_lints/metadata-collector-lint"]
+internal = ["clippy_lints/internal"]
 
 [package.metadata.rust-analyzer]
 # This package uses #[feature(rustc_private)]
index 1bbd89e7822e8a8f7d7d01c29b8302432c145ea4..f001a42d917d3134db7457aeb95713434bd3084c 100644 (file)
@@ -5,7 +5,7 @@
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-[There are over 450 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 500 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
 You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
@@ -37,8 +37,8 @@ Table of contents:
 
 ## Usage
 
-Below are instructions on how to use Clippy as a subcommand, compiled from source
-or in Travis CI.
+Below are instructions on how to use Clippy as a cargo subcommand,
+in projects that do not use cargo, or in Travis CI.
 
 ### As a cargo subcommand (`cargo clippy`)
 
@@ -98,22 +98,18 @@ If you want to run Clippy **only** on the given crate, use the `--no-deps` optio
 cargo clippy -p example -- --no-deps
 ```
 
-### As a rustc replacement (`clippy-driver`)
+### Using `clippy-driver`
 
-Clippy can also be used in projects that do not use cargo. To do so, you will need to replace
-your `rustc` compilation commands with `clippy-driver`. For example, if your project runs:
-
-```terminal
-rustc --edition 2018 -Cpanic=abort foo.rs
-```
-
-Then, to enable Clippy, you will need to call:
+Clippy can also be used in projects that do not use cargo. To do so, run `clippy-driver`
+with the same arguments you use for `rustc`. For example:
 
 ```terminal
 clippy-driver --edition 2018 -Cpanic=abort foo.rs
 ```
 
-Note that `rustc` will still run, i.e. it will still emit the output files it normally does.
+Note that `clippy-driver` is designed for running Clippy only and should not be used as a general
+replacement for `rustc`. `clippy-driver` may produce artifacts that are not optimized as expected,
+for example.
 
 ### Travis CI
 
index 9ceadee58ea5981777ff171d7a94ad7c9f09e41d..d513a229b7e386d3178c7055a2140f8d263c8a8a 100644 (file)
@@ -3,7 +3,7 @@
 use shell_escape::escape;
 use std::ffi::{OsStr, OsString};
 use std::path::Path;
-use std::process::{self, Command};
+use std::process::{self, Command, Stdio};
 use std::{fs, io};
 use walkdir::WalkDir;
 
@@ -31,6 +31,7 @@ fn from(error: walkdir::Error) -> Self {
 struct FmtContext {
     check: bool,
     verbose: bool,
+    rustfmt_path: String,
 }
 
 // the "main" function of cargo dev fmt
@@ -102,7 +103,23 @@ fn output_err(err: CliError) {
         }
     }
 
-    let context = FmtContext { check, verbose };
+    let output = Command::new("rustup")
+        .args(["which", "rustfmt"])
+        .stderr(Stdio::inherit())
+        .output()
+        .expect("error running `rustup which rustfmt`");
+    if !output.status.success() {
+        eprintln!("`rustup which rustfmt` did not execute successfully");
+        process::exit(1);
+    }
+    let mut rustfmt_path = String::from_utf8(output.stdout).expect("invalid rustfmt path");
+    rustfmt_path.truncate(rustfmt_path.trim_end().len());
+
+    let context = FmtContext {
+        check,
+        verbose,
+        rustfmt_path,
+    };
     let result = try_run(&context);
     let code = match result {
         Ok(true) => 0,
@@ -141,8 +158,12 @@ fn exec(
         println!("{}", format_command(&program, &dir, args));
     }
 
-    let child = Command::new(&program).current_dir(&dir).args(args.iter()).spawn()?;
-    let output = child.wait_with_output()?;
+    let output = Command::new(&program)
+        .env("RUSTFMT", &context.rustfmt_path)
+        .current_dir(&dir)
+        .args(args.iter())
+        .output()
+        .unwrap();
     let success = output.status.success();
 
     if !context.check && !success {
@@ -159,7 +180,6 @@ fn exec(
 fn cargo_fmt(context: &FmtContext, path: &Path) -> Result<bool, CliError> {
     let mut args = vec!["fmt", "--all"];
     if context.check {
-        args.push("--");
         args.push("--check");
     }
     let success = exec(context, "cargo", path, &args)?;
@@ -200,7 +220,7 @@ fn rustfmt(context: &FmtContext, paths: impl Iterator<Item = OsString>) -> Resul
     }
     args.extend(paths);
 
-    let success = exec(context, "rustfmt", std::env::current_dir()?, &args)?;
+    let success = exec(context, &context.rustfmt_path, std::env::current_dir()?, &args)?;
 
     Ok(success)
 }
index 8dd073ef405a172960a8886488ec61b183c6d906..d368ef1f46a2a98866e6aedcf32581c9ce17c047 100644 (file)
@@ -321,7 +321,7 @@ fn gen_register_lint_list<'a>(
 
     for (is_public, module_name, lint_name) in details {
         if !is_public {
-            output.push_str("    #[cfg(feature = \"internal-lints\")]\n");
+            output.push_str("    #[cfg(feature = \"internal\")]\n");
         }
         output.push_str(&format!("    {}::{},\n", module_name, lint_name));
     }
index 7d2a3e4f639c3a2182c338de4301c9a62775693a..2053ca64ba23d19626dfdbaaebd826f70d82a4db 100644 (file)
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.59"
+version = "0.1.60"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
@@ -30,8 +30,7 @@ url = { version = "2.2", features = ["serde"] }
 [features]
 deny-warnings = ["clippy_utils/deny-warnings"]
 # build clippy with internal lints enabled, off by default
-internal-lints = ["clippy_utils/internal-lints"]
-metadata-collector-lint = ["serde_json", "clippy_utils/metadata-collector-lint"]
+internal = ["clippy_utils/internal", "serde_json"]
 
 [package.metadata.rust-analyzer]
 # This crate uses #[feature(rustc_private)]
index b7f414742f1566bd69731f71ce323c6364c7b947..c82837746bd5d1086ea8fbfb29a3f8b62b00abfd 100644 (file)
@@ -1,12 +1,10 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::higher;
-use clippy_utils::source::snippet_opt;
-use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call, peel_blocks};
-use if_chain::if_chain;
-use rustc_hir::{Expr, ExprKind, UnOp};
+use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
+use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
 
 impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        let lint_true = |is_debug: bool| {
-            span_lint_and_help(
-                cx,
-                ASSERTIONS_ON_CONSTANTS,
-                e.span,
-                if is_debug {
-                    "`debug_assert!(true)` will be optimized out by the compiler"
-                } else {
-                    "`assert!(true)` will be optimized out by the compiler"
-                },
-                None,
-                "remove it",
-            );
+        let Some(macro_call) = root_macro_call_first_node(cx, e) else { return };
+        let is_debug = match cx.tcx.get_diagnostic_name(macro_call.def_id) {
+            Some(sym::debug_assert_macro) => true,
+            Some(sym::assert_macro) => false,
+            _ => return,
         };
-        let lint_false_without_message = || {
+        let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return };
+        let Some((Constant::Bool(val), _)) = constant(cx, cx.typeck_results(), condition) else { return };
+        if val {
             span_lint_and_help(
                 cx,
                 ASSERTIONS_ON_CONSTANTS,
-                e.span,
-                "`assert!(false)` should probably be replaced",
+                macro_call.span,
+                &format!(
+                    "`{}!(true)` will be optimized out by the compiler",
+                    cx.tcx.item_name(macro_call.def_id)
+                ),
                 None,
-                "use `panic!()` or `unreachable!()`",
+                "remove it",
             );
-        };
-        let lint_false_with_message = |panic_message: String| {
+        } else if !is_debug {
+            let (assert_arg, panic_arg) = match panic_expn {
+                PanicExpn::Empty => ("", ""),
+                _ => (", ..", ".."),
+            };
             span_lint_and_help(
                 cx,
                 ASSERTIONS_ON_CONSTANTS,
-                e.span,
-                &format!("`assert!(false, {})` should probably be replaced", panic_message),
+                macro_call.span,
+                &format!("`assert!(false{})` should probably be replaced", assert_arg),
                 None,
-                &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message),
+                &format!("use `panic!({})` or `unreachable!({0})`", panic_arg),
             );
-        };
-
-        if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") {
-            if debug_assert_span.from_expansion() {
-                return;
-            }
-            if_chain! {
-                if let ExprKind::Unary(_, lit) = e.kind;
-                if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), lit);
-                if is_true;
-                then {
-                    lint_true(true);
-                }
-            };
-        } else if let Some(assert_span) = is_direct_expn_of(e.span, "assert") {
-            if assert_span.from_expansion() {
-                return;
-            }
-            if let Some(assert_match) = match_assert_with_message(cx, e) {
-                match assert_match {
-                    // matched assert but not message
-                    AssertKind::WithoutMessage(false) => lint_false_without_message(),
-                    AssertKind::WithoutMessage(true) | AssertKind::WithMessage(_, true) => lint_true(false),
-                    AssertKind::WithMessage(panic_message, false) => lint_false_with_message(panic_message),
-                };
-            }
-        }
-    }
-}
-
-/// Result of calling `match_assert_with_message`.
-enum AssertKind {
-    WithMessage(String, bool),
-    WithoutMessage(bool),
-}
-
-/// Check if the expression matches
-///
-/// ```rust,ignore
-/// if !c {
-///   {
-///     ::std::rt::begin_panic(message, _)
-///   }
-/// }
-/// ```
-///
-/// where `message` is any expression and `c` is a constant bool.
-fn match_assert_with_message<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<AssertKind> {
-    if_chain! {
-        if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr);
-        if let ExprKind::Unary(UnOp::Not, expr) = cond.kind;
-        // bind the first argument of the `assert!` macro
-        if let Some((Constant::Bool(is_true), _)) = constant(cx, cx.typeck_results(), expr);
-        let begin_panic_call = peel_blocks(then);
-        // function call
-        if let Some(arg) = match_panic_call(cx, begin_panic_call);
-        // bind the second argument of the `assert!` macro if it exists
-        if let panic_message = snippet_opt(cx, arg.span);
-        // second argument of begin_panic is irrelevant
-        // as is the second match arm
-        then {
-            // an empty message occurs when it was generated by the macro
-            // (and not passed by the user)
-            return panic_message
-                .filter(|msg| !msg.is_empty())
-                .map(|msg| AssertKind::WithMessage(msg, is_true))
-                .or(Some(AssertKind::WithoutMessage(is_true)));
         }
     }
-    None
 }
index 0629674307ba77dd86ad61b4f042a1a726cdf8dd..a58d12ddd6b4372278e4569126f2233d81183e28 100644 (file)
@@ -1,9 +1,10 @@
 //! checks for attributes
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::macros::{is_panic, macro_backtrace};
 use clippy_utils::msrvs;
 use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
-use clippy_utils::{extract_msrv_attr, match_panic_def_id, meets_msrv};
+use clippy_utils::{extract_msrv_attr, meets_msrv};
 use if_chain::if_chain;
 use rustc_ast::{AttrKind, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem};
 use rustc_errors::Applicability;
@@ -443,20 +444,15 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_
 }
 
 fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool {
+    if macro_backtrace(expr.span).last().map_or(false, |macro_call| {
+        is_panic(cx, macro_call.def_id) || cx.tcx.item_name(macro_call.def_id) == sym::unreachable
+    }) {
+        return false;
+    }
     match &expr.kind {
         ExprKind::Block(block, _) => is_relevant_block(cx, typeck_results, block),
         ExprKind::Ret(Some(e)) => is_relevant_expr(cx, typeck_results, e),
         ExprKind::Ret(None) | ExprKind::Break(_, None) => false,
-        ExprKind::Call(path_expr, _) => {
-            if let ExprKind::Path(qpath) = &path_expr.kind {
-                typeck_results
-                    .qpath_res(qpath, path_expr.hir_id)
-                    .opt_def_id()
-                    .map_or(true, |fun_id| !match_panic_def_id(cx, fun_id))
-            } else {
-                true
-            }
-        },
         _ => true,
     }
 }
index d0b8c52a36a92e9891c33dd1bee45e7ef6fab7b5..c50e214be288dd4a9389ad67d254bd9be3153a67 100644 (file)
@@ -1,4 +1,5 @@
-use clippy_utils::{diagnostics::span_lint_and_sugg, higher, is_direct_expn_of, ty::implements_trait};
+use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
+use clippy_utils::{diagnostics::span_lint_and_sugg, ty::implements_trait};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, Lit};
@@ -41,7 +42,7 @@ fn is_bool_lit(e: &Expr<'_>) -> bool {
     ) && !e.span.from_expansion()
 }
 
-fn is_impl_not_trait_with_bool_out(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
+fn is_impl_not_trait_with_bool_out(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(e);
 
     cx.tcx
@@ -66,44 +67,40 @@ fn is_impl_not_trait_with_bool_out(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
 
 impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let macros = ["assert_eq", "debug_assert_eq"];
-        let inverted_macros = ["assert_ne", "debug_assert_ne"];
-
-        for mac in macros.iter().chain(inverted_macros.iter()) {
-            if let Some(span) = is_direct_expn_of(expr.span, mac) {
-                if let Some(args) = higher::extract_assert_macro_args(expr) {
-                    if let [a, b, ..] = args[..] {
-                        let nb_bool_args = usize::from(is_bool_lit(a)) + usize::from(is_bool_lit(b));
-
-                        if nb_bool_args != 1 {
-                            // If there are two boolean arguments, we definitely don't understand
-                            // what's going on, so better leave things as is...
-                            //
-                            // Or there is simply no boolean and then we can leave things as is!
-                            return;
-                        }
-
-                        if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) {
-                            // At this point the expression which is not a boolean
-                            // literal does not implement Not trait with a bool output,
-                            // so we cannot suggest to rewrite our code
-                            return;
-                        }
+        let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+        let macro_name = cx.tcx.item_name(macro_call.def_id);
+        if !matches!(
+            macro_name.as_str(),
+            "assert_eq" | "debug_assert_eq" | "assert_ne" | "debug_assert_ne"
+        ) {
+            return;
+        }
+        let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
+        if !(is_bool_lit(a) ^ is_bool_lit(b)) {
+            // If there are two boolean arguments, we definitely don't understand
+            // what's going on, so better leave things as is...
+            //
+            // Or there is simply no boolean and then we can leave things as is!
+            return;
+        }
 
-                        let non_eq_mac = &mac[..mac.len() - 3];
-                        span_lint_and_sugg(
-                            cx,
-                            BOOL_ASSERT_COMPARISON,
-                            span,
-                            &format!("used `{}!` with a literal bool", mac),
-                            "replace it with",
-                            format!("{}!(..)", non_eq_mac),
-                            Applicability::MaybeIncorrect,
-                        );
-                        return;
-                    }
-                }
-            }
+        if !is_impl_not_trait_with_bool_out(cx, a) || !is_impl_not_trait_with_bool_out(cx, b) {
+            // At this point the expression which is not a boolean
+            // literal does not implement Not trait with a bool output,
+            // so we cannot suggest to rewrite our code
+            return;
         }
+
+        let macro_name = macro_name.as_str();
+        let non_eq_mac = &macro_name[..macro_name.len() - 3];
+        span_lint_and_sugg(
+            cx,
+            BOOL_ASSERT_COMPARISON,
+            macro_call.span,
+            &format!("used `{}!` with a literal bool", macro_name),
+            "replace it with",
+            format!("{}!(..)", non_eq_mac),
+            Applicability::MaybeIncorrect,
+        );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
new file mode 100644 (file)
index 0000000..b8f5217
--- /dev/null
@@ -0,0 +1,97 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_no_std_crate;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{meets_msrv, msrvs};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for the usage of `&expr as *const T` or
+    /// `&mut expr as *mut T`, and suggest using `ptr::addr_of` or
+    /// `ptr::addr_of_mut` instead.
+    ///
+    /// ### Why is this bad?
+    /// This would improve readability and avoid creating a reference
+    /// that points to an uninitialized value or unaligned place.
+    /// Read the `ptr::addr_of` docs for more information.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let val = 1;
+    /// let p = &val as *const i32;
+    ///
+    /// let mut val_mut = 1;
+    /// let p_mut = &mut val_mut as *mut i32;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let val = 1;
+    /// let p = std::ptr::addr_of!(val);
+    ///
+    /// let mut val_mut = 1;
+    /// let p_mut = std::ptr::addr_of_mut!(val_mut);
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub BORROW_AS_PTR,
+    pedantic,
+    "borrowing just to cast to a raw pointer"
+}
+
+impl_lint_pass!(BorrowAsPtr => [BORROW_AS_PTR]);
+
+pub struct BorrowAsPtr {
+    msrv: Option<RustcVersion>,
+}
+
+impl BorrowAsPtr {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if !meets_msrv(self.msrv.as_ref(), &msrvs::BORROW_AS_PTR) {
+            return;
+        }
+
+        if expr.span.from_expansion() {
+            return;
+        }
+
+        if_chain! {
+            if let ExprKind::Cast(left_expr, ty) = &expr.kind;
+            if let TyKind::Ptr(_) = ty.kind;
+            if let ExprKind::AddrOf(BorrowKind::Ref, mutability, e) = &left_expr.kind;
+
+            then {
+                let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
+                let macro_name = match mutability {
+                    Mutability::Not => "addr_of",
+                    Mutability::Mut => "addr_of_mut",
+                };
+
+                span_lint_and_sugg(
+                    cx,
+                    BORROW_AS_PTR,
+                    expr.span,
+                    "borrow as raw pointer",
+                    "try",
+                    format!(
+                        "{}::ptr::{}!({})",
+                        core_or_std,
+                        macro_name,
+                        snippet_opt(cx, e.span).unwrap()
+                    ),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
index 3f286dd9e2fca893b849ce17450b909caf4d3d02..e8f39cd37090d2f14fd64fedb0ae629ae19eb942 100644 (file)
@@ -67,7 +67,7 @@ fn check_case_sensitive_file_extension_comparison(ctx: &LateContext<'_>, expr: &
     None
 }
 
-impl LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons {
+impl<'tcx> LateLintPass<'tcx> for CaseSensitiveFileExtensionComparisons {
     fn check_expr(&mut self, ctx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let Some(span) = check_case_sensitive_file_extension_comparison(ctx, expr) {
             span_lint_and_help(
index 248b35b024ee1aa8a7a0b9f520c3ceab1b86f86f..b9de5510455b9e7bdb3351b8e61c7bf27514d990 100644 (file)
@@ -9,7 +9,7 @@
 
 use super::CAST_PTR_ALIGNMENT;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if let ExprKind::Cast(cast_expr, cast_to) = expr.kind {
         if is_hir_ty_cfg_dependant(cx, cast_to) {
             return;
index d9bf1ea58b97bb8a49ad3ed0588b0ec3c0175146..15f2f81f4079e5b2e88b66809e797f845249c3d1 100644 (file)
@@ -6,7 +6,7 @@
 
 use super::CAST_REF_TO_MUT;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
         if let ExprKind::Unary(UnOp::Deref, e) = &expr.kind;
         if let ExprKind::Cast(e, t) = &e.kind;
index 099a0de881ff0fb27eb868631b3742304bd424c0..7cc406018dbe0ab7c3395959899a63567c1a8c33 100644 (file)
@@ -9,7 +9,7 @@
 
 use super::CHAR_LIT_AS_U8;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if_chain! {
         if let ExprKind::Cast(e, _) = &expr.kind;
         if let ExprKind::Lit(l) = &e.kind;
index 3132d3a5cf0976d7dece539347c09c9f61832871..fb04f93fbcf9774190153ab78751a369d15a3408 100644 (file)
@@ -12,7 +12,7 @@
 
 use super::PTR_AS_PTR;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: &Option<RustcVersion>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Option<RustcVersion>) {
     if !meets_msrv(msrv.as_ref(), &msrvs::POINTER_CAST) {
         return;
     }
index d07bc23235b0f37bdadf0811097775129c8e3802..73ce656ad151437d490bf435e525c9d8c1797258 100644 (file)
@@ -316,7 +316,7 @@ struct BlockEqual {
 
 /// This function can also trigger the `IF_SAME_THEN_ELSE` in which case it'll return `None` to
 /// abort any further processing and avoid duplicate lint triggers.
-fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option<BlockEqual> {
+fn scan_block_for_eq(cx: &LateContext<'_>, blocks: &[&Block<'_>]) -> Option<BlockEqual> {
     let mut start_eq = usize::MAX;
     let mut end_eq = usize::MAX;
     let mut expr_eq = true;
@@ -385,11 +385,7 @@ fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option<
     })
 }
 
-fn check_for_warn_of_moved_symbol(
-    cx: &LateContext<'tcx>,
-    symbols: &FxHashSet<Symbol>,
-    if_expr: &'tcx Expr<'_>,
-) -> bool {
+fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &FxHashSet<Symbol>, if_expr: &Expr<'_>) -> bool {
     get_enclosing_block(cx, if_expr.hir_id).map_or(false, |block| {
         let ignore_span = block.span.shrink_to_lo().to(if_expr.span);
 
@@ -419,13 +415,13 @@ fn check_for_warn_of_moved_symbol(
 }
 
 fn emit_branches_sharing_code_lint(
-    cx: &LateContext<'tcx>,
+    cx: &LateContext<'_>,
     start_stmts: usize,
     end_stmts: usize,
     lint_end: bool,
     warn_about_moved_symbol: bool,
-    blocks: &[&Block<'tcx>],
-    if_expr: &'tcx Expr<'_>,
+    blocks: &[&Block<'_>],
+    if_expr: &Expr<'_>,
 ) {
     if start_stmts == 0 && !lint_end {
         return;
index a0b137efe221a3bc8113a2936403bbce99f9b874..3070588483c21b33d97fc3ab305cce090b096c0f 100644 (file)
@@ -77,7 +77,7 @@ pub struct Default {
 
 impl_lint_pass!(Default => [DEFAULT_TRAIT_ACCESS, FIELD_REASSIGN_WITH_DEFAULT]);
 
-impl LateLintPass<'_> for Default {
+impl<'tcx> LateLintPass<'tcx> for Default {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if !expr.span.from_expansion();
@@ -110,7 +110,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     }
 
     #[allow(clippy::too_many_lines)]
-    fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
         // start from the `let mut _ = _::default();` and look at all the following
         // statements, see if they re-assign the fields of the binding
         let stmts_head = match block.stmts {
@@ -198,7 +198,7 @@ fn check_block<'tcx>(&mut self, cx: &LateContext<'tcx>, block: &Block<'tcx>) {
                 let ext_with_default = !variant
                     .fields
                     .iter()
-                    .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.ident.name));
+                    .all(|field| assigned_fields.iter().any(|(a, _)| a == &field.name));
 
                 let field_list = assigned_fields
                     .into_iter()
index 3573ea5f02671becbce4b4f1ddd00559fe9c84c9..66b5f49817d8daed5ddd1b235b366553581c85a9 100644 (file)
@@ -54,7 +54,7 @@
 
 declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
 
-impl LateLintPass<'_> for DefaultNumericFallback {
+impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback {
     fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
         let mut visitor = NumericFallbackVisitor::new(cx);
         visitor.visit_body(body);
@@ -161,7 +161,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                                 fields_def
                                     .iter()
                                     .find_map(|f_def| {
-                                        if f_def.ident == field.ident
+                                        if f_def.ident(self.cx.tcx) == field.ident
                                             { Some(self.cx.tcx.type_of(f_def.did)) }
                                         else { None }
                                     });
index fa2b348591be4d7a0118095a99734f9297f60900..bf077a212fd0fcfadc1a78b6f9dfbd86af1a1e59 100644 (file)
@@ -355,7 +355,7 @@ fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
     }
 }
 
-fn try_parse_ref_op(
+fn try_parse_ref_op<'tcx>(
     tcx: TyCtxt<'tcx>,
     typeck: &'tcx TypeckResults<'_>,
     expr: &'tcx Expr<'_>,
@@ -387,7 +387,7 @@ fn try_parse_ref_op(
 
 // Checks whether the type for a deref call actually changed the type, not just the mutability of
 // the reference.
-fn deref_method_same_type(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
+fn deref_method_same_type(result_ty: Ty<'_>, arg_ty: Ty<'_>) -> bool {
     match (result_ty.kind(), arg_ty.kind()) {
         (ty::Ref(_, result_ty, _), ty::Ref(_, arg_ty, _)) => TyS::same_type(result_ty, arg_ty),
 
@@ -457,7 +457,7 @@ fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId,
 }
 
 /// Adjustments are sometimes made in the parent block rather than the expression itself.
-fn find_adjustments(
+fn find_adjustments<'tcx>(
     tcx: TyCtxt<'tcx>,
     typeck: &'tcx TypeckResults<'_>,
     expr: &'tcx Expr<'_>,
@@ -499,7 +499,7 @@ fn find_adjustments(
 }
 
 #[allow(clippy::needless_pass_by_value)]
-fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: StateData) {
+fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData) {
     match state {
         State::DerefMethod {
             ty_changed_count,
@@ -568,7 +568,7 @@ fn report(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data: Stat
 }
 
 impl Dereferencing {
-    fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) {
+    fn check_local_usage(&mut self, cx: &LateContext<'_>, e: &Expr<'_>, local: HirId) {
         if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
             if let Some(pat) = outer_pat {
                 // Check for auto-deref
index 6d4065907fb458da5ca256d4e1d0e22e9c20d6ab..73c00d97020bedf2a6badb9b698b89a59ce9b4de 100644 (file)
@@ -11,6 +11,9 @@
     /// ### What it does
     /// Denies the configured methods and functions in clippy.toml
     ///
+    /// Note: Even though this lint is warn-by-default, it will only trigger if
+    /// methods are defined in the clippy.toml file.
+    ///
     /// ### Why is this bad?
     /// Some methods are undesirable in certain contexts, and it's beneficial to
     /// lint for them as needed.
     /// ```
     #[clippy::version = "1.49.0"]
     pub DISALLOWED_METHODS,
-    nursery,
+    style,
     "use of a disallowed method call"
 }
 
 #[derive(Clone, Debug)]
 pub struct DisallowedMethods {
     conf_disallowed: Vec<conf::DisallowedMethod>,
-    disallowed: DefIdMap<Option<String>>,
+    disallowed: DefIdMap<usize>,
 }
 
 impl DisallowedMethods {
@@ -72,17 +75,10 @@ pub fn new(conf_disallowed: Vec<conf::DisallowedMethod>) -> Self {
 
 impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
     fn check_crate(&mut self, cx: &LateContext<'_>) {
-        for conf in &self.conf_disallowed {
-            let (path, reason) = match conf {
-                conf::DisallowedMethod::Simple(path) => (path, None),
-                conf::DisallowedMethod::WithReason { path, reason } => (
-                    path,
-                    reason.as_ref().map(|reason| format!("{} (from clippy.toml)", reason)),
-                ),
-            };
-            let segs: Vec<_> = path.split("::").collect();
+        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) {
-                self.disallowed.insert(id, reason);
+                self.disallowed.insert(id, index);
             }
         }
     }
@@ -92,15 +88,17 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             Some(def_id) => def_id,
             None => return,
         };
-        let reason = match self.disallowed.get(&def_id) {
-            Some(reason) => reason,
+        let conf = match self.disallowed.get(&def_id) {
+            Some(&index) => &self.conf_disallowed[index],
             None => return,
         };
-        let func_path = cx.tcx.def_path_str(def_id);
-        let msg = format!("use of a disallowed method `{}`", func_path);
+        let msg = format!("use of a disallowed method `{}`", conf.path());
         span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, &msg, |diag| {
-            if let Some(reason) = reason {
-                diag.note(reason);
+            if let conf::DisallowedMethod::WithReason {
+                reason: Some(reason), ..
+            } = conf
+            {
+                diag.note(&format!("{} (from clippy.toml)", reason));
             }
         });
     }
index eaed40327136f75636b013e37ee400b7a9318790..ea4b49b46fe9f6d6e5ca9e6f7e8ee6d3e8f4112b 100644 (file)
@@ -14,6 +14,9 @@
     /// ### What it does
     /// Denies the configured types in clippy.toml.
     ///
+    /// Note: Even though this lint is warn-by-default, it will only trigger if
+    /// types are defined in the clippy.toml file.
+    ///
     /// ### Why is this bad?
     /// Some types are undesirable in certain contexts.
     ///
@@ -44,7 +47,7 @@
     /// ```
     #[clippy::version = "1.55.0"]
     pub DISALLOWED_TYPES,
-    nursery,
+    style,
     "use of disallowed types"
 }
 #[derive(Clone, Debug)]
index 7c2717733578b65de8045664eef9ba6482b93a75..cb7d5ac73941a1712af8b28984857780f8edf812 100644 (file)
@@ -1,8 +1,9 @@
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_note, span_lint_and_then};
+use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use clippy_utils::source::{first_line_of_span, snippet_with_applicability};
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
-use clippy_utils::{is_entrypoint_fn, is_expn_of, match_panic_def_id, method_chain_args, return_ty};
+use clippy_utils::{is_entrypoint_fn, method_chain_args, return_ty};
 use if_chain::if_chain;
 use itertools::Itertools;
 use rustc_ast::ast::{Async, AttrKind, Attribute, Fn, FnRetTy, ItemKind};
@@ -13,7 +14,7 @@
 use rustc_errors::{Applicability, Handler, SuggestionStyle};
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::{AnonConst, Expr, ExprKind, QPath};
+use rustc_hir::{AnonConst, Expr};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
@@ -805,24 +806,17 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             return;
         }
 
-        // check for `begin_panic`
-        if_chain! {
-            if let ExprKind::Call(func_expr, _) = expr.kind;
-            if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
-            if let Some(path_def_id) = path.res.opt_def_id();
-            if match_panic_def_id(self.cx, path_def_id);
-            if is_expn_of(expr.span, "unreachable").is_none();
-            if !is_expn_of_debug_assertions(expr.span);
-            then {
-                self.panic_span = Some(expr.span);
+        if let Some(macro_call) = root_macro_call_first_node(self.cx, expr) {
+            if is_panic(self.cx, macro_call.def_id)
+                || matches!(
+                    self.cx.tcx.item_name(macro_call.def_id).as_str(),
+                    "assert" | "assert_eq" | "assert_ne" | "todo"
+                )
+            {
+                self.panic_span = Some(macro_call.span);
             }
         }
 
-        // check for `assert_eq` or `assert_ne`
-        if is_expn_of(expr.span, "assert_eq").is_some() || is_expn_of(expr.span, "assert_ne").is_some() {
-            self.panic_span = Some(expr.span);
-        }
-
         // check for `unwrap`
         if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
             let receiver_ty = self.typeck_results.expr_ty(&arglists[0][0]).peel_refs();
@@ -844,8 +838,3 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
         NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
     }
 }
-
-fn is_expn_of_debug_assertions(span: Span) -> bool {
-    const MACRO_NAMES: &[&str] = &["debug_assert", "debug_assert_eq", "debug_assert_ne"];
-    MACRO_NAMES.iter().any(|name| is_expn_of(span, name).is_some())
-}
index 3d92eb16870e3d88c8d9460507d4b15cb20c4236..3ce239273e2529cd3f10d875493b54468e76771f 100644 (file)
@@ -233,7 +233,7 @@ struct ContainsExpr<'tcx> {
     key: &'tcx Expr<'tcx>,
     call_ctxt: SyntaxContext,
 }
-fn try_parse_contains(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(MapType, ContainsExpr<'tcx>)> {
+fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(MapType, ContainsExpr<'tcx>)> {
     let mut negated = false;
     let expr = peel_hir_expr_while(expr, |e| match e.kind {
         ExprKind::Unary(UnOp::Not, e) => {
@@ -280,7 +280,7 @@ struct InsertExpr<'tcx> {
     key: &'tcx Expr<'tcx>,
     value: &'tcx Expr<'tcx>,
 }
-fn try_parse_insert(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
+fn try_parse_insert<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<InsertExpr<'tcx>> {
     if let ExprKind::MethodCall(_, _, [map, key, value], _) = expr.kind {
         let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
         if match_def_path(cx, id, &paths::BTREEMAP_INSERT) || match_def_path(cx, id, &paths::HASHMAP_INSERT) {
@@ -301,7 +301,7 @@ enum Edit<'tcx> {
     /// An insertion into the map.
     Insertion(Insertion<'tcx>),
 }
-impl Edit<'tcx> {
+impl<'tcx> Edit<'tcx> {
     fn as_insertion(self) -> Option<Insertion<'tcx>> {
         if let Self::Insertion(i) = self { Some(i) } else { None }
     }
@@ -532,7 +532,7 @@ struct InsertSearchResults<'tcx> {
     allow_insert_closure: bool,
     is_single_insert: bool,
 }
-impl InsertSearchResults<'tcx> {
+impl<'tcx> InsertSearchResults<'tcx> {
     fn as_single_insertion(&self) -> Option<Insertion<'tcx>> {
         self.is_single_insert.then(|| self.edits[0].as_insertion().unwrap())
     }
@@ -633,7 +633,7 @@ fn snippet_closure(&self, cx: &LateContext<'_>, mut span: Span, app: &mut Applic
     }
 }
 
-fn find_insert_calls(
+fn find_insert_calls<'tcx>(
     cx: &LateContext<'tcx>,
     contains_expr: &ContainsExpr<'tcx>,
     expr: &'tcx Expr<'_>,
index 101234605273393b13d7754d8ff28e0e1ee37725..df75b815436b896bd20160303ebe983d8a79b5d0 100644 (file)
@@ -1,10 +1,11 @@
 use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then};
+use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, higher, is_expn_of, is_in_test_function};
+use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, StmtKind};
+use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 
 declare_lint_pass!(EqOp => [EQ_OP, OP_REF]);
 
-const ASSERT_MACRO_NAMES: [&str; 4] = ["assert_eq", "assert_ne", "debug_assert_eq", "debug_assert_ne"];
-
 impl<'tcx> LateLintPass<'tcx> for EqOp {
     #[allow(clippy::similar_names, clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Block(block, _) = e.kind {
-            for stmt in block.stmts {
-                for amn in &ASSERT_MACRO_NAMES {
-                    if_chain! {
-                        if is_expn_of(stmt.span, amn).is_some();
-                        if let StmtKind::Semi(matchexpr) = stmt.kind;
-                        if let Some(macro_args) = higher::extract_assert_macro_args(matchexpr);
-                        if macro_args.len() == 2;
-                        let (lhs, rhs) = (macro_args[0], macro_args[1]);
-                        if eq_expr_value(cx, lhs, rhs);
-                        if !is_in_test_function(cx.tcx, e.hir_id);
-                        then {
-                            span_lint(
-                                cx,
-                                EQ_OP,
-                                lhs.span.to(rhs.span),
-                                &format!("identical args used in this `{}!` macro call", amn),
-                            );
-                        }
-                    }
-                }
+        if_chain! {
+            if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| {
+                let name = cx.tcx.item_name(macro_call.def_id);
+                matches!(name.as_str(), "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne")
+                    .then(|| (macro_call, name))
+            });
+            if let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn);
+            if eq_expr_value(cx, lhs, rhs);
+            if macro_call.is_local();
+            if !is_in_test_function(cx.tcx, e.hir_id);
+            then {
+                span_lint(
+                    cx,
+                    EQ_OP,
+                    lhs.span.to(rhs.span),
+                    &format!("identical args used in this `{}!` macro call", macro_name),
+                );
             }
         }
         if let ExprKind::Binary(op, left, right) = e.kind {
index 06d128f5527b5d8ba3d965b65853c1a0507cf153..cf47e581ccb48f26166502236527f0004983f6b2 100644 (file)
@@ -56,7 +56,7 @@ fn array_rec(pats: &[Pat<'_>]) -> bool {
     }
 }
 
-fn is_structural_partial_eq(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool {
+fn is_structural_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'tcx>) -> bool {
     if let Some(def_id) = cx.tcx.lang_items().eq_trait() {
         implements_trait(cx, ty, def_id, &[other.into()])
     } else {
index d49cec26be5f02c6933c72e50227b5c8501b05ad..c1a84973c42114945130d4c5e9fbeeba75042efd 100644 (file)
@@ -1,9 +1,11 @@
 use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::ty::same_type_and_consts;
+
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TypeckResults;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -35,24 +37,40 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             return;
         }
         if let ExprKind::Binary(ref cmp, left, right) = e.kind {
+            let tck = cx.typeck_results();
             match cmp.node {
                 BinOpKind::Mul | BinOpKind::BitAnd => {
-                    check(cx, left, e.span);
-                    check(cx, right, e.span);
+                    check(cx, tck, left, right, e);
+                    check(cx, tck, right, left, e);
                 },
-                BinOpKind::Div => check(cx, left, e.span),
+                BinOpKind::Div => check(cx, tck, left, right, e),
                 _ => (),
             }
         }
     }
 }
 
-fn check(cx: &LateContext<'_>, e: &Expr<'_>, span: Span) {
-    if constant_simple(cx, cx.typeck_results(), e) == Some(Constant::Int(0)) {
+fn different_types(tck: &TypeckResults<'_>, input: &Expr<'_>, output: &Expr<'_>) -> bool {
+    let input_ty = tck.expr_ty(input).peel_refs();
+    let output_ty = tck.expr_ty(output).peel_refs();
+    !same_type_and_consts(input_ty, output_ty)
+}
+
+fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    tck: &TypeckResults<'tcx>,
+    op: &Expr<'tcx>,
+    other: &Expr<'tcx>,
+    parent: &Expr<'tcx>,
+) {
+    if constant_simple(cx, tck, op) == Some(Constant::Int(0)) {
+        if different_types(tck, other, parent) {
+            return;
+        }
         span_lint(
             cx,
             ERASING_OP,
-            span,
+            parent.span,
             "this operation will always return zero. This is likely not the intended outcome",
         );
     }
index bc5d2f6278dee7e9c05fd58ce40fc0b80b7d16af..af591dd71aa1d37d383570065195df3d6b637821 100644 (file)
@@ -77,7 +77,7 @@ fn check_fn(
         }
 
         let parent_id = cx.tcx.hir().get_parent_item(hir_id);
-        let parent_node = cx.tcx.hir().find(parent_id);
+        let parent_node = cx.tcx.hir().find_by_def_id(parent_id);
 
         let mut trait_self_ty = None;
         if let Some(Node::Item(item)) = parent_node {
@@ -175,8 +175,7 @@ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
                 // skip if there is a `self` parameter binding to a type
                 // that contains `Self` (i.e.: `self: Box<Self>`), see #4804
                 if let Some(trait_self_ty) = self.trait_self_ty {
-                    if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(self.cx.tcx, cmt.place.ty(), trait_self_ty)
-                    {
+                    if map.name(cmt.hir_id) == kw::SelfLower && contains_ty(cmt.place.ty(), trait_self_ty) {
                         return;
                     }
                 }
index 5a4b424710440f03b947c4b03cabb337839df59d..b22515a39079a2518ece04f75e10d3601e235fc2 100644 (file)
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::higher::VecArgs;
 use clippy_utils::source::snippet_opt;
+use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::usage::local_used_after_expr;
 use clippy_utils::{get_enclosing_loop_or_closure, higher, path_to_local, path_to_local_id};
 use if_chain::if_chain;
@@ -12,6 +13,7 @@
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::{self, ClosureKind, Ty, TypeFoldable};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -113,6 +115,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             // A type param function ref like `T::f` is not 'static, however
             // it is if cast like `T::f as fn()`. This seems like a rustc bug.
             if !substs.types().any(|t| matches!(t.kind(), ty::Param(_)));
+            let callee_ty_unadjusted = cx.typeck_results().expr_ty(callee).peel_refs();
+            if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Arc);
+            if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Rc);
             then {
                 span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
                     if let Some(mut snippet) = snippet_opt(cx, callee.span) {
index d64cc61916c5eb4cf0bf00314253cc8b229d4b97..cbf52d19334c0f79a15a7fdc4b876dcca6d973b5 100644 (file)
@@ -34,11 +34,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
             if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::EXIT);
             let parent = cx.tcx.hir().get_parent_item(e.hir_id);
-            if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find(parent);
+            if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent);
             // If the next item up is a function we check if it is an entry point
             // and only then emit a linter warning
-            let def_id = cx.tcx.hir().local_def_id(parent);
-            if !is_entrypoint_fn(cx, def_id.to_def_id());
+            if !is_entrypoint_fn(cx, parent.to_def_id());
             then {
                 span_lint(cx, EXIT, e.span, "usage of `process::exit`");
             }
index 6b327b9ce1720aeb1fbde29b499fb174f8a393e5..98e5234e0aa94640a928d5eff4814b8c9a465307 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
-use clippy_utils::higher::FormatArgsExpn;
+use clippy_utils::macros::FormatArgsExpn;
 use clippy_utils::{is_expn_of, match_function_call, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -48,7 +48,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
             } else {
                 None
             };
-            if let Some(format_args) = FormatArgsExpn::parse(write_arg);
+            if let Some(format_args) = FormatArgsExpn::parse(cx, write_arg);
             then {
                 let calling_macro =
                     // ordering is important here, since `writeln!` uses `write!` internally
@@ -80,7 +80,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                     )
                 };
                 let msg = format!("use of `{}.unwrap()`", used);
-                if let [write_output] = *format_args.format_string_symbols {
+                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();
index 05d300058cf4f270ca6e9713c40deb1bbe7b1e8a..02f1baf27fae81cc184cf64a5fdfe723d70c84cc 100644 (file)
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::{is_panic, root_macro_call_first_node};
+use clippy_utils::method_chain_args;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_expn_of, match_panic_def_id, method_chain_args};
 use if_chain::if_chain;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -68,7 +69,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
 
 fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_items: &[hir::ImplItemRef]) {
     use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-    use rustc_hir::{Expr, ExprKind, ImplItemKind, QPath};
+    use rustc_hir::{Expr, ImplItemKind};
 
     struct FindPanicUnwrap<'a, 'tcx> {
         lcx: &'a LateContext<'tcx>,
@@ -80,14 +81,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
         type Map = Map<'tcx>;
 
         fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
-            // check for `begin_panic`
-            if_chain! {
-                if let ExprKind::Call(func_expr, _) = expr.kind;
-                if let ExprKind::Path(QPath::Resolved(_, path)) = func_expr.kind;
-                if let Some(path_def_id) = path.res.opt_def_id();
-                if match_panic_def_id(self.lcx, path_def_id);
-                if is_expn_of(expr.span, "unreachable").is_none();
-                then {
+            if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) {
+                if is_panic(self.lcx, macro_call.def_id) {
                     self.result.push(expr.span);
                 }
             }
index 3f043e5f2f1c55be2ec3b1833297bfb76e8d547b..688d8f8630f3fa38b84e55dd4489309b62ba2f73 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::FormatExpn;
+use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
 use clippy_utils::source::{snippet_opt, snippet_with_applicability};
 use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
 
 impl<'tcx> LateLintPass<'tcx> for UselessFormat {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let FormatExpn { call_site, format_args } = match FormatExpn::parse(expr) {
-            Some(e) if !e.call_site.from_expansion() => e,
-            _ => return,
+        let (format_args, call_site) = if_chain! {
+            if let Some(macro_call) = root_macro_call_first_node(cx, expr);
+            if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id);
+            if let Some(format_args) = FormatArgsExpn::find_nested(cx, expr, macro_call.expn);
+            then {
+                (format_args, macro_call.span)
+            } else {
+                return
+            }
         };
 
         let mut applicability = Applicability::MachineApplicable;
         if format_args.value_args.is_empty() {
-            if format_args.format_string_parts.is_empty() {
-                span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability);
-            } else {
-                if_chain! {
-                    if let [e] = &*format_args.format_string_parts;
-                    if let ExprKind::Lit(lit) = &e.kind;
-                    if let Some(s_src) = snippet_opt(cx, lit.span);
-                    then {
+            match *format_args.format_string_parts {
+                [] => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
+                [_] => {
+                    if let Some(s_src) = snippet_opt(cx, format_args.format_string_span) {
                         // Simulate macro expansion, converting {{ and }} to { and }.
                         let s_expand = s_src.replace("{{", "{").replace("}}", "}");
                         let sugg = format!("{}.to_string()", s_expand);
                         span_useless_format(cx, call_site, sugg, applicability);
                     }
-                }
+                },
+                [..] => {},
             }
         } else if let [value] = *format_args.value_args {
             if_chain! {
-                if format_args.format_string_symbols == [kw::Empty];
+                if format_args.format_string_parts == [kw::Empty];
                 if match cx.typeck_results().expr_ty(value).peel_refs().kind() {
                     ty::Adt(adt, _) => cx.tcx.is_diagnostic_item(sym::String, adt.did),
                     ty::Str => true,
                     _ => false,
                 };
                 if let Some(args) = format_args.args();
-                if args.iter().all(|arg| arg.is_display() && !arg.has_string_formatting());
+                if args.iter().all(|arg| arg.format_trait == sym::Display && !arg.has_string_formatting());
                 then {
                     let is_new_string = match value.kind {
                         ExprKind::Binary(..) => true,
index f0e1a67dcddb93d852d21eeae72b812be8280dbe..ae423d799d71a3defb511ef01a02e13c1ea84241 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::higher::{FormatArgsArg, FormatArgsExpn, FormatExpn};
+use clippy_utils::macros::{FormatArgsArg, FormatArgsExpn};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::{is_diag_trait_item, match_def_path, paths};
@@ -83,7 +83,7 @@
 impl<'tcx> LateLintPass<'tcx> for FormatArgs {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if_chain! {
-            if let Some(format_args) = FormatArgsExpn::parse(expr);
+            if let Some(format_args) = FormatArgsExpn::parse(cx, expr);
             let expr_expn_data = expr.span.ctxt().outer_expn_data();
             let outermost_expn_data = outermost_expn_data(expr_expn_data);
             if let Some(macro_def_id) = outermost_expn_data.macro_def_id;
@@ -97,7 +97,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
             if let Some(args) = format_args.args();
             then {
                 for (i, arg) in args.iter().enumerate() {
-                    if !arg.is_display() {
+                    if arg.format_trait != sym::Display {
                         continue;
                     }
                     if arg.has_string_formatting() {
@@ -106,8 +106,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
                     if is_aliased(&args, i) {
                         continue;
                     }
-                    check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg);
-                    check_to_string_in_format_args(cx, name, arg);
+                    check_format_in_format_args(cx, outermost_expn_data.call_site, name, arg.value);
+                    check_to_string_in_format_args(cx, name, arg.value);
                 }
             }
         }
@@ -122,30 +122,31 @@ fn outermost_expn_data(expn_data: ExpnData) -> ExpnData {
     }
 }
 
-fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &FormatArgsArg<'_>) {
-    if_chain! {
-        if FormatExpn::parse(arg.value).is_some();
-        if !arg.value.span.ctxt().outer_expn_data().call_site.from_expansion();
-        then {
-            span_lint_and_then(
-                cx,
-                FORMAT_IN_FORMAT_ARGS,
-                call_site,
-                &format!("`format!` in `{}!` args", name),
-                |diag| {
-                    diag.help(&format!(
-                        "combine the `format!(..)` arguments with the outer `{}!(..)` call",
-                        name
-                    ));
-                    diag.help("or consider changing `format!` to `format_args!`");
-                },
-            );
-        }
+fn check_format_in_format_args(cx: &LateContext<'_>, call_site: Span, name: Symbol, arg: &Expr<'_>) {
+    let expn_data = arg.span.ctxt().outer_expn_data();
+    if expn_data.call_site.from_expansion() {
+        return;
+    }
+    let Some(mac_id) = expn_data.macro_def_id else { return };
+    if !cx.tcx.is_diagnostic_item(sym::format_macro, mac_id) {
+        return;
     }
+    span_lint_and_then(
+        cx,
+        FORMAT_IN_FORMAT_ARGS,
+        call_site,
+        &format!("`format!` in `{}!` args", name),
+        |diag| {
+            diag.help(&format!(
+                "combine the `format!(..)` arguments with the outer `{}!(..)` call",
+                name
+            ));
+            diag.help("or consider changing `format!` to `format_args!`");
+        },
+    );
 }
 
-fn check_to_string_in_format_args<'tcx>(cx: &LateContext<'tcx>, name: Symbol, arg: &FormatArgsArg<'tcx>) {
-    let value = arg.value;
+fn check_to_string_in_format_args(cx: &LateContext<'_>, name: Symbol, value: &Expr<'_>) {
     if_chain! {
         if !value.span.from_expansion();
         if let ExprKind::MethodCall(_, _, [receiver], _) = value.kind;
index 866ff216f84a21df3dc04355760f8d8e4a11e40b..5ece2cc5ac4f7dd3b509a1dc262b5b1df53f5eae 100644 (file)
@@ -53,7 +53,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
 
-impl LateLintPass<'_> for FromOverInto {
+impl<'tcx> LateLintPass<'tcx> for FromOverInto {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
         if !meets_msrv(self.msrv.as_ref(), &msrvs::RE_REBALANCING_COHERENCE) {
             return;
index 73e800073b03fe6c0f0e6d93ceef01a834f0dd61..57b0751320521b5bab69b34e34a0196e6517213a 100644 (file)
@@ -43,7 +43,7 @@
 
 declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]);
 
-impl LateLintPass<'tcx> for FromStrRadix10 {
+impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
         if_chain! {
             if let ExprKind::Call(maybe_path, arguments) = &exp.kind;
index 77d08081c07f1d2bf07911b33de74f4a9f0148ef..bf59103e3f4d2bce903907fc9c41653eff1cf155 100644 (file)
@@ -18,7 +18,7 @@
 
 use super::{DOUBLE_MUST_USE, MUST_USE_CANDIDATE, MUST_USE_UNIT};
 
-pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
+pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     let attrs = cx.tcx.hir().attrs(item.hir_id());
     let attr = must_use_attr(attrs);
     if let hir::ItemKind::Fn(ref sig, ref _generics, ref body_id) = item.kind {
@@ -40,7 +40,7 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     }
 }
 
-pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
+pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
     if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind {
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@@ -48,7 +48,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
         let attr = must_use_attr(attrs);
         if let Some(attr) = attr {
             check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
-        } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.hir_id()).is_none() {
+        } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id).is_none() {
             check_must_use_candidate(
                 cx,
                 sig.decl,
@@ -62,7 +62,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<
     }
 }
 
-pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
+pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind {
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
index f83789bb2199e0e2bfff2fb35eb2d64297c1e7ac..6d829a18b2e0927a0ef6ae95bf186fa15797b952 100644 (file)
@@ -9,7 +9,7 @@
 
 use super::NOT_UNSAFE_PTR_ARG_DEREF;
 
-pub(super) fn check_fn(
+pub(super) fn check_fn<'tcx>(
     cx: &LateContext<'tcx>,
     kind: intravisit::FnKind<'tcx>,
     decl: &'tcx hir::FnDecl<'tcx>,
@@ -25,14 +25,14 @@ pub(super) fn check_fn(
     check_raw_ptr(cx, unsafety, decl, body, cx.tcx.hir().local_def_id(hir_id));
 }
 
-pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
+pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
         let body = cx.tcx.hir().body(eid);
         check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id);
     }
 }
 
-fn check_raw_ptr(
+fn check_raw_ptr<'tcx>(
     cx: &LateContext<'tcx>,
     unsafety: hir::Unsafety,
     decl: &'tcx hir::FnDecl<'tcx>,
index 71f6f87ae602beb7d2009eb5642d1e85417c063a..120fcb2619c7c66dd59dd58bdb3b7c1ea8b30170 100644 (file)
@@ -13,7 +13,7 @@
 
 use super::RESULT_UNIT_ERR;
 
-pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
+pub(super) fn check_item(cx: &LateContext<'_>, item: &hir::Item<'_>) {
     if let hir::ItemKind::Fn(ref sig, ref _generics, _) = item.kind {
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
@@ -23,17 +23,17 @@ pub(super) fn check_item(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
     }
 }
 
-pub(super) fn check_impl_item(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
+pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &hir::ImplItem<'_>) {
     if let hir::ImplItemKind::Fn(ref sig, _) = item.kind {
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
-        if is_public && trait_ref_of_method(cx, item.hir_id()).is_none() {
+        if is_public && trait_ref_of_method(cx, item.def_id).is_none() {
             check_result_unit_err(cx, sig.decl, item.span, fn_header_span);
         }
     }
 }
 
-pub(super) fn check_trait_item(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
+pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
         let is_public = cx.access_levels.is_exported(item.def_id);
         let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
index 63a14d8d4cde897a04387e97e9649ea30ead2d63..3af960491ed01d5872a0df98cba836829cadd303 100644 (file)
@@ -9,9 +9,9 @@
 use super::TOO_MANY_ARGUMENTS;
 
 pub(super) fn check_fn(
-    cx: &LateContext<'tcx>,
-    kind: intravisit::FnKind<'tcx>,
-    decl: &'tcx hir::FnDecl<'_>,
+    cx: &LateContext<'_>,
+    kind: intravisit::FnKind<'_>,
+    decl: &hir::FnDecl<'_>,
     span: Span,
     hir_id: hir::HirId,
     too_many_arguments_threshold: u64,
@@ -39,11 +39,7 @@ pub(super) fn check_fn(
     }
 }
 
-pub(super) fn check_trait_item(
-    cx: &LateContext<'tcx>,
-    item: &'tcx hir::TraitItem<'_>,
-    too_many_arguments_threshold: u64,
-) {
+pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>, too_many_arguments_threshold: u64) {
     if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
         // don't lint extern functions decls, it's not their fault
         if sig.header.abi == Abi::Rust {
index 65efbbab41a460f0ab4f9b2c84a400cbe22efeee..54bdea7ea25d634bde692af85f925652f9ca4d64 100644 (file)
@@ -11,9 +11,9 @@
 
 pub(super) fn check_fn(
     cx: &LateContext<'_>,
-    kind: FnKind<'tcx>,
+    kind: FnKind<'_>,
     span: Span,
-    body: &'tcx hir::Body<'_>,
+    body: &hir::Body<'_>,
     too_many_lines_threshold: u64,
 ) {
     // Closures must be contained in a parent body, which will be checked for `too_many_lines`.
index 16e5c5ca603db450474ce1697cf4e110041bbc6e..9525c163ece17a7b04a1e4a8e5c2ce50c343612e 100644 (file)
@@ -55,7 +55,7 @@ pub fn new(msrv: Option<RustcVersion>) -> Self {
 
 impl_lint_pass!(IfThenSomeElseNone => [IF_THEN_SOME_ELSE_NONE]);
 
-impl LateLintPass<'_> for IfThenSomeElseNone {
+impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'tcx Expr<'_>) {
         if !meets_msrv(self.msrv.as_ref(), &msrvs::BOOL_THEN) {
             return;
index 07caeada80d003fa96f48474a741c22bacf121d0..d650d6e9a85871881a680e755c6fc7def02fb345 100644 (file)
@@ -94,8 +94,8 @@ fn get_call_site(span: Span, ctxt: SyntaxContext) -> Option<Span> {
 }
 
 fn lint_implicit_returns(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'_>,
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
     // The context of the function body.
     ctxt: SyntaxContext,
     // Whether the expression is from a macro expansion.
index 1debdef9d86c7b077594bef9115ec3fbf70d8f9b..3d44a669d8f0507ed1870a6fe81a4bea12aa38d7 100644 (file)
@@ -63,7 +63,7 @@
 
 declare_lint_pass!(InconsistentStructConstructor => [INCONSISTENT_STRUCT_CONSTRUCTOR]);
 
-impl LateLintPass<'_> for InconsistentStructConstructor {
+impl<'tcx> LateLintPass<'tcx> for InconsistentStructConstructor {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if_chain! {
             if !expr.span.from_expansion();
@@ -76,7 +76,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             then {
                 let mut def_order_map = FxHashMap::default();
                 for (idx, field) in variant.fields.iter().enumerate() {
-                    def_order_map.insert(field.ident.name, idx);
+                    def_order_map.insert(field.name, idx);
                 }
 
                 if is_consistent_order(fields, &def_order_map) {
index 69f1c90beec5d31cc049262194ee7a0526874d02..073313e2bad4e2e40648ea921fb8538e1f6a00ba 100644 (file)
@@ -69,7 +69,7 @@ pub fn new(max_suggested_slice_pattern_length: u64, msrv: Option<RustcVersion>)
 
 impl_lint_pass!(IndexRefutableSlice => [INDEX_REFUTABLE_SLICE]);
 
-impl LateLintPass<'_> for IndexRefutableSlice {
+impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if_chain! {
             if !expr.span.from_expansion() || is_expn_of(expr.span, "if_chain").is_some();
index 60d234cd6f08f19fcb904f3b68df5a5ccab418b1..55c04a1186fc3376fce1d70124b972727d9e0163 100644 (file)
@@ -116,7 +116,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<
             if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String);
 
             // Filters instances of to_string which are required by a trait
-            if trait_ref_of_method(cx, impl_item.hir_id()).is_none();
+            if trait_ref_of_method(cx, impl_item.def_id).is_none();
 
             then {
                 show_lint(cx, impl_item);
index 5fe6725b581dc341f4c5e89cfb603c3b64ff528c..9284e002409920673763967bb375b5bbf1b1b90a 100644 (file)
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
 use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind};
@@ -46,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for NumberedFields {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
         if let ExprKind::Struct(path, fields, None) = e.kind {
             if !fields.is_empty()
-                && !in_macro(e.span)
+                && !e.span.from_expansion()
                 && fields
                     .iter()
                     .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
index 0af6b3b7d464ef67ab1e7b1ba16dcbe2ac802dca..d3bdc819a9f2b48e277d9dd5aaca17859e3d1782 100644 (file)
@@ -1,8 +1,7 @@
-use clippy_utils::{diagnostics::span_lint, return_ty, ty::implements_trait};
-use rustc_hir::{ImplItem, ImplItemKind};
+use clippy_utils::{diagnostics::span_lint, get_parent_node, ty::implements_trait};
+use rustc_hir::{def_id::LocalDefId, FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::symbol::kw;
 use rustc_span::symbol::sym;
 
 declare_clippy_lint! {
 
 declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
 
-impl LateLintPass<'_> for IterNotReturningIterator {
-    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'tcx>) {
-        let name = impl_item.ident.name.as_str();
-        if_chain! {
-            if let ImplItemKind::Fn(fn_sig, _) = &impl_item.kind;
-            let ret_ty = return_ty(cx, impl_item.hir_id());
-            if matches!(name, "iter" | "iter_mut");
-            if let [param] = cx.tcx.fn_arg_names(impl_item.def_id);
-            if param.name == kw::SelfLower;
-            if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
-            if !implements_trait(cx, ret_ty, iter_trait_id, &[]);
+impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
+        let name = item.ident.name.as_str();
+        if matches!(name, "iter" | "iter_mut") {
+            if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
+                check_sig(cx, name, fn_sig, item.def_id);
+            }
+        }
+    }
 
-            then {
-                span_lint(
-                    cx,
-                    ITER_NOT_RETURNING_ITERATOR,
-                    fn_sig.span,
-                    &format!("this method is named `{}` but its return type does not implement `Iterator`", name),
-                );
+    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
+        let name = item.ident.name.as_str();
+        if matches!(name, "iter" | "iter_mut")
+            && !matches!(
+                get_parent_node(cx.tcx, item.hir_id()),
+                Some(Node::Item(Item { kind: ItemKind::Impl(i), .. })) if i.of_trait.is_some()
+            )
+        {
+            if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
+                check_sig(cx, name, fn_sig, item.def_id);
             }
         }
     }
 }
+
+fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
+    if sig.decl.implicit_self.has_implicit_self() {
+        let ret_ty = cx.tcx.fn_sig(fn_id).skip_binder().output();
+        let ret_ty = cx
+            .tcx
+            .try_normalize_erasing_regions(cx.param_env, ret_ty)
+            .unwrap_or(ret_ty);
+        if cx
+            .tcx
+            .get_diagnostic_item(sym::Iterator)
+            .map_or(false, |iter_id| !implements_trait(cx, ret_ty, iter_id, &[]))
+        {
+            span_lint(
+                cx,
+                ITER_NOT_RETURNING_ITERATOR,
+                sig.span,
+                &format!(
+                    "this method is named `{}` but its return type does not implement `Iterator`",
+                    name
+                ),
+            );
+        }
+    }
+}
index 20e6220ec7d3adaa3250873b8285e53e533462a9..e1168c3f6022ef381fc2eb576b44fb47ea8c3e41 100644 (file)
@@ -214,14 +214,14 @@ fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
     {
         let mut current_and_super_traits = DefIdSet::default();
         fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
+        let is_empty = sym!(is_empty);
 
         let is_empty_method_found = current_and_super_traits
             .iter()
-            .flat_map(|&i| cx.tcx.associated_items(i).in_definition_order())
+            .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty))
             .any(|i| {
                 i.kind == ty::AssocKind::Fn
                     && i.fn_has_self_parameter
-                    && i.ident.name == sym!(is_empty)
                     && cx.tcx.fn_sig(i.def_id).inputs().skip_binder().len() == 1
             });
 
@@ -245,7 +245,7 @@ enum LenOutput<'tcx> {
     Option(DefId),
     Result(DefId, Ty<'tcx>),
 }
-fn parse_len_output(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
+fn parse_len_output<'tcx>(cx: &LateContext<'_>, sig: FnSig<'tcx>) -> Option<LenOutput<'tcx>> {
     match *sig.output().kind() {
         ty::Int(_) | ty::Uint(_) => Some(LenOutput::Integral),
         ty::Adt(adt, subs) if cx.tcx.is_diagnostic_item(sym::Option, adt.did) => {
@@ -458,7 +458,7 @@ fn is_empty_array(expr: &Expr<'_>) -> bool {
 fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     /// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
     fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
-        if item.kind == ty::AssocKind::Fn && item.ident.name.as_str() == "is_empty" {
+        if item.kind == ty::AssocKind::Fn {
             let sig = cx.tcx.fn_sig(item.def_id);
             let ty = sig.skip_binder();
             ty.inputs().len() == 1
@@ -469,10 +469,11 @@ fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
 
     /// Checks the inherent impl's items for an `is_empty(self)` method.
     fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
+        let is_empty = sym!(is_empty);
         cx.tcx.inherent_impls(id).iter().any(|imp| {
             cx.tcx
                 .associated_items(*imp)
-                .in_definition_order()
+                .filter_by_name_unhygienic(is_empty)
                 .any(|item| is_is_empty(cx, item))
         })
     }
@@ -480,9 +481,10 @@ fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
     let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
     match ty.kind() {
         ty::Dynamic(tt, ..) => tt.principal().map_or(false, |principal| {
+            let is_empty = sym!(is_empty);
             cx.tcx
                 .associated_items(principal.def_id())
-                .in_definition_order()
+                .filter_by_name_unhygienic(is_empty)
                 .any(|item| is_is_empty(cx, item))
         }),
         ty::Projection(ref proj) => has_is_empty_impl(cx, proj.item_def_id),
index d03276f7f98ba70912584d40a3256c88c0d86d58..cb1ef01f5ba9da535914e20717219b40ef8c33af 100644 (file)
@@ -124,7 +124,7 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
             if let Some(init) = local.init;
             then {
                 let init_ty = cx.typeck_results().expr_ty(init);
-                let contains_sync_guard = init_ty.walk(cx.tcx).any(|inner| match inner.unpack() {
+                let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
                     GenericArgKind::Type(inner_ty) => {
                         SYNC_GUARD_PATHS.iter().any(|path| match_type(cx, inner_ty, path))
                     },
index 944411087e9511dd9dab1e90f3f90a5031b30b11..26fb4259952b6ac5b971179f41b36ad0b86d3c7b 100644 (file)
@@ -37,6 +37,8 @@
     LintId::of(derivable_impls::DERIVABLE_IMPLS),
     LintId::of(derive::DERIVE_HASH_XOR_EQ),
     LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
+    LintId::of(disallowed_methods::DISALLOWED_METHODS),
+    LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(doc::MISSING_SAFETY_DOC),
     LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
     LintId::of(double_comparison::DOUBLE_COMPARISONS),
     LintId::of(loops::WHILE_LET_ON_ITERATOR),
     LintId::of(main_recursion::MAIN_RECURSION),
     LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
+    LintId::of(manual_bits::MANUAL_BITS),
     LintId::of(manual_map::MANUAL_MAP),
     LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
     LintId::of(manual_strip::MANUAL_STRIP),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
     LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK),
     LintId::of(mut_reference::UNNECESSARY_MUT_PASSED),
-    LintId::of(mutex_atomic::MUTEX_ATOMIC),
     LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE),
     LintId::of(needless_bool::BOOL_COMPARISON),
     LintId::of(needless_bool::NEEDLESS_BOOL),
index 002122793f3b6b4c2a26965be3bbbd1239f2d1cb..746bdb19c3d927c71003c869be6f41ef6774a82c 100644 (file)
@@ -3,33 +3,33 @@
 // Manual edits will be overwritten.
 
 store.register_lints(&[
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::CLIPPY_LINTS_INTERNAL,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::COLLAPSIBLE_SPAN_LINT_CALLS,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::COMPILER_LINT_FUNCTIONS,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::DEFAULT_LINT,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::IF_CHAIN_STYLE,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::INTERNING_DEFINED_SYMBOL,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::INVALID_CLIPPY_VERSION_ATTRIBUTE,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::INVALID_PATHS,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::LINT_WITHOUT_LINT_PASS,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::MATCH_TYPE_ON_DIAGNOSTIC_ITEM,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::MISSING_CLIPPY_VERSION_ATTRIBUTE,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::OUTER_EXPN_EXPN_DATA,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::PRODUCE_ICE,
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     utils::internal_lints::UNNECESSARY_SYMBOL_STR,
     absurd_extreme_comparisons::ABSURD_EXTREME_COMPARISONS,
     approx_const::APPROX_CONSTANT,
@@ -59,6 +59,7 @@
     bool_assert_comparison::BOOL_ASSERT_COMPARISON,
     booleans::LOGIC_BUG,
     booleans::NONMINIMAL_BOOL,
+    borrow_as_ptr::BORROW_AS_PTR,
     bytecount::NAIVE_BYTECOUNT,
     cargo_common_metadata::CARGO_COMMON_METADATA,
     case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS,
     main_recursion::MAIN_RECURSION,
     manual_assert::MANUAL_ASSERT,
     manual_async_fn::MANUAL_ASYNC_FN,
+    manual_bits::MANUAL_BITS,
     manual_map::MANUAL_MAP,
     manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
     manual_ok_or::MANUAL_OK_OR,
     shadow::SHADOW_REUSE,
     shadow::SHADOW_SAME,
     shadow::SHADOW_UNRELATED,
+    single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES,
     single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS,
     size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT,
     slow_vector_initialization::SLOW_VECTOR_INITIALIZATION,
index e3cf067001834a3b16b00d480584e2771e37ed2e..a7353790100267681b11ae92b234125b48571dfe 100644 (file)
@@ -6,8 +6,6 @@
     LintId::of(attrs::EMPTY_LINE_AFTER_OUTER_ATTR),
     LintId::of(cognitive_complexity::COGNITIVE_COMPLEXITY),
     LintId::of(copies::BRANCHES_SHARING_CODE),
-    LintId::of(disallowed_methods::DISALLOWED_METHODS),
-    LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(equatable_if_let::EQUATABLE_IF_LET),
     LintId::of(fallible_impl_from::FALLIBLE_IMPL_FROM),
     LintId::of(floating_point_arithmetic::IMPRECISE_FLOPS),
@@ -17,6 +15,7 @@
     LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
     LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
     LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
+    LintId::of(mutex_atomic::MUTEX_ATOMIC),
     LintId::of(mutex_atomic::MUTEX_INTEGER),
     LintId::of(non_send_fields_in_send_ty::NON_SEND_FIELDS_IN_SEND_TY),
     LintId::of(nonstandard_macro_braces::NONSTANDARD_MACRO_BRACES),
index 70a4a624378909dd1040fbe9997927c07fa6d8c2..1744b7c825078e40ed37210384bb3cda7a4d0409 100644 (file)
@@ -7,6 +7,7 @@
     LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
     LintId::of(bit_mask::VERBOSE_BIT_MASK),
+    LintId::of(borrow_as_ptr::BORROW_AS_PTR),
     LintId::of(bytecount::NAIVE_BYTECOUNT),
     LintId::of(case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS),
     LintId::of(casts::CAST_LOSSLESS),
index 2ea0b696f1feb3ad437c61d8c9c1072de7da606f..f9ffd4cf829fa220ac198750eedf317b4ba93916 100644 (file)
@@ -19,7 +19,6 @@
     LintId::of(methods::SINGLE_CHAR_PATTERN),
     LintId::of(methods::UNNECESSARY_TO_OWNED),
     LintId::of(misc::CMP_OWNED),
-    LintId::of(mutex_atomic::MUTEX_ATOMIC),
     LintId::of(redundant_clone::REDUNDANT_CLONE),
     LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION),
     LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE),
index eab389a9bd892089b94a10c749b2837d3916b25c..e7e2798da7da99785f7b46c6410ee615f00c4bcd 100644 (file)
@@ -54,6 +54,7 @@
     LintId::of(shadow::SHADOW_REUSE),
     LintId::of(shadow::SHADOW_SAME),
     LintId::of(shadow::SHADOW_UNRELATED),
+    LintId::of(single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES),
     LintId::of(strings::STRING_ADD),
     LintId::of(strings::STRING_SLICE),
     LintId::of(strings::STRING_TO_STRING),
index 1a0b869d40adb5f2fb8e4c9ef89ea812533f0569..05211476ff2300df79103d25e801f600f2cb692b 100644 (file)
@@ -16,6 +16,8 @@
     LintId::of(comparison_chain::COMPARISON_CHAIN),
     LintId::of(default::FIELD_REASSIGN_WITH_DEFAULT),
     LintId::of(dereference::NEEDLESS_BORROW),
+    LintId::of(disallowed_methods::DISALLOWED_METHODS),
+    LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(doc::MISSING_SAFETY_DOC),
     LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
     LintId::of(enum_variants::ENUM_VARIANT_NAMES),
@@ -41,6 +43,7 @@
     LintId::of(loops::WHILE_LET_ON_ITERATOR),
     LintId::of(main_recursion::MAIN_RECURSION),
     LintId::of(manual_async_fn::MANUAL_ASYNC_FN),
+    LintId::of(manual_bits::MANUAL_BITS),
     LintId::of(manual_map::MANUAL_MAP),
     LintId::of(manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE),
     LintId::of(map_clone::MAP_CLONE),
index d4687a1e2879749d7253fcf0d2bc90ece839f7ad..79e9882fef4c49c42c2d6fb4bca32878a42f23bf 100644 (file)
@@ -4,7 +4,6 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
 #![feature(drain_filter)]
-#![feature(in_band_lifetimes)]
 #![feature(iter_intersperse)]
 #![feature(let_else)]
 #![feature(once_cell)]
@@ -153,12 +152,9 @@ macro_rules! declare_clippy_lint {
     };
 }
 
-#[cfg(feature = "metadata-collector-lint")]
+#[cfg(feature = "internal")]
 mod deprecated_lints;
-#[cfg_attr(
-    any(feature = "internal-lints", feature = "metadata-collector-lint"),
-    allow(clippy::missing_clippy_version_attribute)
-)]
+#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
 mod utils;
 
 // begin lints modules, do not remove this comment, it’s used in `update_lints`
@@ -177,6 +173,7 @@ macro_rules! declare_clippy_lint {
 mod blocks_in_if_conditions;
 mod bool_assert_comparison;
 mod booleans;
+mod borrow_as_ptr;
 mod bytecount;
 mod cargo_common_metadata;
 mod case_sensitive_file_extension_comparisons;
@@ -264,6 +261,7 @@ macro_rules! declare_clippy_lint {
 mod main_recursion;
 mod manual_assert;
 mod manual_async_fn;
+mod manual_bits;
 mod manual_map;
 mod manual_non_exhaustive;
 mod manual_ok_or;
@@ -351,6 +349,7 @@ macro_rules! declare_clippy_lint {
 mod semicolon_if_nothing_returned;
 mod serde_api;
 mod shadow;
+mod single_char_lifetime_names;
 mod single_component_path_imports;
 mod size_of_in_element_count;
 mod slow_vector_initialization;
@@ -471,7 +470,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     include!("lib.register_restriction.rs");
     include!("lib.register_pedantic.rs");
 
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     include!("lib.register_internal.rs");
 
     include!("lib.register_all.rs");
@@ -483,7 +482,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     include!("lib.register_cargo.rs");
     include!("lib.register_nursery.rs");
 
-    #[cfg(feature = "metadata-collector-lint")]
+    #[cfg(feature = "internal")]
     {
         if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) {
             store.register_late_pass(|| Box::new(utils::internal_lints::metadata_collector::MetadataCollector::new()));
@@ -492,7 +491,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     }
 
     // all the internal lints
-    #[cfg(feature = "internal-lints")]
+    #[cfg(feature = "internal")]
     {
         store.register_early_pass(|| Box::new(utils::internal_lints::ClippyLintsInternal));
         store.register_early_pass(|| Box::new(utils::internal_lints::ProduceIce));
@@ -858,6 +857,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(needless_late_init::NeedlessLateInit));
     store.register_late_pass(|| Box::new(return_self_not_must_use::ReturnSelfNotMustUse));
     store.register_late_pass(|| Box::new(init_numbered_fields::NumberedFields));
+    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)));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
index 0e2b78609c2c13c90f3ab022f477a183a75d6171..6dd7b22ff94b5f80c9d5e49d7210913dedcd6c90 100644 (file)
@@ -91,7 +91,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
         if let ImplItemKind::Fn(ref sig, id) = item.kind {
-            let report_extra_lifetimes = trait_ref_of_method(cx, item.hir_id()).is_none();
+            let report_extra_lifetimes = trait_ref_of_method(cx, item.def_id).is_none();
             check_fn_inner(
                 cx,
                 sig.decl,
index dda09fecdf90f5918fa396569c981f89f80359f7..823cf0f43221ca644030184f2b1b35ff96aa58e4 100644 (file)
@@ -5,7 +5,7 @@
 use rustc_hir::{Block, Expr};
 use rustc_lint::LateContext;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, loop_block: &Block<'_>) {
     if loop_block.stmts.is_empty() && loop_block.expr.is_none() && !is_in_panic_handler(cx, expr) {
         let msg = "empty `loop {}` wastes CPU cycles";
         let help = if is_no_std_crate(cx) {
index 1bab0d99b695c3348e4d20ace42fb3fc6ee643ff..17246cc5426ae1ef638fc0ec546959ba9a8d0f7e 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_middle::ty::TyS;
 use rustc_span::symbol::sym;
 
-pub(super) fn check(cx: &LateContext<'_>, self_arg: &'hir Expr<'hir>, call_expr: &Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>) {
     let self_ty = cx.typeck_results().expr_ty(self_arg);
     let self_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg);
     if !(TyS::same_type(self_ty, self_ty_adjusted) && is_trait_method(cx, call_expr, sym::IntoIterator)) {
index c62fa5e998bd475da630f949ac6198c71ce02a97..48c4015e07b6d308abd6aeae6932d159344a206b 100644 (file)
@@ -2,7 +2,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::is_copy;
 use clippy_utils::{get_enclosing_block, higher, path_to_local, sugg};
 use if_chain::if_chain;
 use rustc_ast::ast;
@@ -62,15 +62,15 @@ pub(super) fn check<'tcx>(
                         if_chain! {
                             if let ExprKind::Index(base_left, idx_left) = lhs.kind;
                             if let ExprKind::Index(base_right, idx_right) = rhs.kind;
-                            if is_slice_like(cx, cx.typeck_results().expr_ty(base_left));
-                            if is_slice_like(cx, cx.typeck_results().expr_ty(base_right));
+                            if let Some(ty) = get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_left));
+                            if get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some();
                             if let Some((start_left, offset_left)) = get_details_from_idx(cx, idx_left, &starts);
                             if let Some((start_right, offset_right)) = get_details_from_idx(cx, idx_right, &starts);
 
                             // Source and destination must be different
                             if path_to_local(base_left) != path_to_local(base_right);
                             then {
-                                Some((IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left },
+                                Some((ty, IndexExpr { base: base_left, idx: start_left, idx_offset: offset_left },
                                     IndexExpr { base: base_right, idx: start_right, idx_offset: offset_right }))
                             } else {
                                 None
@@ -78,7 +78,7 @@ pub(super) fn check<'tcx>(
                         }
                     })
                 })
-                .map(|o| o.map(|(dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, &dst, &src)))
+                .map(|o| o.map(|(ty, dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, ty, &dst, &src)))
                 .collect::<Option<Vec<_>>>()
                 .filter(|v| !v.is_empty())
                 .map(|v| v.join("\n    "));
@@ -105,6 +105,7 @@ fn build_manual_memcpy_suggestion<'tcx>(
     start: &Expr<'_>,
     end: &Expr<'_>,
     limits: ast::RangeLimits,
+    elem_ty: Ty<'tcx>,
     dst: &IndexExpr<'_>,
     src: &IndexExpr<'_>,
 ) -> String {
@@ -187,9 +188,16 @@ fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> {
         .into()
     };
 
+    let method_str = if is_copy(cx, elem_ty) {
+        "copy_from_slice"
+    } else {
+        "clone_from_slice"
+    };
+
     format!(
-        "{}.clone_from_slice(&{}[{}..{}]);",
+        "{}.{}(&{}[{}..{}]);",
         dst,
+        method_str,
         src_base_str,
         src_offset.maybe_par(),
         src_limit.maybe_par()
@@ -203,7 +211,7 @@ fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> {
 #[derive(Clone)]
 struct MinifyingSugg<'a>(Sugg<'a>);
 
-impl Display for MinifyingSugg<'a> {
+impl<'a> Display for MinifyingSugg<'a> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         self.0.fmt(f)
     }
@@ -324,14 +332,13 @@ struct Start<'hir> {
     kind: StartKind<'hir>,
 }
 
-fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'_>) -> bool {
-    let is_slice = match ty.kind() {
-        ty::Ref(_, subty, _) => is_slice_like(cx, subty),
-        ty::Slice(..) | ty::Array(..) => true,
-        _ => false,
-    };
-
-    is_slice || is_type_diagnostic_item(cx, ty, sym::Vec) || is_type_diagnostic_item(cx, ty, sym::VecDeque)
+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),
+        _ => None,
+    }
 }
 
 fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
index aedf0844937d1a2327cbf3a96307cbe4c931a01b..37a57d8feb1d33bc432c0a5f067da1f03baf818c 100644 (file)
@@ -147,7 +147,7 @@ pub fn is_found(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     }
 }
 
-impl intravisit::Visitor<'tcx> for BreakAfterExprVisitor {
+impl<'tcx> intravisit::Visitor<'tcx> for BreakAfterExprVisitor {
     type Map = Map<'tcx>;
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
index ba895f35faa267a1d7e0545bdc6f8bdf978f3afd..6248680aa621663e4dc5528816578b3054c133a5 100644 (file)
@@ -339,8 +339,8 @@ fn detect_iter_and_into_iters<'tcx: 'a, 'a>(
     }
 }
 
-fn get_captured_ids(cx: &LateContext<'tcx>, ty: &'_ TyS<'_>) -> HirIdSet {
-    fn get_captured_ids_recursive(cx: &LateContext<'tcx>, ty: &'_ TyS<'_>, set: &mut HirIdSet) {
+fn get_captured_ids(cx: &LateContext<'_>, ty: &'_ TyS<'_>) -> HirIdSet {
+    fn get_captured_ids_recursive(cx: &LateContext<'_>, ty: &'_ TyS<'_>, set: &mut HirIdSet) {
         match ty.kind() {
             ty::Adt(_, generics) => {
                 for generic in *generics {
index 172d9fc39a29fb8975254f0e266a7fdf59ae663a..33abd2a72d8809384618191316b2d4fb86c8b5c3 100644 (file)
@@ -58,8 +58,7 @@ pub(super) fn check<'tcx>(
 
                 // ensure that the indexed variable was declared before the loop, see #601
                 if let Some(indexed_extent) = indexed_extent {
-                    let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
-                    let parent_def_id = cx.tcx.hir().local_def_id(parent_id);
+                    let parent_def_id = cx.tcx.hir().get_parent_item(expr.hir_id);
                     let region_scope_tree = cx.tcx.region_scope_tree(parent_def_id);
                     let pat_extent = region_scope_tree.var_scope(pat.hir_id.local_id);
                     if region_scope_tree.is_subscope_of(indexed_extent, pat_extent) {
@@ -263,8 +262,7 @@ fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Ex
                 let res = self.cx.qpath_res(seqpath, seqexpr.hir_id);
                 match res {
                     Res::Local(hir_id) => {
-                        let parent_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
-                        let parent_def_id = self.cx.tcx.hir().local_def_id(parent_id);
+                        let parent_def_id = self.cx.tcx.hir().get_parent_item(expr.hir_id);
                         let extent = self.cx.tcx.region_scope_tree(parent_def_id).var_scope(hir_id.local_id);
                         if index_used_directly {
                             self.indexed_directly.insert(
index a3aa6be6afd645ccd94a717d431c481af8c1ed5d..bb1b3e2a1ec6ae9ab437f86bbd670e524a946579 100644 (file)
@@ -10,8 +10,8 @@
 use std::iter::{once, Iterator};
 
 pub(super) fn check(
-    cx: &LateContext<'tcx>,
-    block: &'tcx Block<'_>,
+    cx: &LateContext<'_>,
+    block: &Block<'_>,
     loop_id: HirId,
     span: Span,
     for_loop: Option<&ForLoop<'_>>,
index 2eb247de9f42b79a789e8695fb05edaaada931c5..ab83291461fb4e1526dd727a898c9d84201a0bd2 100644 (file)
@@ -49,7 +49,7 @@ fn emit_lint(cx: &LateContext<'_>, vec: &Expr<'_>, pushed_item: &Expr<'_>) {
         if same_item_push_visitor.should_lint();
         if let Some((vec, pushed_item)) = same_item_push_visitor.vec_push;
         let vec_ty = cx.typeck_results().expr_ty(vec);
-        let ty = vec_ty.walk(cx.tcx).nth(1).unwrap().expect_ty();
+        let ty = vec_ty.walk().nth(1).unwrap().expect_ty();
         if cx
             .tcx
             .lang_items()
index 4dcd5c87722eec0f8c9e43f0e4f9fa6a4efc0cc5..8f57df0be6bd47563a82e932f9fe5bcda0946aea 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, loop_block: &'tcx Block<'_>) {
     // extract the expression from the first statement (if any) in a block
     let inner_stmt_expr = extract_expr_from_first_stmt(loop_block);
     // or extract the first expression (if any) from the block
index b390476a664d9e54f4c4490df4763204cc9c3265..750328d1d01a5b4385b2b08bfc2c30e4f0b16eb8 100644 (file)
@@ -8,12 +8,13 @@
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
-use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, PatKind, QPath, UnOp};
+use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, Mutability, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
-use rustc_span::{symbol::sym, Span, Symbol};
+use rustc_middle::ty::adjustment::Adjust;
+use rustc_span::{symbol::sym, Symbol};
 
-pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-    let (scrutinee_expr, iter_expr, some_pat, loop_expr) = if_chain! {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+    let (scrutinee_expr, iter_expr_struct, iter_expr, some_pat, loop_expr) = if_chain! {
         if let Some(higher::WhileLet { if_then, let_pat, let_expr }) = higher::WhileLet::hir(expr);
         // check for `Some(..)` pattern
         if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = let_pat.kind;
@@ -27,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         // get the loop containing the match expression
         if !uses_iter(cx, &iter_expr_struct, if_then);
         then {
-            (let_expr, iter_expr_struct, some_pat, expr)
+            (let_expr, iter_expr_struct, iter_expr, some_pat, expr)
         } else {
             return;
         }
@@ -47,7 +48,11 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be
     // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used
     // afterwards a mutable borrow of a field isn't necessary.
-    let by_ref = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) {
+    let by_ref = if cx.typeck_results().expr_ty(iter_expr).ref_mutability() == Some(Mutability::Mut)
+        || !iter_expr_struct.can_move
+        || !iter_expr_struct.fields.is_empty()
+        || needs_mutable_borrow(cx, &iter_expr_struct, loop_expr)
+    {
         ".by_ref()"
     } else {
         ""
@@ -67,26 +72,36 @@ pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
 #[derive(Debug)]
 struct IterExpr {
-    /// The span of the whole expression, not just the path and fields stored here.
-    span: Span,
     /// The fields used, in order of child to parent.
     fields: Vec<Symbol>,
     /// The path being used.
     path: Res,
+    /// Whether or not the iterator can be moved.
+    can_move: bool,
 }
 
 /// Parses any expression to find out which field of which variable is used. Will return `None` if
 /// the expression might have side effects.
 fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExpr> {
-    let span = e.span;
     let mut fields = Vec::new();
+    let mut can_move = true;
     loop {
+        if cx
+            .typeck_results()
+            .expr_adjustments(e)
+            .iter()
+            .any(|a| matches!(a.kind, Adjust::Deref(Some(..))))
+        {
+            // Custom deref impls need to borrow the whole value as it's captured by reference
+            can_move = false;
+            fields.clear();
+        }
         match e.kind {
             ExprKind::Path(ref path) => {
                 break Some(IterExpr {
-                    span,
                     fields,
                     path: cx.qpath_res(path, e.hir_id),
+                    can_move,
                 });
             },
             ExprKind::Field(base, name) => {
@@ -99,10 +114,12 @@ fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExp
             // Shouldn't have side effects, but there's no way to trace which field is used. So forget which fields have
             // already been seen.
             ExprKind::Index(base, idx) if !idx.can_have_side_effects() => {
+                can_move = false;
                 fields.clear();
                 e = base;
             },
             ExprKind::Unary(UnOp::Deref, base) => {
+                can_move = false;
                 fields.clear();
                 e = base;
             },
@@ -174,7 +191,7 @@ fn is_expr_same_child_or_parent_field(cx: &LateContext<'_>, expr: &Expr<'_>, fie
 
 /// Strips off all field and path expressions. This will return true if a field or path has been
 /// skipped. Used to skip them after failing to check for equality.
-fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) {
+fn skip_fields_and_path<'tcx>(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) {
     let mut e = expr;
     let e = loop {
         match e.kind {
@@ -187,13 +204,13 @@ fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool
 }
 
 /// Checks if the given expression uses the iterator.
-fn uses_iter(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool {
+fn uses_iter<'tcx>(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool {
     struct V<'a, 'b, 'tcx> {
         cx: &'a LateContext<'tcx>,
         iter_expr: &'b IterExpr,
         uses_iter: bool,
     }
-    impl Visitor<'tcx> for V<'_, '_, 'tcx> {
+    impl<'tcx> Visitor<'tcx> for V<'_, '_, 'tcx> {
         type Map = ErasedMap<'tcx>;
         fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
             NestedVisitorMap::None
@@ -228,7 +245,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
 }
 
 #[allow(clippy::too_many_lines)]
-fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr: &'tcx Expr<'_>) -> bool {
+fn needs_mutable_borrow(cx: &LateContext<'_>, iter_expr: &IterExpr, loop_expr: &Expr<'_>) -> bool {
     struct AfterLoopVisitor<'a, 'b, 'tcx> {
         cx: &'a LateContext<'tcx>,
         iter_expr: &'b IterExpr,
@@ -236,7 +253,7 @@ struct AfterLoopVisitor<'a, 'b, 'tcx> {
         after_loop: bool,
         used_iter: bool,
     }
-    impl Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
+    impl<'tcx> Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
         type Map = ErasedMap<'tcx>;
         fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
             NestedVisitorMap::None
@@ -275,7 +292,7 @@ struct NestedLoopVisitor<'a, 'b, 'tcx> {
         found_local: bool,
         used_after: bool,
     }
-    impl Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
+    impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
         type Map = ErasedMap<'tcx>;
 
         fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
index 50d80e6a1d224fc2ae05c5b2ec681cd53ee69f10..ca1ccb93bf3fbeea048a54fda55a0070aba819ab 100644 (file)
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::in_macro;
 use clippy_utils::source::snippet;
 use hir::def::{DefKind, Res};
 use if_chain::if_chain;
@@ -96,7 +95,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
             if let Res::Def(DefKind::Mod, id) = path.res;
             if !id.is_local();
             then {
-                for kid in cx.tcx.item_children(id).iter() {
+                for kid in cx.tcx.module_children(id).iter() {
                     if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
                         let span = mac_attr.span;
                         let def_path = cx.tcx.def_path_str(mac_id);
@@ -104,34 +103,34 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
                     }
                 }
             } else {
-                if in_macro(item.span) {
+                if item.span.from_expansion() {
                     self.push_unique_macro_pat_ty(cx, item.span);
                 }
             }
         }
     }
     fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
-        if in_macro(attr.span) {
+        if attr.span.from_expansion() {
             self.push_unique_macro(cx, attr.span);
         }
     }
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
-        if in_macro(expr.span) {
+        if expr.span.from_expansion() {
             self.push_unique_macro(cx, expr.span);
         }
     }
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
-        if in_macro(stmt.span) {
+        if stmt.span.from_expansion() {
             self.push_unique_macro(cx, stmt.span);
         }
     }
     fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
-        if in_macro(pat.span) {
+        if pat.span.from_expansion() {
             self.push_unique_macro_pat_ty(cx, pat.span);
         }
     }
     fn check_ty(&mut self, cx: &LateContext<'_>, ty: &hir::Ty<'_>) {
-        if in_macro(ty.span) {
+        if ty.span.from_expansion() {
             self.push_unique_macro_pat_ty(cx, ty.span);
         }
     }
index 5a2a965716cc6bc457454f304ae9157db0970b9a..26b53ab5d683739b5e5b7d7df594be12f808575c 100644 (file)
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::PanicExpn;
+use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_expn_of, sugg};
+use clippy_utils::{peel_blocks_with_stmt, sugg};
 use rustc_errors::Applicability;
-use rustc_hir::{Block, Expr, ExprKind, StmtKind, UnOp};
+use rustc_hir::{Expr, ExprKind, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
 
 declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
 
-impl LateLintPass<'_> for ManualAssert {
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+impl<'tcx> LateLintPass<'tcx> for ManualAssert {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
         if_chain! {
-            if let Expr {
-                kind: ExprKind:: If(cond, Expr {
-                    kind: ExprKind::Block(
-                        Block {
-                            stmts: [stmt],
-                            ..
-                        },
-                        _),
-                    ..
-                }, None),
-                ..
-            } = &expr;
-            if is_expn_of(stmt.span, "panic").is_some();
+            if let ExprKind::If(cond, then, None) = expr.kind;
             if !matches!(cond.kind, ExprKind::Let(_));
-            if let StmtKind::Semi(semi) = stmt.kind;
+            if !expr.span.from_expansion();
+            let then = peel_blocks_with_stmt(then);
+            if let Some(macro_call) = root_macro_call(then.span);
+            if cx.tcx.item_name(macro_call.def_id) == sym::panic;
             if !cx.tcx.sess.source_map().is_multiline(cond.span);
-
+            if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn);
             then {
-                let call = if_chain! {
-                    if let ExprKind::Block(block, _) = semi.kind;
-                    if let Some(init) = block.expr;
-                    then {
-                        init
-                    } else {
-                        semi
-                    }
-                };
-                let span = if let Some(panic_expn) = PanicExpn::parse(call) {
-                    match *panic_expn.format_args.value_args {
-                        [] => panic_expn.format_args.format_string_span,
-                        [.., last] => panic_expn.format_args.format_string_span.to(last.span),
-                    }
-                } else if let ExprKind::Call(_, [format_args]) = call.kind {
-                    format_args.span
-                } else {
-                    return
-                };
                 let mut applicability = Applicability::MachineApplicable;
-                let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
-                let cond_sugg = if let ExprKind::DropTemps(e, ..) = cond.kind {
-                    if let Expr{kind: ExprKind::Unary(UnOp::Not, not_expr), ..} = e {
-                         sugg::Sugg::hir_with_applicability(cx, not_expr, "..", &mut applicability).maybe_par().to_string()
-                    } else {
-                       format!("!{}", sugg::Sugg::hir_with_applicability(cx, e, "..", &mut applicability).maybe_par())
-                    }
-                } else {
-                   format!("!{}", sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par())
+                let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
+                let cond = cond.peel_drop_temps();
+                let (cond, not) = match cond.kind {
+                    ExprKind::Unary(UnOp::Not, e) => (e, ""),
+                    _ => (cond, "!"),
                 };
-
+                let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
+                let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
                 span_lint_and_sugg(
                     cx,
                     MANUAL_ASSERT,
                     expr.span,
                     "only a `panic!` in `if`-then statement",
                     "try",
-                    format!("assert!({}, {});", cond_sugg, sugg),
+                    sugg,
                     Applicability::MachineApplicable,
                 );
             }
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
new file mode 100644 (file)
index 0000000..50bf252
--- /dev/null
@@ -0,0 +1,107 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{match_def_path, meets_msrv, msrvs, paths};
+use rustc_ast::ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind, GenericArg, QPath};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, Ty};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for uses of `std::mem::size_of::<T>() * 8` when
+    /// `T::BITS` is available.
+    ///
+    /// ### Why is this bad?
+    /// Can be written as the shorter `T::BITS`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// std::mem::size_of::<usize>() * 8;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// usize::BITS;
+    /// ```
+    #[clippy::version = "1.60.0"]
+    pub MANUAL_BITS,
+    style,
+    "manual implementation of `size_of::<T>() * 8` can be simplified with `T::BITS`"
+}
+
+#[derive(Clone)]
+pub struct ManualBits {
+    msrv: Option<RustcVersion>,
+}
+
+impl ManualBits {
+    #[must_use]
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
+
+impl_lint_pass!(ManualBits => [MANUAL_BITS]);
+
+impl<'tcx> LateLintPass<'tcx> for ManualBits {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if !meets_msrv(self.msrv.as_ref(), &msrvs::MANUAL_BITS) {
+            return;
+        }
+
+        if_chain! {
+            if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind;
+            if let BinOpKind::Mul = &bin_op.node;
+            if let Some((real_ty, resolved_ty, other_expr)) = get_one_size_of_ty(cx, left_expr, right_expr);
+            if matches!(resolved_ty.kind(), ty::Int(_) | ty::Uint(_));
+            if let ExprKind::Lit(lit) = &other_expr.kind;
+            if let LitKind::Int(8, _) = lit.node;
+
+            then {
+                span_lint_and_sugg(
+                    cx,
+                    MANUAL_BITS,
+                    expr.span,
+                    "usage of `mem::size_of::<T>()` to obtain the size of `T` in bits",
+                    "consider using",
+                    format!("{}::BITS", snippet_opt(cx, real_ty.span).unwrap()),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
+
+fn get_one_size_of_ty<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr1: &'tcx Expr<'_>,
+    expr2: &'tcx Expr<'_>,
+) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>, &'tcx Expr<'tcx>)> {
+    match (get_size_of_ty(cx, expr1), get_size_of_ty(cx, expr2)) {
+        (Some((real_ty, resolved_ty)), None) => Some((real_ty, resolved_ty, expr2)),
+        (None, Some((real_ty, resolved_ty))) => Some((real_ty, resolved_ty, expr1)),
+        _ => None,
+    }
+}
+
+fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(&'tcx rustc_hir::Ty<'tcx>, Ty<'tcx>)> {
+    if_chain! {
+        if let ExprKind::Call(count_func, _func_args) = expr.kind;
+        if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
+
+        if let QPath::Resolved(_, count_func_path) = count_func_qpath;
+        if let Some(segment_zero) = count_func_path.segments.get(0);
+        if let Some(args) = segment_zero.args;
+        if let Some(GenericArg::Type(real_ty)) = args.args.get(0);
+
+        if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
+        if match_def_path(cx, def_id, &paths::MEM_SIZE_OF);
+        then {
+            cx.typeck_results().node_substs(count_func.hir_id).types().next().map(|resolved_ty| (real_ty, resolved_ty))
+        } else {
+            None
+        }
+    }
+}
index 34a70ca76c6a2a81df2d5ab1e4b1ec35c4a673ed..8475e367b09fe3c4a14bad23f8f29357e64e3d32 100644 (file)
@@ -45,7 +45,7 @@
 
 declare_lint_pass!(ManualMap => [MANUAL_MAP]);
 
-impl LateLintPass<'_> for ManualMap {
+impl<'tcx> LateLintPass<'tcx> for ManualMap {
     #[allow(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let (scrutinee, then_pat, then_body, else_pat, else_body) = match IfLetOrMatch::parse(cx, expr) {
@@ -219,7 +219,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 
 // Checks whether the expression could be passed as a function, or whether a closure is needed.
 // Returns the function to be passed to `map` if it exists.
-fn can_pass_as_func(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+fn can_pass_as_func<'tcx>(cx: &LateContext<'tcx>, binding: HirId, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     match expr.kind {
         ExprKind::Call(func, [arg])
             if path_to_local_id(arg, binding)
@@ -251,8 +251,13 @@ struct SomeExpr<'tcx> {
 
 // Try to parse into a recognized `Option` pattern.
 // i.e. `_`, `None`, `Some(..)`, or a reference to any of those.
-fn try_parse_pattern(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
-    fn f(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ref_count: usize, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
+fn try_parse_pattern<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ctxt: SyntaxContext) -> Option<OptionPat<'tcx>> {
+    fn f<'tcx>(
+        cx: &LateContext<'tcx>,
+        pat: &'tcx Pat<'_>,
+        ref_count: usize,
+        ctxt: SyntaxContext,
+    ) -> Option<OptionPat<'tcx>> {
         match pat.kind {
             PatKind::Wild => Some(OptionPat::Wild),
             PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
@@ -269,7 +274,7 @@ fn f(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, ref_count: usize, ctxt: SyntaxC
 }
 
 // Checks for an expression wrapped by the `Some` constructor. Returns the contained expression.
-fn get_some_expr(
+fn get_some_expr<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
     needs_unsafe_block: bool,
@@ -306,6 +311,6 @@ fn get_some_expr(
 }
 
 // Checks for the `None` value.
-fn is_none_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
+fn is_none_expr(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     matches!(peel_blocks(expr).kind, ExprKind::Path(ref qpath) if is_lang_ctor(cx, qpath, OptionNone))
 }
index b60e2dc366b416e455ea5fe04ea2a38845f22d89..bd083e3e9e2012d8a766aae6e46e67cf8dfaca65 100644 (file)
@@ -40,7 +40,7 @@
 
 declare_lint_pass!(ManualOkOr => [MANUAL_OK_OR]);
 
-impl LateLintPass<'_> for ManualOkOr {
+impl<'tcx> LateLintPass<'tcx> for ManualOkOr {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'tcx>) {
         if in_external_macro(cx.sess(), scrutinee.span) {
             return;
index aac3c6e0de2bb6b12f2bb0f65f3e7de60a9148f7..b3a91d9f18f5d94ff4d782900996310d161ed6f9 100644 (file)
@@ -43,7 +43,7 @@
 
 declare_lint_pass!(ManualUnwrapOr => [MANUAL_UNWRAP_OR]);
 
-impl LateLintPass<'_> for ManualUnwrapOr {
+impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOr {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if in_external_macro(cx.sess(), expr.span) || in_constant(cx, expr.hir_id) {
             return;
index 2c0fc218ca07c0d5eabb6a3140c540406a938a6d..1fc7eb72142843fdfd9b6f2aac5170034d9f3ef1 100644 (file)
@@ -55,7 +55,7 @@ enum CaseMethod {
     AsciiUppercase,
 }
 
-impl LateLintPass<'_> for MatchStrCaseMismatch {
+impl<'tcx> LateLintPass<'tcx> for MatchStrCaseMismatch {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if !in_external_macro(cx.tcx.sess, expr.span);
index 22970507f964c2c9416ab1fadead327da3637995..60dd957db01f8d69d6b67fef0eb020d6b687ecf9 100644 (file)
@@ -2,16 +2,17 @@
 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::higher;
+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_expn_of, is_lang_ctor, is_lint_allowed, is_refutable, is_unit_expr, is_wild, meets_msrv, msrvs,
+    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;
@@ -974,7 +975,8 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
                     }
                     if_chain! {
                         if matching_wild;
-                        if is_panic_call(arm.body);
+                        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,
@@ -997,7 +999,7 @@ enum CommonPrefixSearcher<'a> {
     Path(&'a [PathSegment<'a>]),
     Mixed,
 }
-impl CommonPrefixSearcher<'a> {
+impl<'a> CommonPrefixSearcher<'a> {
     fn with_path(&mut self, path: &'a [PathSegment<'a>]) {
         match path {
             [path @ .., _] => self.with_prefix(path),
@@ -1136,7 +1138,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
                 s.push_str("::");
                 s
             },
-            variant.ident.name,
+            variant.name,
             match variant.ctor_kind {
                 CtorKind::Fn if variant.fields.len() == 1 => "(_)",
                 CtorKind::Fn => "(..)",
@@ -1179,22 +1181,6 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>])
     };
 }
 
-// If the block contains only a `panic!` macro (as expression or statement)
-fn is_panic_call(expr: &Expr<'_>) -> bool {
-    // Unwrap any wrapping blocks
-    let span = if let ExprKind::Block(block, _) = expr.kind {
-        match (&block.expr, block.stmts.len(), block.stmts.first()) {
-            (&Some(exp), 0, _) => exp.span,
-            (&None, 1, Some(stmt)) => stmt.span,
-            _ => return false,
-        }
-    } else {
-        expr.span
-    };
-
-    is_expn_of(span, "panic").is_some() && is_expn_of(span, "unreachable").is_none()
-}
-
 fn check_match_ref_pats<'a, 'b, I>(cx: &LateContext<'_>, ex: &Expr<'_>, pats: I, expr: &Expr<'_>)
 where
     'b: 'a,
@@ -1818,11 +1804,15 @@ pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     /// 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(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    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(cx: &LateContext<'tcx>, ty: Ty<'tcx>, seen: &mut FxHashSet<Ty<'tcx>>) -> bool {
+    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;
         }
@@ -1884,7 +1874,7 @@ fn try_get_generic_ty(ty: Ty<'_>, index: usize) -> Option<Ty<'_>> {
 
     // Checks if there are any temporaries created in the given expression for which drop order
     // matters.
-    fn temporaries_need_ordered_drop(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    fn temporaries_need_ordered_drop<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
         struct V<'a, 'tcx> {
             cx: &'a LateContext<'tcx>,
             res: bool,
index 0ec9387f9c460f1426db4b319e59fe9d349ec2c1..0f39470f34262d2fc95718ea5f143b21e3ea7628 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::FormatExpn;
+use clippy_utils::macros::{root_macro_call_first_node, FormatArgsExpn};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 
 /// Checks for the `EXPECT_FUN_CALL` lint.
 #[allow(clippy::too_many_lines)]
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_span: Span, name: &str, args: &[hir::Expr<'_>]) {
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &hir::Expr<'_>,
+    method_span: Span,
+    name: &str,
+    args: &'tcx [hir::Expr<'tcx>],
+) {
     // Strip `&`, `as_ref()` and `as_str()` off `arg` until we're left with either a `String` or
     // `&str`
     fn get_arg_root<'a>(cx: &LateContext<'_>, arg: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
@@ -128,11 +134,12 @@ fn is_call(node: &hir::ExprKind<'_>) -> bool {
     let mut applicability = Applicability::MachineApplicable;
 
     //Special handling for `format!` as arg_root
-    if let Some(format_expn) = FormatExpn::parse(arg_root) {
-        let span = match *format_expn.format_args.value_args {
-            [] => format_expn.format_args.format_string_span,
-            [.., last] => format_expn.format_args.format_string_span.to(last.span),
-        };
+    if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) {
+        if !cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id) {
+            return;
+        }
+        let Some(format_args) = FormatArgsExpn::find_nested(cx, arg_root, macro_call.expn) else { return };
+        let span = format_args.inputs_span();
         let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
         span_lint_and_sugg(
             cx,
index 8ea9312c0f7075557211e94575f30d946a4fe040..6436e28a63c521cb5d3af2f21a89c4fa45ba224e 100644 (file)
@@ -37,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
     }
 }
 
-fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String {
+fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> String {
     fn strip_angle_brackets(s: &str) -> Option<&str> {
         s.strip_prefix('<')?.strip_suffix('>')
     }
index 4e33b2ff14cdeaa2e3d7427e5349c30c2f22a5d5..ed5136e7d00ff1cbe7c0643f06062916840ed42c 100644 (file)
@@ -80,7 +80,6 @@
 use rustc_middle::ty::{self, TraitRef, Ty, TyS};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::Symbol;
 use rustc_span::{sym, Span};
 use rustc_typeck::hir_ty_to_ty;
 
     /// ### Why is this bad?
     /// The unnecessary calls result in useless allocations.
     ///
+    /// ### Known problems
+    /// `unnecessary_to_owned` can falsely trigger if `IntoIterator::into_iter` is applied to an
+    /// owned copy of a resource and the resource is later used mutably. See
+    /// [#8148](https://github.com/rust-lang/rust-clippy/issues/8148).
+    ///
     /// ### Example
     /// ```rust
     /// let path = std::path::Path::new("x");
@@ -1997,24 +2001,16 @@ pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Sel
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
-fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(Symbol, &'tcx [hir::Expr<'tcx>], Span)> {
+fn method_call<'tcx>(recv: &'tcx hir::Expr<'tcx>) -> Option<(&'tcx str, &'tcx [hir::Expr<'tcx>], Span)> {
     if let ExprKind::MethodCall(path, span, args, _) = recv.kind {
         if !args.iter().any(|e| e.span.from_expansion()) {
-            return Some((path.ident.name, args, span));
+            let name = path.ident.name.as_str();
+            return Some((name, args, span));
         }
     }
     None
 }
 
-/// Same as `method_call` but the `Symbol` is dereferenced into a temporary `&str`
-macro_rules! method_call {
-    ($expr:expr) => {
-        method_call($expr)
-            .as_ref()
-            .map(|&(ref name, args, span)| (name.as_str(), args, span))
-    };
-}
-
 impl<'tcx> LateLintPass<'tcx> for Methods {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if expr.span.from_expansion() {
@@ -2057,7 +2053,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
             return;
         }
         let name = impl_item.ident.name.as_str();
-        let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
+        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
         let item = cx.tcx.hir().expect_item(parent);
         let self_ty = cx.tcx.type_of(item.def_id);
 
@@ -2133,10 +2129,10 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
 
             // walk the return type and check for Self (this does not check associated types)
             if let Some(self_adt) = self_ty.ty_adt_def() {
-                if contains_adt_constructor(cx.tcx, ret_ty, self_adt) {
+                if contains_adt_constructor(ret_ty, self_adt) {
                     return;
                 }
-            } else if contains_ty(cx.tcx, ret_ty, self_ty) {
+            } else if contains_ty(ret_ty, self_ty) {
                 return;
             }
 
@@ -2147,10 +2143,10 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
                     if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
                         // walk the associated type and check for Self
                         if let Some(self_adt) = self_ty.ty_adt_def() {
-                            if contains_adt_constructor(cx.tcx, projection_predicate.ty, self_adt) {
+                            if contains_adt_constructor(projection_predicate.ty, self_adt) {
                                 return;
                             }
-                        } else if contains_ty(cx.tcx, projection_predicate.ty, self_ty) {
+                        } else if contains_ty(projection_predicate.ty, self_ty) {
                             return;
                         }
                     }
@@ -2199,7 +2195,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
             if let TraitItemKind::Fn(_, _) = item.kind;
             let ret_ty = return_ty(cx, item.hir_id());
             let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
-            if !contains_ty(cx.tcx, ret_ty, self_ty);
+            if !contains_ty(ret_ty, self_ty);
 
             then {
                 span_lint(
@@ -2217,7 +2213,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
 
 #[allow(clippy::too_many_lines)]
 fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Option<&RustcVersion>) {
-    if let Some((name, [recv, args @ ..], span)) = method_call!(expr) {
+    if let Some((name, [recv, args @ ..], span)) = method_call(expr) {
         match (name, args) {
             ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [_arg]) => {
                 zst_offset::check(cx, expr, recv);
@@ -2233,7 +2229,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             ("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
             ("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
             ("cloned", []) => cloned_instead_of_copied::check(cx, expr, recv, span, msrv),
-            ("collect", []) => match method_call!(recv) {
+            ("collect", []) => match method_call(recv) {
                 Some((name @ ("cloned" | "copied"), [recv2], _)) => {
                     iter_cloned_collect::check(cx, name, expr, recv2);
                 },
@@ -2247,14 +2243,14 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 },
                 _ => {},
             },
-            ("count", []) => match method_call!(recv) {
+            ("count", []) => match method_call(recv) {
                 Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
                     iter_count::check(cx, expr, recv2, name);
                 },
                 Some(("map", [_, arg], _)) => suspicious_map::check(cx, expr, recv, arg),
                 _ => {},
             },
-            ("expect", [_]) => match method_call!(recv) {
+            ("expect", [_]) => match method_call(recv) {
                 Some(("ok", [recv], _)) => ok_expect::check(cx, expr, recv),
                 _ => expect_used::check(cx, expr, recv),
             },
@@ -2271,13 +2267,13 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 flat_map_option::check(cx, expr, arg, span);
             },
             ("flatten", []) => {
-                if let Some(("map", [recv, map_arg], _)) = method_call!(recv) {
+                if let Some(("map", [recv, map_arg], _)) = method_call(recv) {
                     map_flatten::check(cx, expr, recv, map_arg);
                 }
             },
             ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
             ("for_each", [_]) => {
-                if let Some(("inspect", [_, _], span2)) = method_call!(recv) {
+                if let Some(("inspect", [_, _], span2)) = method_call(recv) {
                     inspect_for_each::check(cx, expr, span2);
                 }
             },
@@ -2286,7 +2282,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
             ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
             ("map", [m_arg]) => {
-                if let Some((name, [recv2, args @ ..], span2)) = method_call!(recv) {
+                if let Some((name, [recv2, args @ ..], span2)) = method_call(recv) {
                     match (name, args) {
                         ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv),
                         ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv),
@@ -2301,7 +2297,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             },
             ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
             ("next", []) => {
-                if let Some((name, [recv, args @ ..], _)) = method_call!(recv) {
+                if let Some((name, [recv, args @ ..], _)) = method_call(recv) {
                     match (name, args) {
                         ("filter", [arg]) => filter_next::check(cx, expr, recv, arg),
                         ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv, arg, msrv),
@@ -2312,7 +2308,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                     }
                 }
             },
-            ("nth", [n_arg]) => match method_call!(recv) {
+            ("nth", [n_arg]) => match method_call(recv) {
                 Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
                 Some(("iter", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
                 Some(("iter_mut", [recv2], _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
@@ -2344,12 +2340,12 @@ 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, span);
             },
-            ("unwrap", []) => match method_call!(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) {
+            ("unwrap_or", [u_arg]) => match method_call(recv) {
                 Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), [lhs, rhs], _)) => {
                     manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
                 },
@@ -2358,7 +2354,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 },
                 _ => {},
             },
-            ("unwrap_or_else", [u_arg]) => match method_call!(recv) {
+            ("unwrap_or_else", [u_arg]) => match method_call(recv) {
                 Some(("map", [recv, map_arg], _)) if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, msrv) => {},
                 _ => {
                     unwrap_or_else_default::check(cx, expr, recv, u_arg);
@@ -2371,7 +2367,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
 }
 
 fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) {
-    if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) {
+    if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call(recv) {
         search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span);
     }
 }
@@ -2535,11 +2531,17 @@ fn matches_ref<'a>(cx: &LateContext<'a>, mutability: hir::Mutability, parent_ty:
             implements_trait(cx, ty, trait_def_id, &[parent_ty.into()])
         }
 
+        fn matches_none<'a>(cx: &LateContext<'a>, parent_ty: Ty<'a>, ty: Ty<'a>) -> bool {
+            !matches_value(cx, parent_ty, ty)
+                && !matches_ref(cx, hir::Mutability::Not, parent_ty, ty)
+                && !matches_ref(cx, hir::Mutability::Mut, parent_ty, ty)
+        }
+
         match self {
             Self::Value => matches_value(cx, parent_ty, ty),
             Self::Ref => matches_ref(cx, hir::Mutability::Not, parent_ty, ty) || ty == parent_ty && is_copy(cx, ty),
             Self::RefMut => matches_ref(cx, hir::Mutability::Mut, parent_ty, ty),
-            Self::No => ty != parent_ty,
+            Self::No => matches_none(cx, parent_ty, ty),
         }
     }
 
index 70f20da1d6db795f4e452d1c618d6efeb790d552..514bdadc442e3ac33263bf9bd202102216f4619e 100644 (file)
@@ -124,7 +124,7 @@ struct IterUsage {
 }
 
 #[allow(clippy::too_many_lines)]
-fn parse_iter_usage(
+fn parse_iter_usage<'tcx>(
     cx: &LateContext<'tcx>,
     ctxt: SyntaxContext,
     mut iter: impl Iterator<Item = (HirId, Node<'tcx>)>,
@@ -281,7 +281,7 @@ pub(super) fn check_needless_splitn(
     }
 }
 
-fn check_iter(
+fn check_iter<'tcx>(
     cx: &LateContext<'tcx>,
     ctxt: SyntaxContext,
     mut iter: impl Iterator<Item = (HirId, Node<'tcx>)>,
index 8300df03e9935a9f0219364edc2ebc3a817cd2c4..5999245ea7d0001e8262c0072ac262f7bd6c624f 100644 (file)
 
 use super::UNNECESSARY_TO_OWNED;
 
-pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, receiver: &'tcx Expr<'tcx>) -> bool {
+pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
     if_chain! {
         if let Some(parent) = get_parent_expr(cx, expr);
         if let Some(callee_def_id) = fn_def_id(cx, parent);
         if is_into_iter(cx, callee_def_id);
         then {
-            check_for_loop_iter(cx, parent, method_name, receiver)
+            check_for_loop_iter(cx, parent, method_name, receiver, false)
         } else {
             false
         }
@@ -30,10 +30,11 @@ pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol
 /// include this code directly is so that it can be called from
 /// `unnecessary_into_owned::check_into_iter_call_arg`.
 pub fn check_for_loop_iter(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'tcx>,
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
     method_name: Symbol,
-    receiver: &'tcx Expr<'tcx>,
+    receiver: &Expr<'_>,
+    cloned_before_iter: bool,
 ) -> bool {
     if_chain! {
         if let Some(grandparent) = get_parent_expr(cx, expr).and_then(|parent| get_parent_expr(cx, parent));
@@ -70,12 +71,22 @@ pub fn check_for_loop_iter(
                 expr.span,
                 &format!("unnecessary use of `{}`", method_name),
                 |diag| {
-                    diag.span_suggestion(expr.span, "use", snippet, Applicability::MachineApplicable);
+                    // If `check_into_iter_call_arg` called `check_for_loop_iter` because a call to
+                    // a `to_owned`-like function was removed, then the next suggestion may be
+                    // incorrect. This is because the iterator that results from the call's removal
+                    // could hold a reference to a resource that is used mutably. See
+                    // https://github.com/rust-lang/rust-clippy/issues/8148.
+                    let applicability = if cloned_before_iter {
+                        Applicability::MaybeIncorrect
+                    } else {
+                        Applicability::MachineApplicable
+                    };
+                    diag.span_suggestion(expr.span, "use", snippet, applicability);
                     for addr_of_expr in addr_of_exprs {
                         match addr_of_expr.kind {
                             ExprKind::AddrOf(_, _, referent) => {
                                 let span = addr_of_expr.span.with_hi(referent.span.lo());
-                                diag.span_suggestion(span, "remove this `&`", String::new(), Applicability::MachineApplicable);
+                                diag.span_suggestion(span, "remove this `&`", String::new(), applicability);
                             }
                             _ => unreachable!(),
                         }
@@ -90,7 +101,7 @@ pub fn check_for_loop_iter(
 
 /// The core logic of `check_for_loop_iter` above, this function wraps a use of
 /// `CloneOrCopyVisitor`.
-fn clone_or_copy_needed(
+fn clone_or_copy_needed<'tcx>(
     cx: &LateContext<'tcx>,
     pat: &Pat<'tcx>,
     body: &'tcx Expr<'tcx>,
index c48bacfce0d37739f159b379fac6d10921093dac..e5b6d296b2d2519a320636db919465f54a7bf21f 100644 (file)
@@ -16,7 +16,7 @@
 
 use super::UNNECESSARY_TO_OWNED;
 
-pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) {
+pub fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol, args: &'tcx [Expr<'tcx>]) {
     if_chain! {
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if let [receiver] = args;
@@ -44,11 +44,11 @@ pub fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, method_name: Symbol
 /// call of a `to_owned`-like function is unnecessary.
 #[allow(clippy::too_many_lines)]
 fn check_addr_of_expr(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'tcx>,
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
     method_name: Symbol,
     method_def_id: DefId,
-    receiver: &'tcx Expr<'tcx>,
+    receiver: &Expr<'_>,
 ) -> bool {
     if_chain! {
         if let Some(parent) = get_parent_expr(cx, expr);
@@ -171,12 +171,7 @@ fn check_addr_of_expr(
 
 /// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its
 /// call of a `to_owned`-like function is unnecessary.
-fn check_into_iter_call_arg(
-    cx: &LateContext<'tcx>,
-    expr: &'tcx Expr<'tcx>,
-    method_name: Symbol,
-    receiver: &'tcx Expr<'tcx>,
-) -> bool {
+fn check_into_iter_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
     if_chain! {
         if let Some(parent) = get_parent_expr(cx, expr);
         if let Some(callee_def_id) = fn_def_id(cx, parent);
@@ -187,7 +182,13 @@ fn check_into_iter_call_arg(
         if let Some(item_ty) = get_iterator_item_ty(cx, parent_ty);
         if let Some(receiver_snippet) = snippet_opt(cx, receiver.span);
         then {
-            if unnecessary_iter_cloned::check_for_loop_iter(cx, parent, method_name, receiver) {
+            if unnecessary_iter_cloned::check_for_loop_iter(
+                cx,
+                parent,
+                method_name,
+                receiver,
+                true,
+            ) {
                 return true;
             }
             let cloned_or_copied = if is_copy(cx, item_ty) {
@@ -195,6 +196,9 @@ fn check_into_iter_call_arg(
             } else {
                 "cloned"
             };
+            // The next suggestion may be incorrect because the removal of the `to_owned`-like
+            // function could cause the iterator to hold a reference to a resource that is used
+            // mutably. See https://github.com/rust-lang/rust-clippy/issues/8148.
             span_lint_and_sugg(
                 cx,
                 UNNECESSARY_TO_OWNED,
@@ -202,7 +206,7 @@ fn check_into_iter_call_arg(
                 &format!("unnecessary use of `{}`", method_name),
                 "use",
                 format!("{}.iter().{}()", receiver_snippet, cloned_or_copied),
-                Applicability::MachineApplicable,
+                Applicability::MaybeIncorrect,
             );
             return true;
         }
@@ -212,7 +216,7 @@ fn check_into_iter_call_arg(
 
 /// Checks whether `expr` is an argument in a function call and, if so, determines whether its call
 /// of a `to_owned`-like function is unnecessary.
-fn check_other_call_arg(
+fn check_other_call_arg<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
     method_name: Symbol,
@@ -278,7 +282,7 @@ fn check_other_call_arg(
 
 /// Walks an expression's ancestors until it finds a non-`AddrOf` expression. Returns the first such
 /// expression found (if any) along with the immediately prior expression.
-fn skip_addr_of_ancestors(
+fn skip_addr_of_ancestors<'tcx>(
     cx: &LateContext<'tcx>,
     mut expr: &'tcx Expr<'tcx>,
 ) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>)> {
@@ -294,7 +298,7 @@ fn skip_addr_of_ancestors(
 
 /// Checks whether an expression is a function or method call and, if so, returns its `DefId`,
 /// `Substs`, and arguments.
-fn get_callee_substs_and_args(
+fn get_callee_substs_and_args<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
 ) -> Option<(DefId, SubstsRef<'tcx>, &'tcx [Expr<'tcx>])> {
@@ -319,7 +323,7 @@ fn get_callee_substs_and_args(
 }
 
 /// Returns the `TraitPredicate`s and `ProjectionPredicate`s for a function's input type.
-fn get_input_traits_and_projections(
+fn get_input_traits_and_projections<'tcx>(
     cx: &LateContext<'tcx>,
     callee_def_id: DefId,
     input: Ty<'tcx>,
@@ -359,7 +363,11 @@ fn get_input_traits_and_projections(
 }
 
 /// Composes two substitutions by applying the latter to the types of the former.
-fn compose_substs(cx: &LateContext<'tcx>, left: &[GenericArg<'tcx>], right: SubstsRef<'tcx>) -> Vec<GenericArg<'tcx>> {
+fn compose_substs<'tcx>(
+    cx: &LateContext<'tcx>,
+    left: &[GenericArg<'tcx>],
+    right: SubstsRef<'tcx>,
+) -> Vec<GenericArg<'tcx>> {
     left.iter()
         .map(|arg| {
             if let GenericArgKind::Type(arg_ty) = arg.unpack() {
index 401dc27811dc3aa05ca5de9c822c9bb41c7a7bd5..21b3f81d5d981978df903b8e2251eeac41c681ed 100644 (file)
@@ -717,7 +717,7 @@ fn check_cast(cx: &LateContext<'_>, span: Span, e: &Expr<'_>, ty: &hir::Ty<'_>)
     }
 }
 
-fn check_binary(
+fn check_binary<'a>(
     cx: &LateContext<'a>,
     expr: &Expr<'_>,
     cmp: &rustc_span::source_map::Spanned<rustc_hir::BinOpKind>,
index a8d410508563c72092cfaa587c014863353ba979..77849e1800f6bf9f22aff0d916f55592d55fc42e 100644 (file)
@@ -121,7 +121,7 @@ fn check_fn(
                 }
             },
             FnKind::Method(_, sig, ..) => {
-                if trait_ref_of_method(cx, hir_id).is_some()
+                if trait_ref_of_method(cx, def_id).is_some()
                     || already_const(sig.header)
                     || method_accepts_dropable(cx, sig.decl.inputs)
                 {
index 5fe887a4573cccb99b283dab4af6b5e969e9cc1a..1bdd805f658549801dec79a6bfd63d1d14e6e66f 100644 (file)
@@ -89,7 +89,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
         if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind {
-            if trait_ref_of_method(cx, item.hir_id()).is_none() {
+            if trait_ref_of_method(cx, item.def_id).is_none() {
                 check_sig(cx, item.hir_id(), sig.decl);
             }
         }
index 12e219cd5c8714318c166726acae0c659bb6c32c..842959ce36b07ad41f3a45df70dcf0a37a21309f 100644 (file)
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{higher, is_direct_expn_of};
+use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
 use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
 
 declare_lint_pass!(DebugAssertWithMutCall => [DEBUG_ASSERT_WITH_MUT_CALL]);
 
-const DEBUG_MACRO_NAMES: [&str; 3] = ["debug_assert", "debug_assert_eq", "debug_assert_ne"];
-
 impl<'tcx> LateLintPass<'tcx> for DebugAssertWithMutCall {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        for dmn in &DEBUG_MACRO_NAMES {
-            if is_direct_expn_of(e.span, dmn).is_some() {
-                if let Some(macro_args) = higher::extract_assert_macro_args(e) {
-                    for arg in macro_args {
-                        let mut visitor = MutArgVisitor::new(cx);
-                        visitor.visit_expr(arg);
-                        if let Some(span) = visitor.expr_span() {
-                            span_lint(
-                                cx,
-                                DEBUG_ASSERT_WITH_MUT_CALL,
-                                span,
-                                &format!("do not call a function with mutable arguments inside of `{}!`", dmn),
-                            );
-                        }
-                    }
-                }
+        let Some(macro_call) = root_macro_call_first_node(cx, e) else { return };
+        let macro_name = cx.tcx.item_name(macro_call.def_id);
+        if !matches!(
+            macro_name.as_str(),
+            "debug_assert" | "debug_assert_eq" | "debug_assert_ne"
+        ) {
+            return;
+        }
+        let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn) else { return };
+        for arg in [lhs, rhs] {
+            let mut visitor = MutArgVisitor::new(cx);
+            visitor.visit_expr(arg);
+            if let Some(span) = visitor.expr_span() {
+                span_lint(
+                    cx,
+                    DEBUG_ASSERT_WITH_MUT_CALL,
+                    span,
+                    &format!(
+                        "do not call a function with mutable arguments inside of `{}!`",
+                        macro_name
+                    ),
+                );
             }
         }
     }
index 816377fe65e9f31e61b5458784af40267abd46cc..73823779e493d98e52e6642777db0db1dee9df1a 100644 (file)
@@ -38,7 +38,7 @@
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub MUTEX_ATOMIC,
-    perf,
+    nursery,
     "using a mutex where an atomic value could be used instead"
 }
 
index 0c1da0351739a25de814988d9db6da15b5bb554b..19d58f7474b0ad548cd50622fd03ecd109de91d8 100644 (file)
@@ -48,7 +48,7 @@
 
 declare_lint_pass!(NeedlessForEach => [NEEDLESS_FOR_EACH]);
 
-impl LateLintPass<'_> for NeedlessForEach {
+impl<'tcx> LateLintPass<'tcx> for NeedlessForEach {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         let expr = match stmt.kind {
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr,
index 094a3f111ba5ae5d9f4b17415166ce4e7b92c09c..9957afcbf04aaee1d7daaa305f1a89e797d335e9 100644 (file)
@@ -330,7 +330,7 @@ fn check<'tcx>(
     Some(())
 }
 
-impl LateLintPass<'tcx> for NeedlessLateInit {
+impl<'tcx> LateLintPass<'tcx> for NeedlessLateInit {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
         let mut parents = cx.tcx.hir().parent_iter(local.hir_id);
 
index 35877d51c0c166c89ec0e70598ed377a84b70a96..ebd4fb0bf51ccb4390a4fa96fdf7e9c5c42f1549 100644 (file)
@@ -118,7 +118,7 @@ fn check_fn(
         let fn_def_id = cx.tcx.hir().local_def_id(hir_id);
 
         let preds = traits::elaborate_predicates(cx.tcx, cx.param_env.caller_bounds().iter())
-            .filter(|p| !p.is_global(cx.tcx))
+            .filter(|p| !p.is_global())
             .filter_map(|obligation| {
                 // Note that we do not want to deal with qualified predicates here.
                 match obligation.predicate.kind().no_bound_vars() {
index f0c0c89ca8f3b5bfff8df170daa76273a47b3566..aec95530bba67ea3b3d2faaeaf93cec7b9612c44 100644 (file)
@@ -101,7 +101,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                             if sig.decl.inputs.is_empty();
                             if name == sym::new;
                             if cx.access_levels.is_reachable(impl_item.def_id);
-                            let self_def_id = cx.tcx.hir().local_def_id(cx.tcx.hir().get_parent_item(id));
+                            let self_def_id = cx.tcx.hir().get_parent_item(id);
                             let self_ty = cx.tcx.type_of(self_def_id);
                             if TyS::same_type(self_ty, return_ty(cx, id));
                             if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default);
index 9d5babc5de840d69e3f5941cc0459a5420fd2ed2..5bf8a1ba1ca3010258ed4d12afe881b5cf88ea7d 100644 (file)
@@ -82,7 +82,7 @@ fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
     }
 }
 
-fn check_no_effect(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) -> bool {
+fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
     if let StmtKind::Semi(expr) = stmt.kind {
         if has_no_effect(cx, expr) {
             span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
@@ -155,7 +155,7 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     }
 }
 
-fn check_unnecessary_operation(cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
+fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
     if_chain! {
         if let StmtKind::Semi(expr) = stmt.kind;
         if let Some(reduced) = reduce_expression(cx, expr);
index 074ba9e92ba4dfcea5e8921afbe8139302efe7f1..afc356d1ab25794b810913ade86be05da6be3c3b 100644 (file)
 use rustc_hir::{
     BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp,
 };
-use rustc_infer::traits::specialization_graph;
 use rustc_lint::{LateContext, LateLintPass, Lint};
 use rustc_middle::mir::interpret::{ConstValue, ErrorHandled};
 use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{self, AssocKind, Const, Ty};
+use rustc_middle::ty::{self, Const, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{InnerSpan, Span, DUMMY_SP};
 use rustc_typeck::hir_ty_to_ty;
@@ -189,7 +188,10 @@ fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: D
 
     let result = cx.tcx.const_eval_resolve(
         cx.param_env,
-        ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs),
+        ty::Unevaluated::new(
+            ty::WithOptConstParam::unknown(def_id),
+            substs,
+        ),
         None,
     );
     is_value_unfrozen_raw(cx, result, ty)
@@ -281,7 +283,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitIt
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
         if let ImplItemKind::Const(hir_ty, body_id) = &impl_item.kind {
-            let item_def_id = cx.tcx.hir().get_parent_did(impl_item.hir_id());
+            let item_def_id = cx.tcx.hir().get_parent_item(impl_item.hir_id());
             let item = cx.tcx.hir().expect_item(item_def_id);
 
             match &item.kind {
@@ -293,8 +295,10 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<
                         // Lint a trait impl item only when the definition is a generic type,
                         // assuming an assoc const is not meant to be an interior mutable type.
                         if let Some(of_trait_def_id) = of_trait_ref.trait_def_id();
-                        if let Some(of_assoc_item) = specialization_graph::Node::Trait(of_trait_def_id)
-                            .item(cx.tcx, impl_item.ident, AssocKind::Const, of_trait_def_id);
+                        if let Some(of_assoc_item) = cx
+                            .tcx
+                            .associated_item(impl_item.def_id)
+                            .trait_item_def_id;
                         if cx
                             .tcx
                             .layout_of(cx.tcx.param_env(of_trait_def_id).and(
@@ -303,7 +307,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<
                                 // and, in that case, the definition is *not* generic.
                                 cx.tcx.normalize_erasing_regions(
                                     cx.tcx.param_env(of_trait_def_id),
-                                    cx.tcx.type_of(of_assoc_item.def_id),
+                                    cx.tcx.type_of(of_assoc_item),
                                 ),
                             ))
                             .is_err();
index 4b57dbc4c412a0d117352899f7ec55005cb19184..e46fee4cac5eefd90aeabbe06886950848938107 100644 (file)
@@ -40,7 +40,7 @@
 
 declare_lint_pass!(NonOctalUnixPermissions => [NON_OCTAL_UNIX_PERMISSIONS]);
 
-impl LateLintPass<'_> for NonOctalUnixPermissions {
+impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         match &expr.kind {
             ExprKind::MethodCall(path, _, [func, param], _) => {
index 203f03d3603c8058a19821b16519c2e16199978c..ab1559c85d8b1f431946778eeb03991ffa925aa9 100644 (file)
@@ -111,7 +111,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                                 non_send_fields.push(NonSendField {
                                     def: field_def,
                                     ty: field_ty,
-                                    generic_params: collect_generic_params(cx, field_ty),
+                                    generic_params: collect_generic_params(field_ty),
                                 })
                             }
                         }
@@ -171,8 +171,8 @@ fn generic_params_string(&self) -> String {
 
 /// Given a type, collect all of its generic parameters.
 /// Example: `MyStruct<P, Box<Q, R>>` => `vec![P, Q, R]`
-fn collect_generic_params<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Vec<Ty<'tcx>> {
-    ty.walk(cx.tcx)
+fn collect_generic_params(ty: Ty<'_>) -> Vec<Ty<'_>> {
+    ty.walk()
         .filter_map(|inner| match inner.unpack() {
             GenericArgKind::Type(inner_ty) => Some(inner_ty),
             _ => None,
@@ -226,7 +226,7 @@ fn ty_allowed_with_raw_pointer_heuristic<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'t
 
 /// Checks if the type contains any pointer-like types in substs (including nested ones)
 fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> bool {
-    for ty_node in target_ty.walk(cx.tcx) {
+    for ty_node in target_ty.walk() {
         if let GenericArgKind::Type(inner_ty) = ty_node.unpack() {
             match inner_ty.kind() {
                 ty::RawPtr(_) => {
index 9c971437645455c1331dc96ba6c1fdcb92bbaf04..e0da12f77fcc79693641f7b08ffe05bbd9bae7c7 100644 (file)
@@ -50,7 +50,7 @@
 declare_lint_pass!(OctalEscapes => [OCTAL_ESCAPES]);
 
 impl EarlyLintPass for OctalEscapes {
-    fn check_expr(&mut self, cx: &EarlyContext<'tcx>, expr: &Expr) {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if in_external_macro(cx.sess, expr.span) {
             return;
         }
@@ -65,7 +65,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'tcx>, expr: &Expr) {
     }
 }
 
-fn check_lit(cx: &EarlyContext<'tcx>, lit: &Lit, span: Span, is_string: bool) {
+fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
     let contents = lit.symbol.as_str();
     let mut iter = contents.char_indices().peekable();
     let mut found = vec![];
index 8769c0452146435d1869b0ea30bfa74721052acb..b7a56970b335520aac10736b4ca9f9f660a2fe93 100644 (file)
@@ -1,8 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::root_macro_call_first_node;
+use clippy_utils::return_ty;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{find_macro_calls, is_expn_of, return_ty};
+use clippy_utils::visitors::expr_visitor_no_bodies;
 use rustc_hir as hir;
-use rustc_hir::intravisit::FnKind;
+use rustc_hir::intravisit::{FnKind, Visitor};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Span};
@@ -55,19 +57,19 @@ fn check_fn(
 }
 
 fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, body: &'tcx hir::Body<'tcx>) {
-    let mut panics = find_macro_calls(
-        &[
-            "unimplemented",
-            "unreachable",
-            "panic",
-            "todo",
-            "assert",
-            "assert_eq",
-            "assert_ne",
-        ],
-        body,
-    );
-    panics.retain(|span| is_expn_of(*span, "debug_assert").is_none());
+    let mut panics = Vec::new();
+    expr_visitor_no_bodies(|expr| {
+        let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return true };
+        if matches!(
+            &*cx.tcx.item_name(macro_call.def_id).as_str(),
+            "unimplemented" | "unreachable" | "panic" | "todo" | "assert" | "assert_eq" | "assert_ne"
+        ) {
+            panics.push(macro_call.span);
+            return false;
+        }
+        true
+    })
+    .visit_expr(&body.value);
     if !panics.is_empty() {
         span_lint_and_then(
             cx,
index edfac824ded987e8c47c5e45493c76b1beb83720..6ef6b9a20aa4b185211eaa6c96c48dae49d11af0 100644 (file)
@@ -1,10 +1,8 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_expn_of, match_panic_call};
-use if_chain::if_chain;
+use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
 
 impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if match_panic_call(cx, expr).is_some()
-            && (is_expn_of(expr.span, "debug_assert").is_none() && is_expn_of(expr.span, "assert").is_none())
-        {
-            let span = get_outer_span(expr);
-            if is_expn_of(expr.span, "unimplemented").is_some() {
+        let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
+        if is_panic(cx, macro_call.def_id) {
+            span_lint(
+                cx,
+                PANIC,
+                macro_call.span,
+                "`panic` should not be present in production code",
+            );
+            return;
+        }
+        match cx.tcx.item_name(macro_call.def_id).as_str() {
+            "todo" => {
+                span_lint(
+                    cx,
+                    TODO,
+                    macro_call.span,
+                    "`todo` should not be present in production code",
+                );
+            },
+            "unimplemented" => {
                 span_lint(
                     cx,
                     UNIMPLEMENTED,
-                    span,
+                    macro_call.span,
                     "`unimplemented` should not be present in production code",
                 );
-            } else if is_expn_of(expr.span, "todo").is_some() {
-                span_lint(cx, TODO, span, "`todo` should not be present in production code");
-            } else if is_expn_of(expr.span, "unreachable").is_some() {
-                span_lint(cx, UNREACHABLE, span, "usage of the `unreachable!` macro");
-            } else if is_expn_of(expr.span, "panic").is_some() {
-                span_lint(cx, PANIC, span, "`panic` should not be present in production code");
-            }
-        }
-    }
-}
-
-fn get_outer_span(expr: &Expr<'_>) -> Span {
-    if_chain! {
-        if expr.span.from_expansion();
-        let first = expr.span.ctxt().outer_expn_data().call_site;
-        if first.from_expansion();
-        then {
-            first.ctxt().outer_expn_data().call_site
-        } else {
-            expr.span
+            },
+            "unreachable" => {
+                span_lint(cx, UNREACHABLE, macro_call.span, "usage of the `unreachable!` macro");
+            },
+            _ => {},
         }
     }
 }
index c08a19d520b607bac1658b9ce50ab64928d2f5e3..63de117a6f1dec08737ffb022427062517570395 100644 (file)
@@ -164,7 +164,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
         if let ImplItemKind::Fn(ref sig, body_id) = item.kind {
             let parent_item = cx.tcx.hir().get_parent_item(item.hir_id());
-            if let Some(Node::Item(it)) = cx.tcx.hir().find(parent_item) {
+            if let Some(Node::Item(it)) = cx.tcx.hir().find_by_def_id(parent_item) {
                 if let ItemKind::Impl(Impl { of_trait: Some(_), .. }) = it.kind {
                     return; // ignore trait impls
                 }
index 3c126fc1ca69a27cc0862dcb3f44a8cf1f2df211..2bec93ac606057e22c483777f9a9a546d332a787 100644 (file)
@@ -39,7 +39,7 @@
 
 static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers";
 
-impl LateLintPass<'_> for PtrEq {
+impl<'tcx> LateLintPass<'tcx> for PtrEq {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if expr.span.from_expansion() {
             return;
index 1cf349f8aa7c7daa7526a25aee610df890de0904..dce1f66107a62c5921a81a9cbe99bbb142e5ce94 100644 (file)
@@ -14,7 +14,7 @@
     visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor as _},
     Mutability,
 };
-use rustc_middle::ty::{self, fold::TypeVisitor, Ty, TyCtxt};
+use rustc_middle::ty::{self, fold::TypeVisitor, Ty};
 use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis, ResultsCursor};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::{BytePos, Span};
@@ -220,7 +220,7 @@ fn check_fn(
                     continue;
                 } else if let Some(loc) = clone_usage.cloned_consume_or_mutate_loc {
                     // cloned value is mutated, and the clone is alive.
-                    if possible_borrower.is_alive_at(ret_local, loc) {
+                    if possible_borrower.local_is_alive_at(ret_local, loc) {
                         continue;
                     }
                 }
@@ -575,7 +575,7 @@ fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _
                 self.possible_borrower.add(borrowed.local, lhs);
             },
             other => {
-                if ContainsRegion(self.cx.tcx)
+                if ContainsRegion
                     .visit_ty(place.ty(&self.body.local_decls, self.cx.tcx).ty)
                     .is_continue()
                 {
@@ -624,7 +624,7 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Loca
                 .flat_map(HybridBitSet::iter)
                 .collect();
 
-            if ContainsRegion(self.cx.tcx)
+            if ContainsRegion
                 .visit_ty(self.body.local_decls[*dest].ty)
                 .is_break()
             {
@@ -703,15 +703,12 @@ fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'_>, _
     }
 }
 
-struct ContainsRegion<'tcx>(TyCtxt<'tcx>);
+struct ContainsRegion;
 
-impl<'tcx> TypeVisitor<'tcx> for ContainsRegion<'tcx> {
+impl TypeVisitor<'_> for ContainsRegion {
     type BreakTy = ();
-    fn tcx_for_anon_const_substs(&self) -> Option<TyCtxt<'tcx>> {
-        Some(self.0)
-    }
 
-    fn visit_region(&mut self, _: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
+    fn visit_region(&mut self, _: ty::Region<'_>) -> ControlFlow<Self::BreakTy> {
         ControlFlow::BREAK
     }
 }
@@ -767,7 +764,7 @@ fn only_borrowers(&mut self, borrowers: &[mir::Local], borrowed: mir::Local, at:
         self.bitset.0 == self.bitset.1
     }
 
-    fn is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
+    fn local_is_alive_at(&mut self, local: mir::Local, at: mir::Location) -> bool {
         self.maybe_live.seek_after_primary_effect(at);
         self.maybe_live.contains(local)
     }
index b2bd0103d1114125f0849b91cb6a7abdb811e194..7c88b42ea3199a771b40f5692f95923cf6928fa6 100644 (file)
@@ -42,7 +42,7 @@
 
 declare_lint_pass!(RedundantSlicing => [REDUNDANT_SLICING]);
 
-impl LateLintPass<'_> for RedundantSlicing {
+impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if expr.span.from_expansion() {
             return;
index 22ae7a291d00e5486e9ef8cb6a7b306aefda8257..b24483723700c2b031a404dddb0fd70db862ccc1 100644 (file)
@@ -50,6 +50,7 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
         if_chain! {
             if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind;
             if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind;
+            if deref_target.span.ctxt() == e.span.ctxt();
             if !addrof_target.span.from_expansion();
             then {
                 let mut applicability = Applicability::MachineApplicable;
index b57ec96bc7e6d101a41d53aa1622bca70cd473cf..5dafd08cf3be0e754b8d9e1d29b4076a2a5c5448 100644 (file)
@@ -1,5 +1,6 @@
+use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::is_must_use_ty;
-use clippy_utils::{diagnostics::span_lint, nth_arg, return_ty};
+use clippy_utils::{nth_arg, return_ty};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, HirId, TraitItem, TraitItemKind};
     /// This lint warns when a method returning `Self` doesn't have the `#[must_use]` attribute.
     ///
     /// ### Why is this bad?
-    /// It prevents to "forget" to use the newly created value.
+    /// Methods returning `Self` often create new values, having the `#[must_use]` attribute
+    /// prevents users from "forgetting" to use the newly created value.
+    ///
+    /// The `#[must_use]` attribute can be added to the type itself to ensure that instances
+    /// are never forgotten. Functions returning a type marked with `#[must_use]` will not be
+    /// linted, as the usage is already enforced by the type attribute.
     ///
     /// ### Limitations
     /// This lint is only applied on methods taking a `self` argument. It would be mostly noise
     /// if it was added on constructors for example.
     ///
     /// ### Example
+    /// Missing attribute
     /// ```rust
     /// pub struct Bar;
-    ///
     /// impl Bar {
     ///     // Bad
     ///     pub fn bar(&self) -> Self {
     ///         Self
     ///     }
+    /// }
+    /// ```
     ///
-    ///     // Good
+    /// It's better to have the `#[must_use]` attribute on the method like this:
+    /// ```rust
+    /// pub struct Bar;
+    /// impl Bar {
     ///     #[must_use]
-    ///     pub fn foo(&self) -> Self {
+    ///     pub fn bar(&self) -> Self {
+    ///         Self
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// Or on the type definition like this:
+    /// ```rust
+    /// #[must_use]
+    /// pub struct Bar;
+    /// impl Bar {
+    ///     pub fn bar(&self) -> Self {
     ///         Self
     ///     }
     /// }
@@ -44,7 +66,7 @@
 
 declare_lint_pass!(ReturnSelfNotMustUse => [RETURN_SELF_NOT_MUST_USE]);
 
-fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalDefId, span: Span, hir_id: HirId) {
+fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, span: Span, hir_id: HirId) {
     if_chain! {
         // If it comes from an external macro, better ignore it.
         if !in_external_macro(cx.sess(), span);
@@ -65,11 +87,13 @@ fn check_method(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'tcx>, fn_def: LocalD
         if !is_must_use_ty(cx, ret_ty);
 
         then {
-            span_lint(
+            span_lint_and_help(
                 cx,
                 RETURN_SELF_NOT_MUST_USE,
                 span,
                 "missing `#[must_use]` attribute on a method returning `Self`",
+                None,
+                "consider adding the `#[must_use]` attribute to the method or directly to the `Self` type"
             );
         }
     }
index 112ccdcdd4202af8fdfea61895e67a38fddfebf6..52e708f628a241ffa55f4bdd5a7d18e7287b7d18 100644 (file)
@@ -301,7 +301,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                 .fn_sig(def_id)
                 .output()
                 .skip_binder()
-                .walk(self.cx.tcx)
+                .walk()
                 .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
         }
 
index d386663e49858eda7d123d04dd2bad7fb0de7a82..123d0ad0457d1f1d5c2dff1f13c3f5eee0f6eb28 100644 (file)
@@ -51,7 +51,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<
             _ => return,
         }
 
-        let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
+        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
         let item = cx.tcx.hir().expect_item(parent);
         let self_ty = cx.tcx.type_of(item.def_id);
         let ret_ty = return_ty(cx, impl_item.hir_id());
@@ -63,10 +63,10 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<
 
         // Ensure method is constructor-like
         if let Some(self_adt) = self_ty.ty_adt_def() {
-            if !contains_adt_constructor(cx.tcx, ret_ty, self_adt) {
+            if !contains_adt_constructor(ret_ty, self_adt) {
                 return;
             }
-        } else if !contains_ty(cx.tcx, ret_ty, self_ty) {
+        } else if !contains_ty(ret_ty, self_ty) {
             return;
         }
 
index 0b3bbbc815580841e701e22d419e37e6ecc336e3..729694da46d5c2ee6a3098d2b9000495cf4a753d 100644 (file)
@@ -37,7 +37,7 @@
 
 declare_lint_pass!(SemicolonIfNothingReturned => [SEMICOLON_IF_NOTHING_RETURNED]);
 
-impl LateLintPass<'_> for SemicolonIfNothingReturned {
+impl<'tcx> LateLintPass<'tcx> for SemicolonIfNothingReturned {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
         if_chain! {
             if !block.span.from_expansion();
diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
new file mode 100644 (file)
index 0000000..ee82666
--- /dev/null
@@ -0,0 +1,63 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use rustc_ast::ast::{GenericParam, GenericParamKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for lifetimes with names which are one character
+    /// long.
+    ///
+    /// ### Why is this bad?
+    /// A single character is likely not enough to express the
+    /// purpose of a lifetime. Using a longer name can make code
+    /// easier to understand, especially for those who are new to
+    /// Rust.
+    ///
+    /// ### Known problems
+    /// Rust programmers and learning resources tend to use single
+    /// character lifetimes, so this lint is at odds with the
+    /// ecosystem at large. In addition, the lifetime's purpose may
+    /// be obvious or, rarely, expressible in one character.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct DiagnosticCtx<'a> {
+    ///     source: &'a str,
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct DiagnosticCtx<'src> {
+    ///     source: &'src str,
+    /// }
+    /// ```
+    #[clippy::version = "1.59.0"]
+    pub SINGLE_CHAR_LIFETIME_NAMES,
+    restriction,
+    "warns against single-character lifetime names"
+}
+
+declare_lint_pass!(SingleCharLifetimeNames => [SINGLE_CHAR_LIFETIME_NAMES]);
+
+impl EarlyLintPass for SingleCharLifetimeNames {
+    fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam) {
+        if in_external_macro(ctx.sess, param.ident.span) {
+            return;
+        }
+
+        if let GenericParamKind::Lifetime = param.kind {
+            if !param.is_placeholder && param.ident.as_str().len() <= 2 {
+                span_lint_and_help(
+                    ctx,
+                    SINGLE_CHAR_LIFETIME_NAMES,
+                    param.ident.span,
+                    "single-character lifetime names are likely uninformative",
+                    None,
+                    "use a more informative name",
+                );
+            }
+        }
+    }
+}
index df1e85afdd799a917fad95e4325de826050faa36..9b195f3c0a228d1edefd01abad488e6347f6b334 100644 (file)
@@ -37,7 +37,7 @@
 
 declare_lint_pass!(SizeOfInElementCount => [SIZE_OF_IN_ELEMENT_COUNT]);
 
-fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option<Ty<'tcx>> {
+fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool) -> Option<Ty<'tcx>> {
     match expr.kind {
         ExprKind::Call(count_func, _func_args) => {
             if_chain! {
@@ -64,7 +64,10 @@ fn get_size_of_ty(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, inverted: bool)
     }
 }
 
-fn get_pointee_ty_and_count_expr(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> {
+fn get_pointee_ty_and_count_expr<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'_>,
+) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> {
     const FUNCTIONS: [&[&str]; 8] = [
         &paths::PTR_COPY_NONOVERLAPPING,
         &paths::PTR_COPY,
index ad8e72ad764e133ff3b4ce29bbda643b8d4c830b..b4a71aefd437ff7b6c1a186467242b7cf3c0fa08 100644 (file)
@@ -381,7 +381,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
 
 declare_lint_pass!(StrToString => [STR_TO_STRING]);
 
-impl LateLintPass<'_> for StrToString {
+impl<'tcx> LateLintPass<'tcx> for StrToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         if_chain! {
             if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind;
@@ -431,7 +431,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
 
 declare_lint_pass!(StringToString => [STRING_TO_STRING]);
 
-impl LateLintPass<'_> for StringToString {
+impl<'tcx> LateLintPass<'tcx> for StringToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
         if_chain! {
             if let ExprKind::MethodCall(path, _, [self_arg, ..], _) = &expr.kind;
index fee01fb0bd186db7999e817c8f3751e0d2cf6d82..d6e948a75607bff1bfcb4da6ab50708febce40db 100644 (file)
@@ -39,7 +39,7 @@
 
 declare_lint_pass!(StrlenOnCStrings => [STRLEN_ON_C_STRINGS]);
 
-impl LateLintPass<'tcx> for StrlenOnCStrings {
+impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             if !expr.span.from_expansion();
index faf43fd9fc1ad536ff934eb4cd1d4d5f116e2931..ca725918e873e3d8269bbf2a978379fe0c259ca1 100644 (file)
@@ -355,7 +355,7 @@ struct BinaryOp<'exprs> {
     right: &'exprs Expr,
 }
 
-impl BinaryOp<'exprs> {
+impl<'exprs> BinaryOp<'exprs> {
     fn new(op: BinOpKind, span: Span, (left, right): (&'exprs Expr, &'exprs Expr)) -> Self {
         Self { op, span, left, right }
     }
@@ -419,7 +419,7 @@ fn chained_binops(kind: &ExprKind) -> Option<Vec<BinaryOp<'_>>> {
     }
 }
 
-fn chained_binops_helper(left_outer: &'expr Expr, right_outer: &'expr Expr) -> Option<Vec<BinaryOp<'expr>>> {
+fn chained_binops_helper<'expr>(left_outer: &'expr Expr, right_outer: &'expr Expr) -> Option<Vec<BinaryOp<'expr>>> {
     match (&left_outer.kind, &right_outer.kind) {
         (
             ExprKind::Paren(ref left_e) | ExprKind::Unary(_, ref left_e),
index a3195de81d15c7415be7d5f95a3626ad1c0ba54a..92494159deeb53029c88592e4d6a7ffe93b24c98 100644 (file)
@@ -66,7 +66,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
             // Check for more than one binary operation in the implemented function
             // Linting when multiple operations are involved can result in false positives
             let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
-            if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get(parent_fn);
+            if let hir::Node::ImplItem(impl_item) = cx.tcx.hir().get_by_def_id(parent_fn);
             if let hir::ImplItemKind::Fn(_, body_id) = impl_item.kind;
             let body = cx.tcx.hir().body(body_id);
             let parent_fn = cx.tcx.hir().get_parent_item(expr.hir_id);
index 47c0a84cd4630ee97a94f3ebfc29f7987ea4e3ff..c9b2ce476e89d0d5cb8408a7b4f0978a3593c5fb 100644 (file)
@@ -53,12 +53,12 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
     }
 }
 
-fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) -> bool {
+fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
     if_chain! {
         // First check if last field is an array
         if let ItemKind::Struct(data, _) = &item.kind;
         if let Some(last_field) = data.fields().last();
-        if let rustc_hir::TyKind::Array(_, length) = last_field.ty.kind;
+        if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind;
 
         // Then check if that that array zero-sized
         let length_ldid = cx.tcx.hir().local_def_id(length.hir_id);
index fb4abceac25e2ccab72372e32f4094c1d8742e81..6369aafe3f9734ec605be603f4eb30d700cace9d 100644 (file)
@@ -1,11 +1,16 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::{snippet, snippet_with_applicability};
-use clippy_utils::SpanlessHash;
+use clippy_utils::{SpanlessEq, SpanlessHash};
+use core::hash::{Hash, Hasher};
 use if_chain::if_chain;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
-use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate};
+use rustc_hir::def::Res;
+use rustc_hir::{
+    GenericBound, Generics, Item, ItemKind, Node, ParamName, Path, PathSegment, QPath, TraitItem, Ty, TyKind,
+    WherePredicate,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
@@ -83,6 +88,53 @@ fn check_generics(&mut self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
         self.check_type_repetition(cx, gen);
         check_trait_bound_duplication(cx, gen);
     }
+
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
+        let Generics { where_clause, .. } = &item.generics;
+        let mut self_bounds_set = FxHashSet::default();
+
+        for predicate in where_clause.predicates {
+            if_chain! {
+                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(
+                    Node::Item(
+                        Item {
+                            kind: ItemKind::Trait(_, _, _, self_bounds, _),
+                            .. }
+                        )
+                    ) = cx.tcx.hir().get_if_local(*def_id);
+                then {
+                    if self_bounds_set.is_empty() {
+                        for bound in self_bounds.iter() {
+                            let Some((self_res, _)) = get_trait_res_span_from_bound(bound) else { continue };
+                            self_bounds_set.insert(self_res);
+                        }
+                    }
+
+                    bound_predicate
+                        .bounds
+                        .iter()
+                        .filter_map(get_trait_res_span_from_bound)
+                        .for_each(|(trait_item_res, span)| {
+                            if self_bounds_set.get(&trait_item_res).is_some() {
+                                span_lint_and_help(
+                                    cx,
+                                    TRAIT_DUPLICATION_IN_BOUNDS,
+                                    span,
+                                    "this trait bound is already specified in trait declaration",
+                                    None,
+                                    "consider removing this trait bound",
+                                );
+                            }
+                        });
+                }
+            }
+        }
+    }
 }
 
 fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)> {
@@ -94,24 +146,40 @@ fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)
 }
 
 impl TraitBounds {
-    fn check_type_repetition(self, cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
+    fn check_type_repetition<'tcx>(self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
+        struct SpanlessTy<'cx, 'tcx> {
+            ty: &'tcx Ty<'tcx>,
+            cx: &'cx LateContext<'tcx>,
+        }
+        impl PartialEq for SpanlessTy<'_, '_> {
+            fn eq(&self, other: &Self) -> bool {
+                let mut eq = SpanlessEq::new(self.cx);
+                eq.inter_expr().eq_ty(self.ty, other.ty)
+            }
+        }
+        impl Hash for SpanlessTy<'_, '_> {
+            fn hash<H: Hasher>(&self, h: &mut H) {
+                let mut t = SpanlessHash::new(self.cx);
+                t.hash_ty(self.ty);
+                h.write_u64(t.finish());
+            }
+        }
+        impl Eq for SpanlessTy<'_, '_> {}
+
         if gen.span.from_expansion() {
             return;
         }
-        let hash = |ty| -> u64 {
-            let mut hasher = SpanlessHash::new(cx);
-            hasher.hash_ty(ty);
-            hasher.finish()
-        };
-        let mut map: UnhashMap<u64, Vec<&GenericBound<'_>>> = UnhashMap::default();
+        let mut map: UnhashMap<SpanlessTy<'_, '_>, Vec<&GenericBound<'_>>> = UnhashMap::default();
         let mut applicability = Applicability::MaybeIncorrect;
         for bound in gen.where_clause.predicates {
             if_chain! {
                 if let WherePredicate::BoundPredicate(ref p) = bound;
                 if p.bounds.len() as u64 <= self.max_trait_bounds;
                 if !p.span.from_expansion();
-                let h = hash(p.bounded_ty);
-                if let Some(ref v) = map.insert(h, p.bounds.iter().collect::<Vec<_>>());
+                if let Some(ref v) = map.insert(
+                    SpanlessTy { ty: p.bounded_ty, cx },
+                    p.bounds.iter().collect::<Vec<_>>()
+                );
 
                 then {
                     let mut hint_string = format!(
index 481e595743585a8ea3ad5794b0dc53a93b4f459c..67cc8913318962f2f849ab1441a166dd7b9d9eaa 100644 (file)
     /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information.
     ///
     /// ### Why is this bad?
-    /// Any `&Box<T>` can also be a `&T`, which is more
-    /// general.
+    /// A `&Box<T>` parameter requires the function caller to box `T` first before passing it to a function.
+    /// Using `&T` defines a concrete type for the parameter and generalizes the function, this would also
+    /// auto-deref to `&T` at the function call site if passed a `&Box<T>`.
     ///
     /// ### Example
     /// ```rust,ignore
@@ -311,12 +312,12 @@ pub struct Types {
 
 impl<'tcx> LateLintPass<'tcx> for Types {
     fn check_fn(&mut self, cx: &LateContext<'_>, _: FnKind<'_>, decl: &FnDecl<'_>, _: &Body<'_>, _: Span, id: HirId) {
-        let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(id))
-        {
-            matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
-        } else {
-            false
-        };
+        let is_in_trait_impl =
+            if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(id)) {
+                matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
+            } else {
+                false
+            };
 
         let is_exported = cx.access_levels.is_exported(cx.tcx.hir().local_def_id(id));
 
@@ -352,7 +353,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>)
         match item.kind {
             ImplItemKind::Const(ty, _) => {
                 let is_in_trait_impl = if let Some(hir::Node::Item(item)) =
-                    cx.tcx.hir().find(cx.tcx.hir().get_parent_item(item.hir_id()))
+                    cx.tcx.hir().find_by_def_id(cx.tcx.hir().get_parent_item(item.hir_id()))
                 {
                     matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
                 } else {
index 3d3b4a6679dd1e445b956a8777b6a6e889c93b8d..697ed267e2f357309961ac1642e4509c00e505a7 100644 (file)
@@ -113,8 +113,8 @@ fn check_block_post(&mut self, _: &LateContext<'_>, _: &'_ Block<'_>) {
     }
 }
 
-impl<'hir> Visitor<'hir> for UndocumentedUnsafeBlocks {
-    type Map = Map<'hir>;
+impl<'v> Visitor<'v> for UndocumentedUnsafeBlocks {
+    type Map = Map<'v>;
 
     fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
         NestedVisitorMap::None
index c58fa67a023881c6a74255f5adb80b6bc9204761..7557e14d11f526917b8faa0da05a3e941c829896 100644 (file)
@@ -36,7 +36,7 @@
 
 declare_lint_pass!(UndroppedManuallyDrops => [UNDROPPED_MANUALLY_DROPS]);
 
-impl LateLintPass<'tcx> for UndroppedManuallyDrops {
+impl<'tcx> LateLintPass<'tcx> for UndroppedManuallyDrops {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let Some([arg_0, ..]) = match_function_call(cx, expr, &paths::DROP) {
             let ty = cx.typeck_results().expr_ty(arg_0);
index 46cc76b150e4a20e5f4b63dd85874c38ce57b987..2ffaf24f942ae705dbd72cf3098b15c73030c6ee 100644 (file)
@@ -78,7 +78,7 @@ fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'_>) {
     }
 }
 
-fn handle_uninit_vec_pair(
+fn handle_uninit_vec_pair<'tcx>(
     cx: &LateContext<'tcx>,
     maybe_init_or_reserve: &'tcx Stmt<'tcx>,
     maybe_set_len: &'tcx Expr<'tcx>,
@@ -196,7 +196,7 @@ fn is_reserve(cx: &LateContext<'_>, path: &PathSegment<'_>, self_expr: &Expr<'_>
 }
 
 /// Returns self if the expression is `Vec::set_len()`
-fn extract_set_len_self(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> {
+fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<(&'tcx Expr<'tcx>, Span)> {
     // peel unsafe blocks in `unsafe { vec.set_len() }`
     let expr = peel_hir_expr_while(expr, |e| {
         if let ExprKind::Block(block, _) = e.kind {
index 26b4e0f58a870beabd074916fad606a8ceb862da..dcf8a9d7c84d39416926d2e4f7f30dd4aa1bb3b3 100644 (file)
@@ -46,7 +46,7 @@
 }
 declare_lint_pass!(UnitHash => [UNIT_HASH]);
 
-impl LateLintPass<'tcx> for UnitHash {
+impl<'tcx> LateLintPass<'tcx> for UnitHash {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if_chain! {
             if let ExprKind::MethodCall(name_ident, _, args, _) = &expr.kind;
index 6d9aff474214c30420508b7390b28d874f2e5f32..1dd8895ebd0763be6dd77e2da8f7f34fd8566030 100644 (file)
@@ -1,35 +1,29 @@
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
 use rustc_hir::{BinOpKind, Expr, ExprKind};
 use rustc_lint::LateContext;
-use rustc_span::hygiene::{ExpnKind, MacroKind};
 
 use super::UNIT_CMP;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
     if expr.span.from_expansion() {
-        if let Some(callee) = expr.span.source_callee() {
-            if let ExpnKind::Macro(MacroKind::Bang, symbol) = callee.kind {
-                if let ExprKind::Binary(ref cmp, left, _) = expr.kind {
-                    let op = cmp.node;
-                    if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() {
-                        let result = match symbol.as_str() {
-                            "assert_eq" | "debug_assert_eq" => "succeed",
-                            "assert_ne" | "debug_assert_ne" => "fail",
-                            _ => return,
-                        };
-                        span_lint(
-                            cx,
-                            UNIT_CMP,
-                            expr.span,
-                            &format!(
-                                "`{}` of unit values detected. This will always {}",
-                                symbol.as_str(),
-                                result
-                            ),
-                        );
-                    }
-                }
+        if let Some(macro_call) = root_macro_call_first_node(cx, expr) {
+            let macro_name = cx.tcx.item_name(macro_call.def_id);
+            let result = match macro_name.as_str() {
+                "assert_eq" | "debug_assert_eq" => "succeed",
+                "assert_ne" | "debug_assert_ne" => "fail",
+                _ => return,
+            };
+            let Some ((left, _, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
+            if !cx.typeck_results().expr_ty(left).is_unit() {
+                return;
             }
+            span_lint(
+                cx,
+                UNIT_CMP,
+                macro_call.span,
+                &format!("`{}` of unit values detected. This will always {}", macro_name, result),
+            );
         }
         return;
     }
index d024577f485317b55bb54acbc35f571bff8bf6d7..32adccdbd1cedea225f47209ea1a97680dc0bc96 100644 (file)
@@ -226,7 +226,7 @@ fn expr_borrows(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
     matches!(ty.kind(), ty::Ref(..))
         || ty
-            .walk(cx.tcx)
+            .walk()
             .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
 }
 
index 004530db0861d28a1373e34b91a3cf82fb23dc14..287ac5b4a90835d162e12b4c9407e29f563e5578 100644 (file)
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::{is_try, match_trait_method, paths};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
     /// partial-write/read, use
     /// `write_all`/`read_exact` instead.
     ///
+    /// When working with asynchronous code (either with the `futures`
+    /// crate or with `tokio`), a similar issue exists for
+    /// `AsyncWriteExt::write()` and `AsyncReadExt::read()` : these
+    /// functions are also not guaranteed to process the entire
+    /// buffer.  Your code should either handle partial-writes/reads, or
+    /// call the `write_all`/`read_exact` methods on those traits instead.
+    ///
     /// ### Known problems
     /// Detects only common patterns.
     ///
-    /// ### Example
+    /// ### Examples
     /// ```rust,ignore
     /// use std::io;
     /// fn foo<W: io::Write>(w: &mut W) -> io::Result<()> {
@@ -68,6 +75,23 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
     }
 }
 
+/// If `expr` is an (e).await, return the inner expression "e" that's being
+/// waited on.  Otherwise return None.
+fn try_remove_await<'a>(expr: &'a hir::Expr<'a>) -> Option<&hir::Expr<'a>> {
+    if let hir::ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind {
+        if let hir::ExprKind::Call(func, [ref arg_0, ..]) = expr.kind {
+            if matches!(
+                func.kind,
+                hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..))
+            ) {
+                return Some(arg_0);
+            }
+        }
+    }
+
+    None
+}
+
 fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
     let mut call = call;
     while let hir::ExprKind::MethodCall(path, _, args, _) = call.kind {
@@ -77,30 +101,69 @@ fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<
             break;
         }
     }
-    check_method_call(cx, call, expr);
+
+    if let Some(call) = try_remove_await(call) {
+        check_method_call(cx, call, expr, true);
+    } else {
+        check_method_call(cx, call, expr, false);
+    }
 }
 
-fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) {
+fn check_method_call(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>, is_await: bool) {
     if let hir::ExprKind::MethodCall(path, _, _, _) = call.kind {
         let symbol = path.ident.as_str();
-        let read_trait = match_trait_method(cx, call, &paths::IO_READ);
-        let write_trait = match_trait_method(cx, call, &paths::IO_WRITE);
+        let read_trait = if is_await {
+            match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCREADEXT)
+                || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCREADEXT)
+        } else {
+            match_trait_method(cx, call, &paths::IO_READ)
+        };
+        let write_trait = if is_await {
+            match_trait_method(cx, call, &paths::FUTURES_IO_ASYNCWRITEEXT)
+                || match_trait_method(cx, call, &paths::TOKIO_IO_ASYNCWRITEEXT)
+        } else {
+            match_trait_method(cx, call, &paths::IO_WRITE)
+        };
 
-        match (read_trait, write_trait, symbol) {
-            (true, _, "read") => span_lint(
+        match (read_trait, write_trait, symbol, is_await) {
+            (true, _, "read", false) => span_lint_and_help(
+                cx,
+                UNUSED_IO_AMOUNT,
+                expr.span,
+                "read amount is not handled",
+                None,
+                "use `Read::read_exact` instead, or handle partial reads",
+            ),
+            (true, _, "read", true) => span_lint_and_help(
                 cx,
                 UNUSED_IO_AMOUNT,
                 expr.span,
-                "read amount is not handled. Use `Read::read_exact` instead",
+                "read amount is not handled",
+                None,
+                "use `AsyncReadExt::read_exact` instead, or handle partial reads",
             ),
-            (true, _, "read_vectored") => span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "read amount is not handled"),
-            (_, true, "write") => span_lint(
+            (true, _, "read_vectored", _) => {
+                span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "read amount is not handled");
+            },
+            (_, true, "write", false) => span_lint_and_help(
                 cx,
                 UNUSED_IO_AMOUNT,
                 expr.span,
-                "written amount is not handled. Use `Write::write_all` instead",
+                "written amount is not handled",
+                None,
+                "use `Write::write_all` instead, or handle partial writes",
             ),
-            (_, true, "write_vectored") => span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "written amount is not handled"),
+            (_, true, "write", true) => span_lint_and_help(
+                cx,
+                UNUSED_IO_AMOUNT,
+                expr.span,
+                "written amount is not handled",
+                None,
+                "use `AsyncWriteExt::write_all` instead, or handle partial writes",
+            ),
+            (_, true, "write_vectored", _) => {
+                span_lint(cx, UNUSED_IO_AMOUNT, expr.span, "written amount is not handled");
+            },
             _ => (),
         }
     }
index aa105580ee354833284b04ca99d6638183018a9b..fd9d5b52e501f318199e5fa94ad9cf55dd79cad6 100644 (file)
@@ -42,7 +42,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem<'_>)
         if impl_item.span.from_expansion() {
             return;
         }
-        let parent = cx.tcx.hir().get_parent_did(impl_item.hir_id());
+        let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id());
         let parent_item = cx.tcx.hir().expect_item(parent);
         let assoc_item = cx.tcx.associated_item(impl_item.def_id);
         if_chain! {
index 059f7f647f88f0e0f486a400a4608b6fbf422884..cf9a4a5e6d37d7d1c32a4ccdae3e26f7c9485e89 100644 (file)
@@ -13,7 +13,6 @@
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::map::Map;
-use rustc_middle::ty::AssocKind;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
@@ -143,10 +142,10 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
                 // trait, not in the impl of the trait.
                 let trait_method = cx
                     .tcx
-                    .associated_items(impl_trait_ref.def_id)
-                    .find_by_name_and_kind(cx.tcx, impl_item.ident, AssocKind::Fn, impl_trait_ref.def_id)
+                    .associated_item(impl_item.def_id)
+                    .trait_item_def_id
                     .expect("impl method matches a trait method");
-                let trait_method_sig = cx.tcx.fn_sig(trait_method.def_id);
+                let trait_method_sig = cx.tcx.fn_sig(trait_method);
                 let trait_method_sig = cx.tcx.erase_late_bound_regions(trait_method_sig);
 
                 // `impl_inputs_outputs` is an iterator over the types (`hir::Ty`) declared in the
@@ -171,7 +170,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_
                 //
                 // See also https://github.com/rust-lang/rust-clippy/issues/2894.
                 for (impl_hir_ty, trait_sem_ty) in impl_inputs_outputs.zip(trait_method_sig.inputs_and_output) {
-                    if trait_sem_ty.walk(cx.tcx).any(|inner| inner == self_ty.into()) {
+                    if trait_sem_ty.walk().any(|inner| inner == self_ty.into()) {
                         let mut visitor = SkipTyCollector::default();
                         visitor.visit_ty(impl_hir_ty);
                         types_to_skip.extend(visitor.types_to_skip);
index c1b811c2174405ca3c11e7bd68e90d545999b26f..7751c593e435a3410d52c139bf286b8c79dfb22e 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_ast::LitIntType;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
-use rustc_hir::{ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
+use rustc_hir::{ArrayLen, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::{Ident, Symbol};
@@ -567,7 +567,14 @@ macro_rules! kind {
                 bind!(self, value, length);
                 kind!("Repeat({value}, {length})");
                 self.expr(value);
-                self.body(field!(length.body));
+                match length.value {
+                    ArrayLen::Infer(..) => out!("if let ArrayLen::Infer(..) = length;"),
+                    ArrayLen::Body(anon_const) => {
+                        bind!(self, anon_const);
+                        out!("if let ArrayLen::Body({anon_const}) = {length};");
+                        self.body(field!(anon_const.body));
+                    },
+                }
             },
             ExprKind::Err => kind!("Err"),
             ExprKind::DropTemps(expr) => {
index 9c83d30eb9cc1a0a691810ff7568a5a6c50bff31..d6deb50cc907379f7b66b633c8eaf77b298976a4 100644 (file)
@@ -23,6 +23,14 @@ pub enum DisallowedMethod {
     WithReason { path: String, reason: Option<String> },
 }
 
+impl DisallowedMethod {
+    pub fn path(&self) -> &str {
+        let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
+
+        path
+    }
+}
+
 /// A single disallowed type, used by the `DISALLOWED_TYPES` lint.
 #[derive(Clone, Debug, Deserialize)]
 #[serde(untagged)]
@@ -113,7 +121,7 @@ fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapA
             }
         }
 
-        #[cfg(feature = "metadata-collector-lint")]
+        #[cfg(feature = "internal")]
         pub mod metadata {
             use crate::utils::internal_lints::metadata_collector::ClippyConfiguration;
 
index abf4826a06917bc5991b4d2514e025ac90d30f20..e90b6b73b34208c2283e480d3a18cde80d117765 100644 (file)
@@ -334,12 +334,17 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
             println!("{}anon_const:", ind);
             print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
         },
-        hir::ExprKind::Repeat(val, ref anon_const) => {
+        hir::ExprKind::Repeat(val, length) => {
             println!("{}Repeat", ind);
             println!("{}value:", ind);
             print_expr(cx, val, indent + 1);
             println!("{}repeat count:", ind);
-            print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
+            match length {
+                hir::ArrayLen::Infer(_, _) => println!("{}repeat count: _", ind),
+                hir::ArrayLen::Body(anon_const) => {
+                    print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
+                },
+            }
         },
         hir::ExprKind::Err => {
             println!("{}Err", ind);
index e98dcd3cf983b721905c555cb9f2c2aceef18d4d..9c3dcc8e96a0644698ce5a915fdb5e72c1d8a534 100644 (file)
@@ -1,5 +1,6 @@
 use clippy_utils::consts::{constant_simple, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::match_type;
 use clippy_utils::{
@@ -34,7 +35,7 @@
 
 use std::borrow::{Borrow, Cow};
 
-#[cfg(feature = "metadata-collector-lint")]
+#[cfg(feature = "internal")]
 pub mod metadata_collector;
 
 declare_clippy_lint! {
@@ -410,9 +411,13 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
                 }
                 self.declared_lints.insert(item.ident.name, item.span);
             }
-        } else if is_expn_of(item.span, "impl_lint_pass").is_some()
-            || is_expn_of(item.span, "declare_lint_pass").is_some()
-        {
+        } else if let Some(macro_call) = root_macro_call_first_node(cx, item) {
+            if !matches!(
+                &*cx.tcx.item_name(macro_call.def_id).as_str(),
+                "impl_lint_pass" | "declare_lint_pass"
+            ) {
+                return;
+            }
             if let hir::ItemKind::Impl(hir::Impl {
                 of_trait: None,
                 items: impl_item_refs,
@@ -924,9 +929,20 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
         let lang_item_path = cx.get_def_path(*item_def_id);
         if path_syms.starts_with(&lang_item_path) {
             if let [item] = &path_syms[lang_item_path.len()..] {
-                for child in cx.tcx.item_children(*item_def_id) {
-                    if child.ident.name == *item {
-                        return true;
+                if matches!(
+                    cx.tcx.def_kind(*item_def_id),
+                    DefKind::Mod | DefKind::Enum | DefKind::Trait
+                ) {
+                    for child in cx.tcx.module_children(*item_def_id) {
+                        if child.ident.name == *item {
+                            return true;
+                        }
+                    }
+                } else {
+                    for child in cx.tcx.associated_item_def_ids(*item_def_id) {
+                        if cx.tcx.item_name(*child) == *item {
+                            return true;
+                        }
                     }
                 }
             }
@@ -984,7 +1000,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() {
-                for item in cx.tcx.item_children(def_id).iter() {
+                for item in cx.tcx.module_children(def_id).iter() {
                     if_chain! {
                         if let Res::Def(DefKind::Const, item_def_id) = item.res;
                         let ty = cx.tcx.type_of(item_def_id);
index 7707eebd6223e2cb01ab4b0b4bd559ab3fc7aa6c..4e46d79dc087047aca119d05c2d603a53b8b10bf 100644 (file)
@@ -1,8 +1,7 @@
 //! This lint is used to collect metadata about clippy lints. This metadata is exported as a json
 //! file and then used to generate the [clippy lint list](https://rust-lang.github.io/rust-clippy/master/index.html)
 //!
-//! This module and therefor the entire lint is guarded by a feature flag called
-//! `metadata-collector-lint`
+//! This module and therefore the entire lint is guarded by a feature flag called `internal`
 //!
 //! The module transforms all lint names to ascii lowercase to ensure that we don't have mismatches
 //! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such
@@ -578,7 +577,7 @@ fn get_lint_version(cx: &LateContext<'_>, item: &Item<'_>) -> String {
 fn get_lint_group_and_level_or_lint(
     cx: &LateContext<'_>,
     lint_name: &str,
-    item: &'hir Item<'_>,
+    item: &Item<'_>,
 ) -> Option<(String, &'static str)> {
     let result = cx
         .lint_store
@@ -697,20 +696,20 @@ fn extract_emission_info<'hir>(
 }
 
 /// Resolves the possible lints that this expression could reference
-fn resolve_lints(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec<String> {
+fn resolve_lints<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Vec<String> {
     let mut resolver = LintResolver::new(cx);
     resolver.visit_expr(expr);
     resolver.lints
 }
 
 /// This function tries to resolve the linked applicability to the given expression.
-fn resolve_applicability(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<usize> {
+fn resolve_applicability<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<usize> {
     let mut resolver = ApplicabilityResolver::new(cx);
     resolver.visit_expr(expr);
     resolver.complete()
 }
 
-fn check_is_multi_part(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hir>) -> bool {
+fn check_is_multi_part<'hir>(cx: &LateContext<'hir>, closure_expr: &'hir hir::Expr<'hir>) -> bool {
     if let ExprKind::Closure(_, _, body_id, _, _) = closure_expr.kind {
         let mut scanner = IsMultiSpanScanner::new(cx);
         intravisit::walk_body(&mut scanner, cx.tcx.hir().body(body_id));
@@ -825,7 +824,7 @@ fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
 }
 
 /// This returns the parent local node if the expression is a reference one
-fn get_parent_local(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> {
+fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Option<&'hir hir::Local<'hir>> {
     if let ExprKind::Path(QPath::Resolved(_, path)) = expr.kind {
         if let hir::def::Res::Local(local_hir) = path.res {
             return get_parent_local_hir_id(cx, local_hir);
@@ -835,7 +834,7 @@ fn get_parent_local(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -> Opti
     None
 }
 
-fn get_parent_local_hir_id(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
+fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
     let map = cx.tcx.hir();
 
     match map.find(map.get_parent_node(hir_id)) {
index b67448e3a57406be07c7589baec3e72f17a964b2..dc385ebacba664db68ea0ed564508f9ef7a312cb 100644 (file)
@@ -1,5 +1,5 @@
 pub mod author;
 pub mod conf;
 pub mod inspector;
-#[cfg(any(feature = "internal-lints", feature = "metadata-collector-lint"))]
+#[cfg(feature = "internal")]
 pub mod internal_lints;
index 1bc0eb6303c01f692c04d08fdf29f94e86fecf0a..43474da3450e2bd1e7641ed96d743c73f28439db 100644 (file)
@@ -77,7 +77,7 @@ fn display_err(&self, cx: &LateContext<'_>) {
     }
 }
 
-impl LateLintPass<'_> for VecInitThenPush {
+impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
     fn check_block(&mut self, _: &LateContext<'tcx>, _: &'tcx Block<'tcx>) {
         self.searcher = None;
     }
index eb8436a501d54b057010db4c95b6f67a68a9452e..70b0560e676044eef19feef0cff8f9733f5394d8 100644 (file)
@@ -69,7 +69,11 @@ fn check_ty(&mut self, cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>) {
 
 fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     let parent_id = cx.tcx.hir().get_parent_item(hir_id);
-    if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_item(parent_id)) {
+    let second_parent_id = cx
+        .tcx
+        .hir()
+        .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(parent_id));
+    if let Some(Node::Item(item)) = cx.tcx.hir().find_by_def_id(second_parent_id) {
         if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind {
             return true;
         }
index 0ba0b59ed13daf6f93653f554b03f6a4d0a0076f..afff6491aba6420b39febc824702f9776656170f 100644 (file)
@@ -1,17 +1,17 @@
 [package]
 name = "clippy_utils"
-version = "0.1.59"
+version = "0.1.60"
 edition = "2021"
 publish = false
 
 [dependencies]
+arrayvec = { version = "0.7", default-features = false }
 if_chain = "1.0"
 rustc-semver = "1.1"
 
 [features]
 deny-warnings = []
-internal-lints = []
-metadata-collector-lint = []
+internal = []
 
 [package.metadata.rust-analyzer]
 # This crate uses #[feature(rustc_private)]
index 8400bfbbd99d2550d09021754a61ffc8e4cf5f9b..3d3180521ab7a2fcb533727a1ed8a43a84971cf7 100644 (file)
@@ -5,7 +5,6 @@
 #![allow(clippy::similar_names, clippy::wildcard_imports, clippy::enum_glob_use)]
 
 use crate::{both, over};
-use if_chain::if_chain;
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, *};
 use rustc_span::symbol::Ident;
@@ -679,34 +678,3 @@ pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool {
         _ => false,
     }
 }
-
-/// Extract args from an assert-like macro.
-///
-/// Currently working with:
-/// - `assert_eq!` and `assert_ne!`
-/// - `debug_assert_eq!` and `debug_assert_ne!`
-///
-/// For example:
-///
-/// `debug_assert_eq!(a, b)` will return Some([a, b])
-pub fn extract_assert_macro_args(mut expr: &Expr) -> Option<[&Expr; 2]> {
-    if_chain! {
-        if let ExprKind::If(_, ref block, _) = expr.kind;
-        if let StmtKind::Semi(ref e) = block.stmts.get(0)?.kind;
-        then {
-            expr = e;
-        }
-    }
-    if_chain! {
-        if let ExprKind::Block(ref block, _) = expr.kind;
-        if let StmtKind::Expr(ref expr) = block.stmts.get(0)?.kind;
-        if let ExprKind::Match(ref match_expr, _) = expr.kind;
-        if let ExprKind::Tup(ref tup) = match_expr.kind;
-        if let [a, b, ..] = tup.as_slice();
-        if let (&ExprKind::AddrOf(_, _, ref a), &ExprKind::AddrOf(_, _, ref b)) = (&a.kind, &b.kind);
-        then {
-            return Some([&*a, &*b]);
-        }
-    }
-    None
-}
index 5c024612f8eba85711aa188d834b663c58a3790f..e09a663538ddcfeff5899eae3d0af5155b6a2340 100644 (file)
@@ -223,7 +223,7 @@ pub fn constant_simple<'tcx>(
     constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) })
 }
 
-pub fn constant_full_int(
+pub fn constant_full_int<'tcx>(
     lcx: &LateContext<'tcx>,
     typeck_results: &ty::TypeckResults<'tcx>,
     e: &Expr<'_>,
@@ -413,7 +413,10 @@ fn fetch_path(&mut self, qpath: &QPath<'_>, id: HirId, ty: Ty<'tcx>) -> Option<C
                     .tcx
                     .const_eval_resolve(
                         self.param_env,
-                        ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs),
+                        ty::Unevaluated::new(
+                            ty::WithOptConstParam::unknown(def_id),
+                            substs,
+                        ),
                         None,
                     )
                     .ok()
index d47b002ad7aca95a94336ac60e6b6f511913d3b4..ca222c3d669956d4b97eb5e4bd9f46ead9aa0d1d 100644 (file)
@@ -198,7 +198,7 @@ pub fn span_lint_hir_and_then(
 ///     |
 ///     = note: `-D fold-any` implied by `-D warnings`
 /// ```
-#[cfg_attr(feature = "internal-lints", allow(clippy::collapsible_span_lint_calls))]
+#[cfg_attr(feature = "internal", allow(clippy::collapsible_span_lint_calls))]
 pub fn span_lint_and_sugg<'a, T: LintContext>(
     cx: &'a T,
     lint: &'static Lint,
index 61e529a6079c935b65c3345b68dffaf5fded8f9e..c3936ec95d46dc077edb1a1e6d251005be252142 100644 (file)
@@ -45,7 +45,12 @@ fn bitor_assign(&mut self, rhs: Self) {
 }
 
 /// Determine the eagerness of the given function call.
-fn fn_eagerness(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, args: &'tcx [Expr<'_>]) -> EagernessSuggestion {
+fn fn_eagerness<'tcx>(
+    cx: &LateContext<'tcx>,
+    fn_id: DefId,
+    name: Symbol,
+    args: &'tcx [Expr<'_>],
+) -> EagernessSuggestion {
     use EagernessSuggestion::{Eager, Lazy, NoChange};
     let name = name.as_str();
 
@@ -92,7 +97,7 @@ fn fn_eagerness(cx: &LateContext<'tcx>, fn_id: DefId, name: Symbol, args: &'tcx
 }
 
 #[allow(clippy::too_many_lines)]
-fn expr_eagerness(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggestion {
+fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessSuggestion {
     struct V<'cx, 'tcx> {
         cx: &'cx LateContext<'tcx>,
         eagerness: EagernessSuggestion,
@@ -225,11 +230,11 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
 }
 
 /// Whether the given expression should be changed to evaluate eagerly
-pub fn switch_to_eager_eval(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
+pub fn switch_to_eager_eval<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
     expr_eagerness(cx, expr) == EagernessSuggestion::Eager
 }
 
 /// Whether the given expression should be changed to evaluate lazily
-pub fn switch_to_lazy_eval(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
+pub fn switch_to_lazy_eval<'tcx>(cx: &'_ LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
     expr_eagerness(cx, expr) == EagernessSuggestion::Lazy
 }
index c764c35d444fb4ec1c96512a7a5969283e054838..160a51740cd7cde24cf8f31fa13a52fb02925ff8 100644 (file)
@@ -3,15 +3,13 @@
 #![deny(clippy::missing_docs_in_private_items)]
 
 use crate::ty::is_type_diagnostic_item;
-use crate::{is_expn_of, last_path_segment, match_def_path, paths};
+use crate::{is_expn_of, match_def_path, paths};
 use if_chain::if_chain;
 use rustc_ast::ast::{self, LitKind};
 use rustc_hir as hir;
-use rustc_hir::{
-    Arm, Block, BorrowKind, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath, StmtKind, UnOp,
-};
+use rustc_hir::{Arm, Block, Expr, ExprKind, HirId, LoopSource, MatchSource, Node, Pat, QPath};
 use rustc_lint::LateContext;
-use rustc_span::{sym, symbol, ExpnKind, Span, Symbol};
+use rustc_span::{sym, symbol, Span};
 
 /// The essential nodes of a desugared for loop as well as the entire span:
 /// `for pat in arg { body }` becomes `(pat, arg, body)`. Return `(pat, arg, body, span)`.
@@ -428,293 +426,6 @@ pub fn binop(op: hir::BinOpKind) -> ast::BinOpKind {
     }
 }
 
-/// Extract args from an assert-like macro.
-/// Currently working with:
-/// - `assert!`, `assert_eq!` and `assert_ne!`
-/// - `debug_assert!`, `debug_assert_eq!` and `debug_assert_ne!`
-/// For example:
-/// `assert!(expr)` will return `Some([expr])`
-/// `debug_assert_eq!(a, b)` will return `Some([a, b])`
-pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx Expr<'tcx>>> {
-    /// Try to match the AST for a pattern that contains a match, for example when two args are
-    /// compared
-    fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> {
-        if_chain! {
-            if let ExprKind::Match(headerexpr, _, _) = &matchblock_expr.kind;
-            if let ExprKind::Tup([lhs, rhs]) = &headerexpr.kind;
-            if let ExprKind::AddrOf(BorrowKind::Ref, _, lhs) = lhs.kind;
-            if let ExprKind::AddrOf(BorrowKind::Ref, _, rhs) = rhs.kind;
-            then {
-                return Some(vec![lhs, rhs]);
-            }
-        }
-        None
-    }
-
-    if let ExprKind::Block(block, _) = e.kind {
-        if block.stmts.len() == 1 {
-            if let StmtKind::Semi(matchexpr) = block.stmts.get(0)?.kind {
-                // macros with unique arg: `{debug_}assert!` (e.g., `debug_assert!(some_condition)`)
-                if_chain! {
-                    if let Some(If { cond, .. }) = If::hir(matchexpr);
-                    if let ExprKind::Unary(UnOp::Not, condition) = cond.kind;
-                    then {
-                        return Some(vec![condition]);
-                    }
-                }
-
-                // debug macros with two args: `debug_assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
-                if_chain! {
-                    if let ExprKind::Block(matchblock,_) = matchexpr.kind;
-                    if let Some(matchblock_expr) = matchblock.expr;
-                    then {
-                        return ast_matchblock(matchblock_expr);
-                    }
-                }
-            }
-        } else if let Some(matchblock_expr) = block.expr {
-            // macros with two args: `assert_{ne, eq}` (e.g., `assert_ne!(a, b)`)
-            return ast_matchblock(matchblock_expr);
-        }
-    }
-    None
-}
-
-/// A parsed `format!` expansion
-pub struct FormatExpn<'tcx> {
-    /// Span of `format!(..)`
-    pub call_site: Span,
-    /// Inner `format_args!` expansion
-    pub format_args: FormatArgsExpn<'tcx>,
-}
-
-impl FormatExpn<'tcx> {
-    /// Parses an expanded `format!` invocation
-    pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
-        if_chain! {
-            if let ExprKind::Block(block, _) = expr.kind;
-            if let [stmt] = block.stmts;
-            if let StmtKind::Local(local) = stmt.kind;
-            if let Some(init) = local.init;
-            if let ExprKind::Call(_, [format_args]) = init.kind;
-            let expn_data = expr.span.ctxt().outer_expn_data();
-            if let ExpnKind::Macro(_, sym::format) = expn_data.kind;
-            if let Some(format_args) = FormatArgsExpn::parse(format_args);
-            then {
-                Some(FormatExpn {
-                    call_site: expn_data.call_site,
-                    format_args,
-                })
-            } else {
-                None
-            }
-        }
-    }
-}
-
-/// A parsed `format_args!` expansion
-pub struct FormatArgsExpn<'tcx> {
-    /// Span of the first argument, the format string
-    pub format_string_span: Span,
-    /// Values passed after the format string
-    pub value_args: Vec<&'tcx Expr<'tcx>>,
-
-    /// String literal expressions which represent the format string split by "{}"
-    pub format_string_parts: &'tcx [Expr<'tcx>],
-    /// Symbols corresponding to [`Self::format_string_parts`]
-    pub format_string_symbols: Vec<Symbol>,
-    /// Expressions like `ArgumentV1::new(arg0, Debug::fmt)`
-    pub args: &'tcx [Expr<'tcx>],
-    /// The final argument passed to `Arguments::new_v1_formatted`, if applicable
-    pub fmt_expr: Option<&'tcx Expr<'tcx>>,
-}
-
-impl FormatArgsExpn<'tcx> {
-    /// Parses an expanded `format_args!` or `format_args_nl!` invocation
-    pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
-        if_chain! {
-            if let ExpnKind::Macro(_, name) = expr.span.ctxt().outer_expn_data().kind;
-            let name = name.as_str();
-            if name.ends_with("format_args") || name.ends_with("format_args_nl");
-            if let ExprKind::Call(_, args) = expr.kind;
-            if let Some((strs_ref, args, fmt_expr)) = match args {
-                // Arguments::new_v1
-                [strs_ref, args] => Some((strs_ref, args, None)),
-                // Arguments::new_v1_formatted
-                [strs_ref, args, fmt_expr, _unsafe_arg] => Some((strs_ref, args, Some(fmt_expr))),
-                _ => None,
-            };
-            if let ExprKind::AddrOf(BorrowKind::Ref, _, strs_arr) = strs_ref.kind;
-            if let ExprKind::Array(format_string_parts) = strs_arr.kind;
-            if let Some(format_string_symbols) = format_string_parts
-                .iter()
-                .map(|e| {
-                    if let ExprKind::Lit(lit) = &e.kind {
-                        if let LitKind::Str(symbol, _style) = lit.node {
-                            return Some(symbol);
-                        }
-                    }
-                    None
-                })
-                .collect();
-            if let ExprKind::AddrOf(BorrowKind::Ref, _, args) = args.kind;
-            if let ExprKind::Match(args, [arm], _) = args.kind;
-            if let ExprKind::Tup(value_args) = args.kind;
-            if let Some(value_args) = value_args
-                .iter()
-                .map(|e| match e.kind {
-                    ExprKind::AddrOf(_, _, e) => Some(e),
-                    _ => None,
-                })
-                .collect();
-            if let ExprKind::Array(args) = arm.body.kind;
-            then {
-                Some(FormatArgsExpn {
-                    format_string_span: strs_ref.span,
-                    value_args,
-                    format_string_parts,
-                    format_string_symbols,
-                    args,
-                    fmt_expr,
-                })
-            } else {
-                None
-            }
-        }
-    }
-
-    /// Returns a vector of `FormatArgsArg`.
-    pub fn args(&self) -> Option<Vec<FormatArgsArg<'tcx>>> {
-        if let Some(expr) = self.fmt_expr {
-            if_chain! {
-                if let ExprKind::AddrOf(BorrowKind::Ref, _, expr) = expr.kind;
-                if let ExprKind::Array(exprs) = expr.kind;
-                then {
-                    exprs.iter().map(|fmt| {
-                        if_chain! {
-                            // struct `core::fmt::rt::v1::Argument`
-                            if let ExprKind::Struct(_, fields, _) = fmt.kind;
-                            if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position);
-                            if let ExprKind::Lit(lit) = &position_field.expr.kind;
-                            if let LitKind::Int(position, _) = lit.node;
-                            if let Ok(i) = usize::try_from(position);
-                            let arg = &self.args[i];
-                            if let ExprKind::Call(_, [arg_name, _]) = arg.kind;
-                            if let ExprKind::Field(_, j) = arg_name.kind;
-                            if let Ok(j) = j.name.as_str().parse::<usize>();
-                            then {
-                                Some(FormatArgsArg { value: self.value_args[j], arg, fmt: Some(fmt) })
-                            } else {
-                                None
-                            }
-                        }
-                    }).collect()
-                } else {
-                    None
-                }
-            }
-        } else {
-            Some(
-                self.value_args
-                    .iter()
-                    .zip(self.args.iter())
-                    .map(|(value, arg)| FormatArgsArg { value, arg, fmt: None })
-                    .collect(),
-            )
-        }
-    }
-}
-
-/// Type representing a `FormatArgsExpn`'s format arguments
-pub struct FormatArgsArg<'tcx> {
-    /// An element of `value_args` according to `position`
-    pub value: &'tcx Expr<'tcx>,
-    /// An element of `args` according to `position`
-    pub arg: &'tcx Expr<'tcx>,
-    /// An element of `fmt_expn`
-    pub fmt: Option<&'tcx Expr<'tcx>>,
-}
-
-impl<'tcx> FormatArgsArg<'tcx> {
-    /// Returns true if any formatting parameters are used that would have an effect on strings,
-    /// like `{:+2}` instead of just `{}`.
-    pub fn has_string_formatting(&self) -> bool {
-        self.fmt.map_or(false, |fmt| {
-            // `!` because these conditions check that `self` is unformatted.
-            !if_chain! {
-                // struct `core::fmt::rt::v1::Argument`
-                if let ExprKind::Struct(_, fields, _) = fmt.kind;
-                if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
-                // struct `core::fmt::rt::v1::FormatSpec`
-                if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind;
-                let mut precision_found = false;
-                let mut width_found = false;
-                if subfields.iter().all(|field| {
-                    match field.ident.name {
-                        sym::precision => {
-                            precision_found = true;
-                            if let ExprKind::Path(ref precision_path) = field.expr.kind {
-                                last_path_segment(precision_path).ident.name == sym::Implied
-                            } else {
-                                false
-                            }
-                        }
-                        sym::width => {
-                            width_found = true;
-                            if let ExprKind::Path(ref width_qpath) = field.expr.kind {
-                                last_path_segment(width_qpath).ident.name == sym::Implied
-                            } else {
-                                false
-                            }
-                        }
-                        _ => true,
-                    }
-                });
-                if precision_found && width_found;
-                then { true } else { false }
-            }
-        })
-    }
-
-    /// Returns true if the argument is formatted using `Display::fmt`.
-    pub fn is_display(&self) -> bool {
-        if_chain! {
-            if let ExprKind::Call(_, [_, format_field]) = self.arg.kind;
-            if let ExprKind::Path(QPath::Resolved(_, path)) = format_field.kind;
-            if let [.., t, _] = path.segments;
-            if t.ident.name == sym::Display;
-            then { true } else { false }
-        }
-    }
-}
-
-/// A parsed `panic!` expansion
-pub struct PanicExpn<'tcx> {
-    /// Span of `panic!(..)`
-    pub call_site: Span,
-    /// Inner `format_args!` expansion
-    pub format_args: FormatArgsExpn<'tcx>,
-}
-
-impl PanicExpn<'tcx> {
-    /// Parses an expanded `panic!` invocation
-    pub fn parse(expr: &'tcx Expr<'tcx>) -> Option<Self> {
-        if_chain! {
-            if let ExprKind::Call(_, [format_args]) = expr.kind;
-            let expn_data = expr.span.ctxt().outer_expn_data();
-            if let Some(format_args) = FormatArgsExpn::parse(format_args);
-            then {
-                Some(PanicExpn {
-                    call_site: expn_data.call_site,
-                    format_args,
-                })
-            } else {
-                None
-            }
-        }
-    }
-}
-
 /// A parsed `Vec` initialization expression
 #[derive(Clone, Copy)]
 pub enum VecInitKind {
index ad50759effaf85d2f65d2ee330986631b674abe9..5a08a411dd13f5bc338ae60e3f7d6c29c1675eb9 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_hir::def::Res;
 use rustc_hir::HirIdMap;
 use rustc_hir::{
-    BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
+    ArrayLen, BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId,
     InlineAsmOperand, Let, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt,
     StmtKind, Ty, TyKind, TypeBinding,
 };
@@ -170,6 +170,14 @@ fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
         }
     }
 
+    pub fn eq_array_length(&mut self, left: ArrayLen, right: ArrayLen) -> bool {
+        match (left, right) {
+            (ArrayLen::Infer(..), ArrayLen::Infer(..)) => true,
+            (ArrayLen::Body(l_ct), ArrayLen::Body(r_ct)) => self.eq_body(l_ct.body, r_ct.body),
+            (_, _) => false,
+        }
+    }
+
     pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool {
         let cx = self.inner.cx;
         let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value);
@@ -194,8 +202,8 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
         }
 
         let is_eq = match (
-            &reduce_exprkind(self.inner.cx, &left.kind),
-            &reduce_exprkind(self.inner.cx, &right.kind),
+            reduce_exprkind(self.inner.cx, &left.kind),
+            reduce_exprkind(self.inner.cx, &right.kind),
         ) {
             (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => {
                 lb == rb && l_mut == r_mut && self.eq_expr(le, re)
@@ -232,7 +240,7 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
             },
             (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
             (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
-                self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r))
+                self.eq_expr(lc, rc) && self.eq_expr(lt, rt) && both(le, re, |l, r| self.eq_expr(l, r))
             },
             (&ExprKind::Let(l), &ExprKind::Let(r)) => {
                 self.eq_pat(l.pat, r.pat) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) && self.eq_expr(l.init, r.init)
@@ -253,8 +261,8 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
             (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => {
                 self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args)
             },
-            (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => {
-                self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body)
+            (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => {
+                self.eq_expr(le, re) && self.eq_array_length(ll, rl)
             },
             (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)),
             (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r),
@@ -388,12 +396,10 @@ pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_
     }
 
     #[allow(clippy::similar_names)]
-    fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
+    pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
         match (&left.kind, &right.kind) {
             (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
-            (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => {
-                self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body)
-            },
+            (&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => self.eq_ty(lt, rt) && self.eq_array_length(ll, rl),
             (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => {
                 l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty)
             },
@@ -714,9 +720,9 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
             ExprKind::ConstBlock(ref l_id) => {
                 self.hash_body(l_id.body);
             },
-            ExprKind::Repeat(e, ref l_id) => {
+            ExprKind::Repeat(e, len) => {
                 self.hash_expr(e);
-                self.hash_body(l_id.body);
+                self.hash_array_length(len);
             },
             ExprKind::Ret(ref e) => {
                 if let Some(e) = *e {
@@ -845,6 +851,8 @@ pub fn hash_pat(&mut self, pat: &Pat<'_>) {
     pub fn hash_path(&mut self, path: &Path<'_>) {
         match path.res {
             // constant hash since equality is dependant on inter-expression context
+            // e.g. The expressions `if let Some(x) = foo() {}` and `if let Some(y) = foo() {}` are considered equal
+            // even though the binding names are different and they have different `HirId`s.
             Res::Local(_) => 1_usize.hash(&mut self.s),
             _ => {
                 for seg in path.segments {
@@ -906,9 +914,9 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
             TyKind::Slice(ty) => {
                 self.hash_ty(ty);
             },
-            TyKind::Array(ty, anon_const) => {
+            &TyKind::Array(ty, len) => {
                 self.hash_ty(ty);
-                self.hash_body(anon_const.body);
+                self.hash_array_length(len);
             },
             TyKind::Ptr(ref mut_ty) => {
                 self.hash_ty(mut_ty.ty);
@@ -953,6 +961,13 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
         }
     }
 
+    pub fn hash_array_length(&mut self, length: ArrayLen) {
+        match length {
+            ArrayLen::Infer(..) => {},
+            ArrayLen::Body(anon_const) => self.hash_body(anon_const.body),
+        }
+    }
+
     pub fn hash_body(&mut self, body_id: BodyId) {
         // swap out TypeckResults when hashing a body
         let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body_id));
index 54d470ca738201c0a783cc6599de3bf42eb4c32b..c11594002702652576476437e290c357d7ce5cc8 100644 (file)
@@ -1,6 +1,5 @@
 #![feature(box_patterns)]
 #![feature(control_flow_enum)]
-#![feature(in_band_lifetimes)]
 #![feature(let_else)]
 #![feature(once_cell)]
 #![feature(rustc_private)]
@@ -44,6 +43,7 @@
 pub mod eager_or_lazy;
 pub mod higher;
 mod hir_utils;
+pub mod macros;
 pub mod msrvs;
 pub mod numeric_literal;
 pub mod paths;
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::hir_id::{HirIdMap, HirIdSet};
 use rustc_hir::intravisit::{walk_expr, ErasedMap, FnKind, NestedVisitorMap, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk};
 use rustc_hir::{
-    def, Arm, 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, TraitItem,
-    TraitItemKind, TraitRef, TyKind, UnOp,
+    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,
 };
 use rustc_lint::{LateContext, Level, Lint, LintContext};
-use rustc_middle::hir::exports::Export;
 use rustc_middle::hir::map::Map;
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::ty as rustc_ty;
@@ -91,7 +90,6 @@
 use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture};
 use rustc_semver::RustcVersion;
 use rustc_session::Session;
-use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::{ExpnKind, MacroKind};
 use rustc_span::source_map::original_sp;
 use rustc_span::sym;
@@ -127,7 +125,7 @@ macro_rules! extract_msrv_attr {
         extract_msrv_attr!(@EarlyContext);
     };
     (@$context:ident$(, $call:tt)?) => {
-        fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [rustc_ast::ast::Attribute]) {
+        fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
             use $crate::get_unique_inner_attr;
             match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") {
                 Some(msrv_attr) => {
@@ -147,13 +145,6 @@ fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'tcx>, attrs: &'tcx [ru
     };
 }
 
-/// Returns `true` if the span comes from a macro expansion, no matter if from a
-/// macro by example or from a procedural macro
-#[must_use]
-pub fn in_macro(span: Span) -> bool {
-    span.from_expansion() && !matches!(span.ctxt().outer_expn_data().kind, ExpnKind::Desugaring(..))
-}
-
 /// Returns `true` if the two spans come from differing expansions (i.e., one is
 /// from a macro and one isn't).
 #[must_use]
@@ -224,7 +215,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<
 /// ```
 pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool {
     let parent_id = cx.tcx.hir().get_parent_item(id);
-    match cx.tcx.hir().get(parent_id) {
+    match cx.tcx.hir().get_by_def_id(parent_id) {
         Node::Item(&Item {
             kind: ItemKind::Const(..) | ItemKind::Static(..),
             ..
@@ -283,7 +274,11 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
 }
 
 /// Checks if the first type parameter is a lang item.
-pub fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: LangItem) -> Option<&'tcx hir::Ty<'tcx>> {
+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 {
@@ -299,7 +294,7 @@ pub fn is_ty_param_lang_item(cx: &LateContext<'_>, qpath: &QPath<'tcx>, item: La
 }
 
 /// Checks if the first type parameter is a diagnostic item.
-pub fn is_ty_param_diagnostic_item(
+pub fn is_ty_param_diagnostic_item<'tcx>(
     cx: &LateContext<'_>,
     qpath: &QPath<'tcx>,
     item: Symbol,
@@ -376,7 +371,7 @@ pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
     }
 }
 
-pub fn get_qpath_generics(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'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,
@@ -384,7 +379,7 @@ pub fn get_qpath_generics(path: &QPath<'tcx>) -> Option<&'tcx GenericArgs<'tcx>>
     }
 }
 
-pub fn get_qpath_generic_tys(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx hir::Ty<'tcx>> {
+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)
         .iter()
@@ -523,35 +518,59 @@ macro_rules! try_res {
             }
         };
     }
-    fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<&'tcx Export> {
-        tcx.item_children(def_id)
+    fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Option<Res> {
+        match tcx.def_kind(def_id) {
+            DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx
+                .module_children(def_id)
+                .iter()
+                .find(|item| item.ident.name.as_str() == name)
+                .map(|child| child.res.expect_non_local()),
+            DefKind::Impl => tcx
+                .associated_item_def_ids(def_id)
+                .iter()
+                .copied()
+                .find(|assoc_def_id| tcx.item_name(*assoc_def_id).as_str() == name)
+                .map(|assoc_def_id| Res::Def(tcx.def_kind(assoc_def_id), assoc_def_id)),
+            _ => None,
+        }
+    }
+    fn find_primitive(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
+        if let Some(&(index, Target::Impl)) = lang_items::ITEM_REFS.get(&Symbol::intern(name)) {
+            tcx.lang_items().items()[index]
+        } else {
+            None
+        }
+    }
+    fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> {
+        tcx.crates(())
             .iter()
-            .find(|item| item.ident.name.as_str() == name)
+            .find(|&&num| tcx.crate_name(num).as_str() == name)
+            .map(CrateNum::as_def_id)
     }
 
-    let (krate, first, path) = match *path {
-        [krate, first, ref path @ ..] => (krate, first, path),
+    let (base, first, path) = match *path {
+        [base, first, ref path @ ..] => (base, first, path),
         [primitive] => {
             return PrimTy::from_name(Symbol::intern(primitive)).map_or(Res::Err, Res::PrimTy);
         },
         _ => return Res::Err,
     };
     let tcx = cx.tcx;
-    let crates = tcx.crates(());
-    let krate = try_res!(crates.iter().find(|&&num| tcx.crate_name(num).as_str() == krate));
-    let first = try_res!(item_child_by_name(tcx, krate.as_def_id(), first));
+    let first = try_res!(
+        find_primitive(tcx, base)
+            .or_else(|| find_crate(tcx, base))
+            .and_then(|id| item_child_by_name(tcx, id, first))
+    );
+
     let last = path
         .iter()
         .copied()
-        // `get_def_path` seems to generate these empty segments for extern blocks.
-        // We can just ignore them.
-        .filter(|segment| !segment.is_empty())
         // for each segment, find the child item
-        .try_fold(first, |item, segment| {
-            let def_id = item.res.def_id();
+        .try_fold(first, |res, segment| {
+            let def_id = res.def_id();
             if let Some(item) = item_child_by_name(tcx, def_id, segment) {
                 Some(item)
-            } else if matches!(item.res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
+            } else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) {
                 // it is not a child item so check inherent impl items
                 tcx.inherent_impls(def_id)
                     .iter()
@@ -560,7 +579,7 @@ fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Opt
                 None
             }
         });
-    try_res!(last).res.expect_non_local()
+    try_res!(last).expect_non_local()
 }
 
 /// Convenience function to get the `DefId` of a trait by path.
@@ -587,12 +606,13 @@ pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
 ///     }
 /// }
 /// ```
-pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx TraitRef<'tcx>> {
+pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> Option<&'tcx TraitRef<'tcx>> {
     // Get the implemented trait for the current function
+    let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
     let parent_impl = cx.tcx.hir().get_parent_item(hir_id);
     if_chain! {
-        if parent_impl != hir::CRATE_HIR_ID;
-        if let hir::Node::Item(item) = cx.tcx.hir().get(parent_impl);
+        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(); }
     }
@@ -621,6 +641,19 @@ fn projection_stack<'a, 'hir>(mut e: &'a Expr<'hir>) -> (Vec<&'a Expr<'hir>>, &'
     (result, root)
 }
 
+/// Gets the mutability of the custom deref adjustment, if any.
+pub fn expr_custom_deref_adjustment(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<Mutability> {
+    cx.typeck_results()
+        .expr_adjustments(e)
+        .iter()
+        .find_map(|a| match a.kind {
+            Adjust::Deref(Some(d)) => Some(Some(d.mutbl)),
+            Adjust::Deref(None) => None,
+            _ => Some(None),
+        })
+        .and_then(|x| x)
+}
+
 /// Checks if two expressions can be mutably borrowed simultaneously
 /// and they aren't dependent on borrowing same thing twice
 pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -> bool {
@@ -629,7 +662,15 @@ pub fn can_mut_borrow_both(cx: &LateContext<'_>, e1: &Expr<'_>, e2: &Expr<'_>) -
     if !eq_expr_value(cx, r1, r2) {
         return true;
     }
+    if expr_custom_deref_adjustment(cx, r1).is_some() || expr_custom_deref_adjustment(cx, r2).is_some() {
+        return false;
+    }
+
     for (x1, x2) in s1.iter().zip(s2.iter()) {
+        if expr_custom_deref_adjustment(cx, x1).is_some() || expr_custom_deref_adjustment(cx, x2).is_some() {
+            return false;
+        }
+
         match (&x1.kind, &x2.kind) {
             (ExprKind::Field(_, i1), ExprKind::Field(_, i2)) => {
                 if i1 != i2 {
@@ -703,8 +744,8 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
             _ => false,
         },
         ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)),
-        ExprKind::Repeat(x, y) => if_chain! {
-            if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(y.body).value.kind;
+        ExprKind::Repeat(x, ArrayLen::Body(len)) => if_chain! {
+            if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind;
             if let LitKind::Int(v, _) = const_lit.node;
             if v <= 32 && is_default_equivalent(cx, x);
             then {
@@ -752,7 +793,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
 ///
 /// Note that this check is not recursive, so passing the `if` expression will always return true
 /// even though sub-expressions might return false.
-pub fn can_move_expr_to_closure_no_visit(
+pub fn can_move_expr_to_closure_no_visit<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'_>,
     loop_ids: &[HirId],
@@ -827,7 +868,7 @@ fn bitor_assign(&mut self, rhs: Self) {
 /// Note as this will walk up to parent expressions until the capture can be determined it should
 /// only be used while making a closure somewhere a value is consumed. e.g. a block, match arm, or
 /// function argument (other than a receiver).
-pub fn capture_local_usage(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind {
+pub fn capture_local_usage<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'_>) -> CaptureKind {
     fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind {
         let mut capture = CaptureKind::Ref(Mutability::Not);
         pat.each_binding_or_first(&mut |_, id, span, _| match cx
@@ -927,7 +968,7 @@ fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind {
 
 /// Checks if the expression can be moved into a closure as is. This will return a list of captures
 /// if so, otherwise, `None`.
-pub fn can_move_expr_to_closure(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<HirIdMap<CaptureKind>> {
+pub fn can_move_expr_to_closure<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<HirIdMap<CaptureKind>> {
     struct V<'cx, 'tcx> {
         cx: &'cx LateContext<'tcx>,
         // Stack of potential break targets contained in the expression.
@@ -940,7 +981,7 @@ struct V<'cx, 'tcx> {
         /// mutable reference.
         captures: HirIdMap<CaptureKind>,
     }
-    impl Visitor<'tcx> for V<'_, 'tcx> {
+    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
         type Map = ErasedMap<'tcx>;
         fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
             NestedVisitorMap::None
@@ -968,8 +1009,8 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                         };
                         if !self.locals.contains(&local_id) {
                             let capture = match capture.info.capture_kind {
-                                UpvarCapture::ByValue(_) => CaptureKind::Value,
-                                UpvarCapture::ByRef(borrow) => match borrow.kind {
+                                UpvarCapture::ByValue => CaptureKind::Value,
+                                UpvarCapture::ByRef(kind) => match kind {
                                     BorrowKind::ImmBorrow => CaptureKind::Ref(Mutability::Not),
                                     BorrowKind::UniqueImmBorrow | BorrowKind::MutBorrow => {
                                         CaptureKind::Ref(Mutability::Mut)
@@ -1081,14 +1122,13 @@ pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
 /// Returns `true` if the expression is in the program's `#[panic_handler]`.
 pub fn is_in_panic_handler(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     let parent = cx.tcx.hir().get_parent_item(e.hir_id);
-    let def_id = cx.tcx.hir().local_def_id(parent).to_def_id();
-    Some(def_id) == cx.tcx.lang_items().panic_impl()
+    Some(parent.to_def_id()) == cx.tcx.lang_items().panic_impl()
 }
 
 /// Gets the name of the item the expression is in, if available.
 pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
     let parent_id = cx.tcx.hir().get_parent_item(expr.hir_id);
-    match cx.tcx.hir().find(parent_id) {
+    match cx.tcx.hir().find_by_def_id(parent_id) {
         Some(
             Node::Item(Item { ident, .. })
             | Node::TraitItem(TraitItem { ident, .. })
@@ -1138,19 +1178,6 @@ pub fn contains_return(expr: &hir::Expr<'_>) -> bool {
     found
 }
 
-/// Finds calls of the specified macros in a function body.
-pub fn find_macro_calls(names: &[&str], body: &Body<'_>) -> Vec<Span> {
-    let mut result = Vec::new();
-    expr_visitor_no_bodies(|expr| {
-        if names.iter().any(|fun| is_expn_of(expr.span, fun).is_some()) {
-            result.push(expr.span);
-        }
-        true
-    })
-    .visit_expr(&body.value);
-    result
-}
-
 /// Extends the span to the beginning of the spans line, incl. whitespaces.
 ///
 /// ```rust
@@ -1210,7 +1237,7 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio
 }
 
 /// Gets the loop or closure enclosing the given expression, if any.
-pub fn get_enclosing_loop_or_closure(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+pub fn get_enclosing_loop_or_closure<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
     for (_, node) in tcx.hir().parent_iter(expr.hir_id) {
         match node {
             Node::Expr(
@@ -1611,7 +1638,7 @@ pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool
             return true;
         }
         prev_enclosing_node = Some(enclosing_node);
-        enclosing_node = map.get_parent_item(enclosing_node);
+        enclosing_node = map.local_def_id_to_hir_id(map.get_parent_item(enclosing_node));
     }
 
     false
@@ -1679,32 +1706,6 @@ pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool {
     path.first().map_or(false, |s| s.as_str() == "libc") && path.last().map_or(false, |s| s.as_str() == name)
 }
 
-pub fn match_panic_call(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
-    if let ExprKind::Call(func, [arg]) = expr.kind {
-        expr_path_res(cx, func)
-            .opt_def_id()
-            .map_or(false, |id| match_panic_def_id(cx, id))
-            .then(|| arg)
-    } else {
-        None
-    }
-}
-
-pub fn match_panic_def_id(cx: &LateContext<'_>, did: DefId) -> bool {
-    match_any_def_paths(
-        cx,
-        did,
-        &[
-            &paths::BEGIN_PANIC,
-            &paths::PANIC_ANY,
-            &paths::PANICKING_PANIC,
-            &paths::PANICKING_PANIC_FMT,
-            &paths::PANICKING_PANIC_STR,
-        ],
-    )
-    .is_some()
-}
-
 /// Returns the list of condition expressions and the list of blocks in a
 /// sequence of `if/else`.
 /// E.g., this returns `([a, b], [c, d, e])` for the expression
@@ -1744,7 +1745,7 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool {
 }
 
 /// Peels away all the compiler generated code surrounding the body of an async function,
-pub fn get_async_fn_body(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
+pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
     if let ExprKind::Call(
         _,
         &[
@@ -1848,7 +1849,7 @@ fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
 }
 
 /// Gets the node where an expression is either used, or it's type is unified with another branch.
-pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> {
+pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> {
     let mut child_id = expr.hir_id;
     let mut iter = tcx.hir().parent_iter(child_id);
     loop {
@@ -1954,7 +1955,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool {
         .predicates_of(did)
         .predicates
         .iter()
-        .filter_map(|(p, _)| if p.is_global(cx.tcx) { Some(*p) } else { None });
+        .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
     traits::impossible_predicates(
         cx.tcx,
         traits::elaborate_predicates(cx.tcx, predicates)
@@ -2000,7 +2001,7 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S
     if is_primitive {
         // if we have wrappers like Array, Slice or Tuple, print these
         // and get the type enclosed in the slice ref
-        match expr_type.peel_refs().walk(cx.tcx).nth(1).unwrap().expect_ty().kind() {
+        match expr_type.peel_refs().walk().nth(1).unwrap().expect_ty().kind() {
             rustc_ty::Slice(..) => return Some("slice".into()),
             rustc_ty::Array(..) => return Some("array".into()),
             rustc_ty::Tuple(..) => return Some("tuple".into()),
@@ -2008,7 +2009,7 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S
                 // is_recursively_primitive_type() should have taken care
                 // of the rest and we can rely on the type that is found
                 let refs_peeled = expr_type.peel_refs();
-                return Some(refs_peeled.walk(cx.tcx).last().unwrap().to_string());
+                return Some(refs_peeled.walk().last().unwrap().to_string());
             },
         }
     }
@@ -2054,8 +2055,8 @@ pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)
 
 /// Peels off all references on the pattern. Returns the underlying pattern and the number of
 /// references removed.
-pub fn peel_hir_pat_refs(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
-    fn peel(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
+pub fn peel_hir_pat_refs<'a>(pat: &'a Pat<'a>) -> (&'a Pat<'a>, usize) {
+    fn peel<'a>(pat: &'a Pat<'a>, count: usize) -> (&'a Pat<'a>, usize) {
         if let PatKind::Ref(pat, _) = pat.kind {
             peel(pat, count + 1)
         } else {
@@ -2078,7 +2079,7 @@ pub fn peel_hir_expr_while<'tcx>(
 
 /// Peels off up to the given number of references on the expression. Returns the underlying
 /// expression and the number of references removed.
-pub fn peel_n_hir_expr_refs(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
+pub fn peel_n_hir_expr_refs<'a>(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>, usize) {
     let mut remaining = count;
     let e = peel_hir_expr_while(expr, |e| match e.kind {
         ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) if remaining != 0 => {
@@ -2092,7 +2093,7 @@ pub fn peel_n_hir_expr_refs(expr: &'a Expr<'a>, count: usize) -> (&'a Expr<'a>,
 
 /// Peels off all references on the expression. Returns the underlying expression and the number of
 /// references removed.
-pub fn peel_hir_expr_refs(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
+pub fn peel_hir_expr_refs<'a>(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
     let mut count = 0;
     let e = peel_hir_expr_while(expr, |e| match e.kind {
         ExprKind::AddrOf(ast::BorrowKind::Ref, _, e) => {
@@ -2175,7 +2176,7 @@ fn visit_foreign_item(&mut self, _: &ForeignItem<'_>) {}
 
 static TEST_ITEM_NAMES_CACHE: SyncOnceCell<Mutex<FxHashMap<LocalDefId, Vec<Symbol>>>> = SyncOnceCell::new();
 
-fn with_test_item_names(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
+fn with_test_item_names<'tcx>(tcx: TyCtxt<'tcx>, module: LocalDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
     let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
     let mut map: MutexGuard<'_, FxHashMap<LocalDefId, Vec<Symbol>>> = cache.lock().unwrap();
     match map.entry(module) {
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
new file mode 100644 (file)
index 0000000..b7a242c
--- /dev/null
@@ -0,0 +1,539 @@
+#![allow(clippy::similar_names)] // `expr` and `expn`
+
+use crate::visitors::expr_visitor_no_bodies;
+
+use arrayvec::ArrayVec;
+use if_chain::if_chain;
+use rustc_ast::ast::LitKind;
+use rustc_hir::intravisit::Visitor;
+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::{sym, ExpnData, ExpnId, ExpnKind, Span, Symbol};
+use std::ops::ControlFlow;
+
+/// A macro call, like `vec![1, 2, 3]`.
+///
+/// Use `tcx.item_name(macro_call.def_id)` to get the macro name.
+/// Even better is to check if it is a diagnostic item.
+///
+/// This structure is similar to `ExpnData` but it precludes desugaring expansions.
+#[derive(Debug)]
+pub struct MacroCall {
+    /// Macro `DefId`
+    pub def_id: DefId,
+    /// Kind of macro
+    pub kind: MacroKind,
+    /// The expansion produced by the macro call
+    pub expn: ExpnId,
+    /// Span of the macro call site
+    pub span: Span,
+}
+
+impl MacroCall {
+    pub fn is_local(&self) -> bool {
+        span_is_local(self.span)
+    }
+}
+
+/// Returns an iterator of expansions that created the given span
+pub fn expn_backtrace(mut span: Span) -> impl Iterator<Item = (ExpnId, ExpnData)> {
+    std::iter::from_fn(move || {
+        let ctxt = span.ctxt();
+        if ctxt == SyntaxContext::root() {
+            return None;
+        }
+        let expn = ctxt.outer_expn();
+        let data = expn.expn_data();
+        span = data.call_site;
+        Some((expn, data))
+    })
+}
+
+/// Checks whether the span is from the root expansion or a locally defined macro
+pub fn span_is_local(span: Span) -> bool {
+    !span.from_expansion() || expn_is_local(span.ctxt().outer_expn())
+}
+
+/// Checks whether the expansion is the root expansion or a locally defined macro
+pub fn expn_is_local(expn: ExpnId) -> bool {
+    if expn == ExpnId::root() {
+        return true;
+    }
+    let data = expn.expn_data();
+    let backtrace = expn_backtrace(data.call_site);
+    std::iter::once((expn, data))
+        .chain(backtrace)
+        .find_map(|(_, data)| data.macro_def_id)
+        .map_or(true, DefId::is_local)
+}
+
+/// Returns an iterator of macro expansions that created the given span.
+/// Note that desugaring expansions are skipped.
+pub fn macro_backtrace(span: Span) -> impl Iterator<Item = MacroCall> {
+    expn_backtrace(span).filter_map(|(expn, data)| match data {
+        ExpnData {
+            kind: ExpnKind::Macro(kind, _),
+            macro_def_id: Some(def_id),
+            call_site: span,
+            ..
+        } => Some(MacroCall {
+            def_id,
+            kind,
+            expn,
+            span,
+        }),
+        _ => None,
+    })
+}
+
+/// If the macro backtrace of `span` has a macro call at the root expansion
+/// (i.e. not a nested macro call), returns `Some` with the `MacroCall`
+pub fn root_macro_call(span: Span) -> Option<MacroCall> {
+    macro_backtrace(span).last()
+}
+
+/// Like [`root_macro_call`], but only returns `Some` if `node` is the "first node"
+/// produced by the macro call, as in [`first_node_in_macro`].
+pub fn root_macro_call_first_node(cx: &LateContext<'_>, node: &impl HirNode) -> Option<MacroCall> {
+    if first_node_in_macro(cx, node) != Some(ExpnId::root()) {
+        return None;
+    }
+    root_macro_call(node.span())
+}
+
+/// Like [`macro_backtrace`], but only returns macro calls where `node` is the "first node" of the
+/// macro call, as in [`first_node_in_macro`].
+pub fn first_node_macro_backtrace(cx: &LateContext<'_>, node: &impl HirNode) -> impl Iterator<Item = MacroCall> {
+    let span = node.span();
+    first_node_in_macro(cx, node)
+        .into_iter()
+        .flat_map(move |expn| macro_backtrace(span).take_while(move |macro_call| macro_call.expn != expn))
+}
+
+/// If `node` is the "first node" in a macro expansion, returns `Some` with the `ExpnId` of the
+/// macro call site (i.e. the parent of the macro expansion). This generally means that `node`
+/// is the outermost node of an entire macro expansion, but there are some caveats noted below.
+/// This is useful for finding macro calls while visiting the HIR without processing the macro call
+/// at every node within its expansion.
+///
+/// If you already have immediate access to the parent node, it is simpler to
+/// just check the context of that span directly (e.g. `parent.span.from_expansion()`).
+///
+/// If a macro call is in statement position, it expands to one or more statements.
+/// In that case, each statement *and* their immediate descendants will all yield `Some`
+/// with the `ExpnId` of the containing block.
+///
+/// A node may be the "first node" of multiple macro calls in a macro backtrace.
+/// The expansion of the outermost macro call site is returned in such cases.
+pub fn first_node_in_macro(cx: &LateContext<'_>, node: &impl HirNode) -> Option<ExpnId> {
+    // get the macro expansion or return `None` if not found
+    // `macro_backtrace` importantly ignores desugaring expansions
+    let expn = macro_backtrace(node.span()).next()?.expn;
+
+    // get the parent node, possibly skipping over a statement
+    // if the parent is not found, it is sensible to return `Some(root)`
+    let hir = cx.tcx.hir();
+    let mut parent_iter = hir.parent_iter(node.hir_id());
+    let (parent_id, _) = match parent_iter.next() {
+        None => return Some(ExpnId::root()),
+        Some((_, Node::Stmt(_))) => match parent_iter.next() {
+            None => return Some(ExpnId::root()),
+            Some(next) => next,
+        },
+        Some(next) => next,
+    };
+
+    // get the macro expansion of the parent node
+    let parent_span = hir.span(parent_id);
+    let Some(parent_macro_call) = macro_backtrace(parent_span).next() else {
+        // the parent node is not in a macro
+        return Some(ExpnId::root());
+    };
+
+    if parent_macro_call.expn.is_descendant_of(expn) {
+        // `node` is input to a macro call
+        return None;
+    }
+
+    Some(parent_macro_call.expn)
+}
+
+/* Specific Macro Utils */
+
+/// Is `def_id` of `std::panic`, `core::panic` or any inner implementation macros
+pub fn is_panic(cx: &LateContext<'_>, def_id: DefId) -> bool {
+    let Some(name) = cx.tcx.get_diagnostic_name(def_id) else { return false };
+    matches!(
+        name.as_str(),
+        "core_panic_macro"
+            | "std_panic_macro"
+            | "core_panic_2015_macro"
+            | "std_panic_2015_macro"
+            | "core_panic_2021_macro"
+    )
+}
+
+pub enum PanicExpn<'a> {
+    /// No arguments - `panic!()`
+    Empty,
+    /// A string literal or any `&str` - `panic!("message")` or `panic!(message)`
+    Str(&'a Expr<'a>),
+    /// A single argument that implements `Display` - `panic!("{}", object)`
+    Display(&'a Expr<'a>),
+    /// Anything else - `panic!("error {}: {}", a, b)`
+    Format(FormatArgsExpn<'a>),
+}
+
+impl<'a> PanicExpn<'a> {
+    pub fn parse(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<Self> {
+        if !macro_backtrace(expr.span).any(|macro_call| is_panic(cx, macro_call.def_id)) {
+            return None;
+        }
+        let ExprKind::Call(callee, [arg]) = &expr.kind else { return None };
+        let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else { return None };
+        let result = match path.segments.last().unwrap().ident.as_str() {
+            "panic" if arg.span.ctxt() == expr.span.ctxt() => Self::Empty,
+            "panic" | "panic_str" => Self::Str(arg),
+            "panic_display" => {
+                let ExprKind::AddrOf(_, _, e) = &arg.kind else { return None };
+                Self::Display(e)
+            },
+            "panic_fmt" => Self::Format(FormatArgsExpn::parse(cx, arg)?),
+            _ => return None,
+        };
+        Some(result)
+    }
+}
+
+/// Finds the arguments of an `assert!` or `debug_assert!` macro call within the macro expansion
+pub fn find_assert_args<'a>(
+    cx: &LateContext<'_>,
+    expr: &'a Expr<'a>,
+    expn: ExpnId,
+) -> Option<(&'a Expr<'a>, PanicExpn<'a>)> {
+    find_assert_args_inner(cx, expr, expn).map(|([e], p)| (e, p))
+}
+
+/// Finds the arguments of an `assert_eq!` or `debug_assert_eq!` macro call within the macro
+/// expansion
+pub fn find_assert_eq_args<'a>(
+    cx: &LateContext<'_>,
+    expr: &'a Expr<'a>,
+    expn: ExpnId,
+) -> Option<(&'a Expr<'a>, &'a Expr<'a>, PanicExpn<'a>)> {
+    find_assert_args_inner(cx, expr, expn).map(|([a, b], p)| (a, b, p))
+}
+
+fn find_assert_args_inner<'a, const N: usize>(
+    cx: &LateContext<'_>,
+    expr: &'a Expr<'a>,
+    expn: ExpnId,
+) -> Option<([&'a Expr<'a>; N], PanicExpn<'a>)> {
+    let macro_id = expn.expn_data().macro_def_id?;
+    let (expr, expn) = match cx.tcx.item_name(macro_id).as_str().strip_prefix("debug_") {
+        None => (expr, expn),
+        Some(inner_name) => find_assert_within_debug_assert(cx, expr, expn, Symbol::intern(inner_name))?,
+    };
+    let mut args = ArrayVec::new();
+    let mut panic_expn = None;
+    expr_visitor_no_bodies(|e| {
+        if args.is_full() {
+            if panic_expn.is_none() && e.span.ctxt() != expr.span.ctxt() {
+                panic_expn = PanicExpn::parse(cx, e);
+            }
+            panic_expn.is_none()
+        } else if is_assert_arg(cx, e, expn) {
+            args.push(e);
+            false
+        } else {
+            true
+        }
+    })
+    .visit_expr(expr);
+    let args = args.into_inner().ok()?;
+    // if no `panic!(..)` is found, use `PanicExpn::Empty`
+    // to indicate that the default assertion message is used
+    let panic_expn = panic_expn.unwrap_or(PanicExpn::Empty);
+    Some((args, panic_expn))
+}
+
+fn find_assert_within_debug_assert<'a>(
+    cx: &LateContext<'_>,
+    expr: &'a Expr<'a>,
+    expn: ExpnId,
+    assert_name: Symbol,
+) -> Option<(&'a Expr<'a>, ExpnId)> {
+    let mut found = None;
+    expr_visitor_no_bodies(|e| {
+        if found.is_some() || !e.span.from_expansion() {
+            return false;
+        }
+        let e_expn = e.span.ctxt().outer_expn();
+        if e_expn == expn {
+            return true;
+        }
+        if e_expn.expn_data().macro_def_id.map(|id| cx.tcx.item_name(id)) == Some(assert_name) {
+            found = Some((e, e_expn));
+        }
+        false
+    })
+    .visit_expr(expr);
+    found
+}
+
+fn is_assert_arg(cx: &LateContext<'_>, expr: &Expr<'_>, assert_expn: ExpnId) -> bool {
+    if !expr.span.from_expansion() {
+        return true;
+    }
+    let result = macro_backtrace(expr.span).try_for_each(|macro_call| {
+        if macro_call.expn == assert_expn {
+            ControlFlow::Break(false)
+        } else {
+            match cx.tcx.item_name(macro_call.def_id) {
+                // `cfg!(debug_assertions)` in `debug_assert!`
+                sym::cfg => ControlFlow::CONTINUE,
+                // assert!(other_macro!(..))
+                _ => ControlFlow::Break(true),
+            }
+        }
+    });
+    match result {
+        ControlFlow::Break(is_assert_arg) => is_assert_arg,
+        ControlFlow::Continue(()) => true,
+    }
+}
+
+/// A parsed `format_args!` expansion
+pub struct FormatArgsExpn<'tcx> {
+    /// Span of the first argument, the format string
+    pub format_string_span: Span,
+    /// The format string split by formatted args like `{..}`
+    pub format_string_parts: Vec<Symbol>,
+    /// Values passed after the format string
+    pub value_args: Vec<&'tcx Expr<'tcx>>,
+    /// Each element is a `value_args` index and a formatting trait (e.g. `sym::Debug`)
+    pub formatters: Vec<(usize, Symbol)>,
+    /// List of `fmt::v1::Argument { .. }` expressions. If this is empty,
+    /// then `formatters` represents the format args (`{..}`).
+    /// If this is non-empty, it represents the format args, and the `position`
+    /// parameters within the struct expressions are indexes of `formatters`.
+    pub specs: Vec<&'tcx Expr<'tcx>>,
+}
+
+impl<'tcx> FormatArgsExpn<'tcx> {
+    /// Parses an expanded `format_args!` or `format_args_nl!` invocation
+    pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
+        macro_backtrace(expr.span).find(|macro_call| {
+            matches!(
+                cx.tcx.item_name(macro_call.def_id),
+                sym::const_format_args | sym::format_args | sym::format_args_nl
+            )
+        })?;
+        let mut format_string_span: Option<Span> = None;
+        let mut format_string_parts: Vec<Symbol> = Vec::new();
+        let mut value_args: Vec<&Expr<'_>> = Vec::new();
+        let mut formatters: Vec<(usize, Symbol)> = Vec::new();
+        let mut specs: Vec<&Expr<'_>> = Vec::new();
+        expr_visitor_no_bodies(|e| {
+            // if we're still inside of the macro definition...
+            if e.span.ctxt() == expr.span.ctxt() {
+                // ArgumnetV1::new(<value>, <format_trait>::fmt)
+                if_chain! {
+                    if let ExprKind::Call(callee, [val, fmt_path]) = e.kind;
+                    if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind;
+                    if seg.ident.name == sym::new;
+                    if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
+                    if path.segments.last().unwrap().ident.name == sym::ArgumentV1;
+                    if let ExprKind::Path(QPath::Resolved(_, path)) = fmt_path.kind;
+                    if let [.., fmt_trait, _fmt] = path.segments;
+                    then {
+                        let val_idx = if_chain! {
+                            if val.span.ctxt() == expr.span.ctxt();
+                            if let ExprKind::Field(_, field) = val.kind;
+                            if let Ok(idx) = field.name.as_str().parse();
+                            then {
+                                // tuple index
+                                idx
+                            } else {
+                                // assume the value expression is passed directly
+                                formatters.len()
+                            }
+                        };
+                        formatters.push((val_idx, fmt_trait.ident.name));
+                    }
+                }
+                if let ExprKind::Struct(QPath::Resolved(_, path), ..) = e.kind {
+                    if path.segments.last().unwrap().ident.name == sym::Argument {
+                        specs.push(e);
+                    }
+                }
+                // walk through the macro expansion
+                return true;
+            }
+            // assume that the first expr with a differing context represents
+            // (and has the span of) the format string
+            if format_string_span.is_none() {
+                format_string_span = Some(e.span);
+                let span = e.span;
+                // walk the expr and collect string literals which are format string parts
+                expr_visitor_no_bodies(|e| {
+                    if e.span.ctxt() != span.ctxt() {
+                        // defensive check, probably doesn't happen
+                        return false;
+                    }
+                    if let ExprKind::Lit(lit) = &e.kind {
+                        if let LitKind::Str(symbol, _s) = lit.node {
+                            format_string_parts.push(symbol);
+                        }
+                    }
+                    true
+                })
+                .visit_expr(e);
+            } else {
+                // assume that any further exprs with a differing context are value args
+                value_args.push(e);
+            }
+            // don't walk anything not from the macro expansion (e.a. inputs)
+            false
+        })
+        .visit_expr(expr);
+        Some(FormatArgsExpn {
+            format_string_span: format_string_span?,
+            format_string_parts,
+            value_args,
+            formatters,
+            specs,
+        })
+    }
+
+    /// Finds a nested call to `format_args!` within a `format!`-like macro call
+    pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option<Self> {
+        let mut format_args = None;
+        expr_visitor_no_bodies(|e| {
+            if format_args.is_some() {
+                return false;
+            }
+            let e_ctxt = e.span.ctxt();
+            if e_ctxt == expr.span.ctxt() {
+                return true;
+            }
+            if e_ctxt.outer_expn().is_descendant_of(expn_id) {
+                format_args = FormatArgsExpn::parse(cx, e);
+            }
+            false
+        })
+        .visit_expr(expr);
+        format_args
+    }
+
+    /// Returns a vector of `FormatArgsArg`.
+    pub fn args(&self) -> Option<Vec<FormatArgsArg<'tcx>>> {
+        if self.specs.is_empty() {
+            let args = std::iter::zip(&self.value_args, &self.formatters)
+                .map(|(value, &(_, format_trait))| FormatArgsArg {
+                    value,
+                    format_trait,
+                    spec: None,
+                })
+                .collect();
+            return Some(args);
+        }
+        self.specs
+            .iter()
+            .map(|spec| {
+                if_chain! {
+                    // struct `core::fmt::rt::v1::Argument`
+                    if let ExprKind::Struct(_, fields, _) = spec.kind;
+                    if let Some(position_field) = fields.iter().find(|f| f.ident.name == sym::position);
+                    if let ExprKind::Lit(lit) = &position_field.expr.kind;
+                    if let LitKind::Int(position, _) = lit.node;
+                    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) })
+                    } else {
+                        None
+                    }
+                }
+            })
+            .collect()
+    }
+
+    /// 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),
+        }
+    }
+}
+
+/// Type representing a `FormatArgsExpn`'s format arguments
+pub struct FormatArgsArg<'tcx> {
+    /// An element of `value_args` according to `position`
+    pub value: &'tcx Expr<'tcx>,
+    /// An element of `args` according to `position`
+    pub format_trait: Symbol,
+    /// An element of `specs`
+    pub spec: Option<&'tcx Expr<'tcx>>,
+}
+
+impl<'tcx> FormatArgsArg<'tcx> {
+    /// Returns true if any formatting parameters are used that would have an effect on strings,
+    /// like `{:+2}` instead of just `{}`.
+    pub fn has_string_formatting(&self) -> bool {
+        self.spec.map_or(false, |spec| {
+            // `!` because these conditions check that `self` is unformatted.
+            !if_chain! {
+                // struct `core::fmt::rt::v1::Argument`
+                if let ExprKind::Struct(_, fields, _) = spec.kind;
+                if let Some(format_field) = fields.iter().find(|f| f.ident.name == sym::format);
+                // struct `core::fmt::rt::v1::FormatSpec`
+                if let ExprKind::Struct(_, subfields, _) = format_field.expr.kind;
+                if subfields.iter().all(|field| match field.ident.name {
+                    sym::precision | sym::width => match field.expr.kind {
+                        ExprKind::Path(QPath::Resolved(_, path)) => {
+                            path.segments.last().unwrap().ident.name == sym::Implied
+                        }
+                        _ => false,
+                    }
+                    _ => true,
+                });
+                then { true } else { false }
+            }
+        })
+    }
+}
+
+/// A node with a `HirId` and a `Span`
+pub trait HirNode {
+    fn hir_id(&self) -> HirId;
+    fn span(&self) -> Span;
+}
+
+macro_rules! impl_hir_node {
+    ($($t:ident),*) => {
+        $(impl HirNode for hir::$t<'_> {
+            fn hir_id(&self) -> HirId {
+                self.hir_id
+            }
+            fn span(&self) -> Span {
+                self.span
+            }
+        })*
+    };
+}
+
+impl_hir_node!(Expr, Pat);
+
+impl HirNode for hir::Item<'_> {
+    fn hir_id(&self) -> HirId {
+        self.hir_id()
+    }
+
+    fn span(&self) -> Span {
+        self.span
+    }
+}
index 0cec7d6a5e402aa13a05395c23bf5dd630a5d587..a5b409ad96bbbd3125a50005e77430b93339b7df 100644 (file)
@@ -12,8 +12,9 @@ macro_rules! msrv_aliases {
 
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
-    1,53,0 { OR_PATTERNS }
+    1,53,0 { OR_PATTERNS, MANUAL_BITS }
     1,52,0 { STR_SPLIT_ONCE }
+    1,51,0 { BORROW_AS_PTR }
     1,50,0 { BOOL_THEN }
     1,47,0 { TAU }
     1,46,0 { CONST_IF_MATCH }
index 6171823abbbd04fa7142aecaad1231c654150ff2..288c56e9fd737bd386c6afe35fbaea7d1746018c 100644 (file)
@@ -5,16 +5,16 @@
 //! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
 
 pub const ANY_TRAIT: [&str; 3] = ["core", "any", "Any"];
-#[cfg(feature = "metadata-collector-lint")]
+#[cfg(feature = "internal")]
 pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"];
-#[cfg(feature = "metadata-collector-lint")]
+#[cfg(feature = "internal")]
 pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
     ["rustc_lint_defs", "Applicability", "Unspecified"],
     ["rustc_lint_defs", "Applicability", "HasPlaceholders"],
     ["rustc_lint_defs", "Applicability", "MaybeIncorrect"],
     ["rustc_lint_defs", "Applicability", "MachineApplicable"],
 ];
-#[cfg(feature = "metadata-collector-lint")]
+#[cfg(feature = "internal")]
 pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
 pub const ARC_PTR_EQ: [&str; 4] = ["alloc", "sync", "Arc", "ptr_eq"];
 #[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
@@ -25,7 +25,6 @@
 pub const ASSERT_NE_MACRO: [&str; 3] = ["core", "macros", "assert_ne"];
 pub const ASMUT_TRAIT: [&str; 3] = ["core", "convert", "AsMut"];
 pub const ASREF_TRAIT: [&str; 3] = ["core", "convert", "AsRef"];
-pub(super) const BEGIN_PANIC: [&str; 3] = ["std", "panicking", "begin_panic"];
 /// Preferably use the diagnostic item `sym::Borrow` where possible
 pub const BORROW_TRAIT: [&str; 3] = ["core", "borrow", "Borrow"];
 pub const BORROW_MUT_TRAIT: [&str; 3] = ["core", "borrow", "BorrowMut"];
@@ -46,7 +45,7 @@
 pub const DOUBLE_ENDED_ITERATOR: [&str; 4] = ["core", "iter", "traits", "DoubleEndedIterator"];
 pub const DROP: [&str; 3] = ["core", "mem", "drop"];
 pub const DURATION: [&str; 3] = ["core", "time", "Duration"];
-#[cfg(feature = "internal-lints")]
+#[cfg(feature = "internal")]
 pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
 #[allow(clippy::invalid_paths)] // `check_path` does not seem to work for macros
 pub const EPRINT_MACRO: [&str; 3] = ["std", "macros", "eprint"];
 pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
 pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"];
 pub const FUTURE_FROM_GENERATOR: [&str; 3] = ["core", "future", "from_generator"];
+#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"];
+#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWriteExt"];
 pub const HASH: [&str; 3] = ["core", "hash", "Hash"];
 pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"];
 pub const HASHMAP_ENTRY: [&str; 5] = ["std", "collections", "hash", "map", "Entry"];
 pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"];
-#[cfg(feature = "internal-lints")]
+#[cfg(feature = "internal")]
 pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
-#[cfg(feature = "internal-lints")]
+#[cfg(feature = "internal")]
 pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
 pub const INDEX: [&str; 3] = ["core", "ops", "Index"];
 pub const INDEX_MUT: [&str; 3] = ["core", "ops", "IndexMut"];
 pub const ITER_REPEAT: [&str; 5] = ["core", "iter", "sources", "repeat", "repeat"];
 #[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
 pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
-#[cfg(feature = "internal-lints")]
+#[cfg(feature = "internal")]
 pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
-#[cfg(feature = "internal-lints")]
+#[cfg(feature = "internal")]
 pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
-#[cfg(any(feature = "internal-lints", feature = "metadata-collector-lint"))]
+#[cfg(feature = "internal")]
 pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
 pub const MEM_DISCRIMINANT: [&str; 3] = ["core", "mem", "discriminant"];
 pub const MEM_FORGET: [&str; 3] = ["core", "mem", "forget"];
 pub const ORD: [&str; 3] = ["core", "cmp", "Ord"];
 pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
 pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
-pub(super) const PANICKING_PANIC: [&str; 3] = ["core", "panicking", "panic"];
-pub(super) const PANICKING_PANIC_FMT: [&str; 3] = ["core", "panicking", "panic_fmt"];
-pub(super) const PANICKING_PANIC_STR: [&str; 3] = ["core", "panicking", "panic_str"];
-pub(super) const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"];
 pub const PARKING_LOT_RAWMUTEX: [&str; 3] = ["parking_lot", "raw_mutex", "RawMutex"];
 pub const PARKING_LOT_RAWRWLOCK: [&str; 3] = ["parking_lot", "raw_rwlock", "RawRwLock"];
 pub const PARKING_LOT_MUTEX_GUARD: [&str; 2] = ["parking_lot", "MutexGuard"];
 pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
 pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
 pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
+#[cfg_attr(not(unix), allow(clippy::invalid_paths))]
 pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"];
 pub const POLL: [&str; 4] = ["core", "task", "poll", "Poll"];
 pub const POLL_PENDING: [&str; 5] = ["core", "task", "poll", "Poll", "Pending"];
 pub const STR_FROM_UTF8: [&str; 4] = ["core", "str", "converts", "from_utf8"];
 pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
 pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
-#[cfg(feature = "internal-lints")]
+#[cfg(feature = "internal")]
 pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"];
-#[cfg(feature = "internal-lints")]
+#[cfg(feature = "internal")]
 pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"];
-#[cfg(feature = "internal-lints")]
+#[cfg(feature = "internal")]
 pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"];
-#[cfg(feature = "internal-lints")]
+#[cfg(feature = "internal")]
 pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
-#[cfg(feature = "internal-lints")]
+#[cfg(feature = "internal")]
 pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
-#[cfg(feature = "internal-lints")]
+#[cfg(feature = "internal")]
 pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
 pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
 pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
+#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"];
+#[allow(clippy::invalid_paths)] // internal lints do not know about all external crates
+pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"];
 pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
 pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
 pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
index 1a4da1627b7842eecb83d3f85f5f7f3271cad66b..729ee00cba00e2ce75c86bb7a9b086f249fd895b 100644 (file)
@@ -19,7 +19,7 @@
 
 type McfResult = Result<(), (Span, Cow<'static, str>)>;
 
-pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<&RustcVersion>) -> McfResult {
+pub fn is_min_const_fn<'a, 'tcx>(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<&RustcVersion>) -> McfResult {
     let def_id = body.source.def_id();
     let mut current = def_id;
     loop {
@@ -85,8 +85,8 @@ pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, msrv: Option<&Ru
     Ok(())
 }
 
-fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
-    for arg in ty.walk(tcx) {
+fn check_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
+    for arg in ty.walk() {
         let ty = match arg.unpack() {
             GenericArgKind::Type(ty) => ty,
 
@@ -133,7 +133,13 @@ fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) -> McfResult {
     Ok(())
 }
 
-fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rvalue<'tcx>, span: Span) -> McfResult {
+fn check_rvalue<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    def_id: DefId,
+    rvalue: &Rvalue<'tcx>,
+    span: Span,
+) -> McfResult {
     match rvalue {
         Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
         Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => check_operand(tcx, operand, span, body),
@@ -193,7 +199,6 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv
             }
         },
         Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()),
-        Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())),
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
             if ty.is_integral() || ty.is_bool() {
@@ -211,7 +216,12 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv
     }
 }
 
-fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statement: &Statement<'tcx>) -> McfResult {
+fn check_statement<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    def_id: DefId,
+    statement: &Statement<'tcx>,
+) -> McfResult {
     let span = statement.source_info.span;
     match &statement.kind {
         StatementKind::Assign(box (place, rval)) => {
@@ -240,7 +250,7 @@ fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statemen
     }
 }
 
-fn check_operand(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
+fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
     match operand {
         Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, body),
         Operand::Constant(c) => match c.check_static_ptr(tcx) {
@@ -250,7 +260,7 @@ fn check_operand(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &
     }
 }
 
-fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
+fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
     let mut cursor = place.projection.as_ref();
     while let [ref proj_base @ .., elem] = *cursor {
         cursor = proj_base;
@@ -275,7 +285,7 @@ fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'t
     Ok(())
 }
 
-fn check_terminator(
+fn check_terminator<'a, 'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &'a Body<'tcx>,
     terminator: &Terminator<'tcx>,
index d928317259da0f23b875300b02f3fe3c650b20c1..dbad607c58ea34dfee9b37780b166824cd0f2efc 100644 (file)
@@ -281,7 +281,7 @@ pub fn snippet_block_with_applicability<'a, T: LintContext>(
 /// correctly get a snippet of `vec![]`.
 ///
 /// This will also return whether or not the snippet is a macro call.
-pub fn snippet_with_context(
+pub fn snippet_with_context<'a>(
     cx: &LateContext<'_>,
     span: Span,
     outer: SyntaxContext,
index 92662c59226a2e300f38ac8378fe9f932540ce98..87bc8232dde3a6e2501e1fdc0ae2f73584091e8d 100644 (file)
@@ -461,7 +461,7 @@ fn neg(self) -> Sugg<'static> {
     }
 }
 
-impl Not for Sugg<'a> {
+impl<'a> Not for Sugg<'a> {
     type Output = Sugg<'a>;
     fn not(self) -> Sugg<'a> {
         use AssocOp::{Equal, Greater, GreaterEqual, Less, LessEqual, NotEqual};
@@ -846,7 +846,7 @@ struct DerefDelegate<'a, 'tcx> {
     applicability: Applicability,
 }
 
-impl DerefDelegate<'_, 'tcx> {
+impl<'tcx> DerefDelegate<'_, 'tcx> {
     /// build final suggestion:
     /// - create the ending part of suggestion
     /// - concatenate starting and ending parts
index 6d191d4a59bde9948d4fa84e26aacc9ed5d7268c..f109b7845b4bdf7e63af2399cdba24b674fccc05 100644 (file)
@@ -25,7 +25,7 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 }
 
 /// Checks whether a type can be partially moved.
-pub fn can_partially_move_ty(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+pub fn can_partially_move_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     if has_drop(cx, ty) || is_copy(cx, ty) {
         return false;
     }
@@ -37,8 +37,8 @@ pub fn can_partially_move_ty(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 }
 
 /// Walks into `ty` and returns `true` if any inner type is the same as `other_ty`
-pub fn contains_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, other_ty: Ty<'tcx>) -> bool {
-    ty.walk(tcx).any(|inner| match inner.unpack() {
+pub fn contains_ty(ty: Ty<'_>, other_ty: Ty<'_>) -> bool {
+    ty.walk().any(|inner| match inner.unpack() {
         GenericArgKind::Type(inner_ty) => ty::TyS::same_type(other_ty, inner_ty),
         GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
     })
@@ -46,8 +46,8 @@ pub fn contains_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, other_ty: Ty<'tcx>) ->
 
 /// Walks into `ty` and returns `true` if any inner type is an instance of the given adt
 /// constructor.
-pub fn contains_adt_constructor<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, adt: &'tcx AdtDef) -> bool {
-    ty.walk(tcx).any(|inner| match inner.unpack() {
+pub fn contains_adt_constructor(ty: Ty<'_>, adt: &AdtDef) -> bool {
+    ty.walk().any(|inner| match inner.unpack() {
         GenericArgKind::Type(inner_ty) => inner_ty.ty_adt_def() == Some(adt),
         GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => false,
     })
@@ -221,7 +221,7 @@ fn is_normalizable_helper<'tcx>(
                         .iter()
                         .all(|field| is_normalizable_helper(cx, param_env, field.ty(cx.tcx, substs), cache))
                 }),
-                _ => ty.walk(cx.tcx).all(|generic_arg| match generic_arg.unpack() {
+                _ => ty.walk().all(|generic_arg| match generic_arg.unpack() {
                     GenericArgKind::Type(inner_ty) if inner_ty != ty => {
                         is_normalizable_helper(cx, param_env, inner_ty, cache)
                     },
@@ -366,7 +366,7 @@ fn inner(ty: Ty<'_>, depth: usize) -> (Ty<'_>, usize) {
 
 /// Returns `true` if types `a` and `b` are same types having same `Const` generic args,
 /// otherwise returns `false`
-pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+pub fn same_type_and_consts<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
     match (&a.kind(), &b.kind()) {
         (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => {
             if did_a != did_b {
index 4bfd3c64b9c361acb61001600277e3064bbb2ff3..b60cd4736f32ac1d9bdeb9c16337d113679a26a7 100644 (file)
@@ -173,7 +173,7 @@ pub trait Visitable<'tcx> {
 }
 macro_rules! visitable_ref {
     ($t:ident, $f:ident) => {
-        impl Visitable<'tcx> for &'tcx $t<'tcx> {
+        impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
             fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
                 visitor.$f(self);
             }
@@ -217,7 +217,7 @@ pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
 }
 
 /// Checks if the given local is used.
-pub fn is_local_used(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool {
+pub fn is_local_used<'tcx>(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id: HirId) -> bool {
     let mut is_used = false;
     let mut visitor = expr_visitor(cx, |expr| {
         if !is_used {
@@ -231,7 +231,7 @@ pub fn is_local_used(cx: &LateContext<'tcx>, visitable: impl Visitable<'tcx>, id
 }
 
 /// Checks if the given expression is a constant.
-pub fn is_const_evaluatable(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
+pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
     struct V<'a, 'tcx> {
         cx: &'a LateContext<'tcx>,
         is_const: bool,
@@ -321,7 +321,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
 }
 
 /// Checks if the given expression performs an unsafe operation outside of an unsafe block.
-pub fn is_expr_unsafe(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
+pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
     struct V<'a, 'tcx> {
         cx: &'a LateContext<'tcx>,
         is_unsafe: bool,
diff --git a/src/tools/clippy/clippy_workspace_tests/Cargo.toml b/src/tools/clippy/clippy_workspace_tests/Cargo.toml
deleted file mode 100644 (file)
index 7a235b2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-[package]
-name = "clippy_workspace_tests"
-version = "0.1.0"
-edition = "2018"
-
-[workspace]
-members = ["subcrate"]
diff --git a/src/tools/clippy/clippy_workspace_tests/build.rs b/src/tools/clippy/clippy_workspace_tests/build.rs
deleted file mode 100644 (file)
index 3507168..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#![deny(clippy::print_stdout)]
-
-fn main() {
-    // Test for #6041
-    println!("Hello");
-    print!("Hello");
-}
diff --git a/src/tools/clippy/clippy_workspace_tests/path_dep/Cargo.toml b/src/tools/clippy/clippy_workspace_tests/path_dep/Cargo.toml
deleted file mode 100644 (file)
index 85a91cd..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-[package]
-name = "path_dep"
-version = "0.1.0"
diff --git a/src/tools/clippy/clippy_workspace_tests/path_dep/src/lib.rs b/src/tools/clippy/clippy_workspace_tests/path_dep/src/lib.rs
deleted file mode 100644 (file)
index 35ce524..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-#![deny(clippy::empty_loop)]
-
-#[cfg(feature = "primary_package_test")]
-pub fn lint_me() {
-    loop {}
-}
diff --git a/src/tools/clippy/clippy_workspace_tests/src/main.rs b/src/tools/clippy/clippy_workspace_tests/src/main.rs
deleted file mode 100644 (file)
index b322eca..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#![deny(rust_2018_idioms)]
-
-fn main() {}
diff --git a/src/tools/clippy/clippy_workspace_tests/subcrate/Cargo.toml b/src/tools/clippy/clippy_workspace_tests/subcrate/Cargo.toml
deleted file mode 100644 (file)
index 45362c1..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-[package]
-name = "subcrate"
-version = "0.1.0"
-
-[dependencies]
-path_dep = { path = "../path_dep" }
diff --git a/src/tools/clippy/clippy_workspace_tests/subcrate/src/lib.rs b/src/tools/clippy/clippy_workspace_tests/subcrate/src/lib.rs
deleted file mode 100644 (file)
index 8b13789..0000000
+++ /dev/null
@@ -1 +0,0 @@
-
index c7e51d53f511d9e91c044e0c985c9d42ab41b672..207b0be15488561da7a76d9f1ad4933dc9fde58f 100644 (file)
@@ -60,7 +60,7 @@ Two noticeable items here:
 Starting with an `expr`, you can check whether it is calling a specific method `some_method`:
 
 ```rust
-impl LateLintPass<'_> for MyStructLint {
+impl<'tcx> LateLintPass<'tcx> for MyStructLint {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if_chain! {
             // Check our expr is calling a method
index f33f1b65eabdba1a45c3859f9ea941c18cd7bf4e..c694037021a5e518a69af67aed66340ab075ef0d 100644 (file)
@@ -13,7 +13,7 @@ publish = false
 clap = "2.33"
 flate2 = "1.0"
 fs_extra = "1.2"
-rayon = "1.5"
+rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
 tar = "0.4"
index 53e669254cfeafde12b584fec22c15c4e2cc168b..9af8dcc7726f080906adcc1c8ed2b1bc2b711175 100644 (file)
@@ -665,16 +665,6 @@ fn lintcheck_needs_rerun(lintcheck_logs_path: &Path) -> bool {
     logs_modified < clippy_modified
 }
 
-fn is_in_clippy_root() -> bool {
-    if let Ok(pb) = std::env::current_dir() {
-        if let Some(file) = pb.file_name() {
-            return file == PathBuf::from("rust-clippy");
-        }
-    }
-
-    false
-}
-
 /// lintchecks `main()` function
 ///
 /// # Panics
@@ -683,7 +673,7 @@ fn is_in_clippy_root() -> bool {
 /// or if lintcheck is executed from the wrong directory (aka none-repo-root)
 pub fn main() {
     // assert that we launch lintcheck from the repo root (via cargo lintcheck)
-    if !is_in_clippy_root() {
+    if std::fs::metadata("lintcheck/Cargo.toml").is_err() {
         eprintln!("lintcheck needs to be run from clippys repo root!\nUse `cargo lintcheck` alternatively.");
         std::process::exit(3);
     }
index 471ae40f1ac7af43fb20fc1efb8f419a99c4c5f7..e6a58e92072501a2f4bc8293392634d5bae93cac 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-12-30"
+channel = "nightly-2022-01-13"
 components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
index 7ebdd947893e9e1570ed1fe8d31ba32b2b4ffefd..240e233420f0ea124f063951cfa9973f5ac087d9 100644 (file)
@@ -96,7 +96,7 @@ fn new<I>(mut old_args: I) -> Self
             clippy_args.push("--no-deps".into());
         }
 
-        ClippyCmd {
+        Self {
             cargo_subcommand,
             args,
             clippy_args,
diff --git a/src/tools/clippy/tests/cargo/mod.rs b/src/tools/clippy/tests/cargo/mod.rs
deleted file mode 100644 (file)
index 4dbe71e..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#[must_use]
-pub fn is_rustc_test_suite() -> bool {
-    option_env!("RUSTC_TEST_SUITE").is_some()
-}
index a2d58491872b30813e99e0bb2685478183c6dc74..531890c863f5efeda3642e73a67029ea1e879f63 100644 (file)
@@ -1,4 +1,5 @@
 #![feature(test)] // compiletest_rs requires this attribute
+#![feature(once_cell)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
 use std::fs;
 use std::io;
 use std::path::{Path, PathBuf};
+use test_utils::IS_RUSTC_TEST_SUITE;
 
-mod cargo;
+mod test_utils;
 
 // whether to run internal tests or not
-const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal-lints");
+const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal");
 
 /// All crates used in UI tests are listed here
 static TEST_DEPENDENCIES: &[&str] = &[
     "clippy_utils",
     "derive_new",
+    "futures",
     "if_chain",
     "itertools",
     "quote",
@@ -28,6 +31,7 @@
     "serde",
     "serde_derive",
     "syn",
+    "tokio",
     "parking_lot",
 ];
 
@@ -38,6 +42,8 @@
 #[allow(unused_extern_crates)]
 extern crate derive_new;
 #[allow(unused_extern_crates)]
+extern crate futures;
+#[allow(unused_extern_crates)]
 extern crate if_chain;
 #[allow(unused_extern_crates)]
 extern crate itertools;
@@ -47,6 +53,8 @@
 extern crate quote;
 #[allow(unused_extern_crates)]
 extern crate syn;
+#[allow(unused_extern_crates)]
+extern crate tokio;
 
 /// Produces a string with an `--extern` flag for all UI test crate
 /// dependencies.
@@ -298,7 +306,7 @@ fn run_tests(
         Ok(result)
     }
 
-    if cargo::is_rustc_test_suite() {
+    if IS_RUSTC_TEST_SUITE {
         return;
     }
 
index a37cdfed126f6cea9c46d063abf01ac7ff801e5f..67af9d05bf402473a3cc6d34080872e15c30ec61 100644 (file)
 //!
 //! See [Eating your own dog food](https://en.wikipedia.org/wiki/Eating_your_own_dog_food) for context
 
-// Dogfood cannot run on Windows
-#![cfg(not(windows))]
 #![feature(once_cell)]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-use std::lazy::SyncLazy;
 use std::path::PathBuf;
 use std::process::Command;
+use test_utils::IS_RUSTC_TEST_SUITE;
 
-mod cargo;
-
-static CLIPPY_PATH: SyncLazy<PathBuf> = SyncLazy::new(|| {
-    let mut path = std::env::current_exe().unwrap();
-    assert!(path.pop()); // deps
-    path.set_file_name("cargo-clippy");
-    path
-});
+mod test_utils;
 
 #[test]
 fn dogfood_clippy() {
-    // run clippy on itself and fail the test if lint warnings are reported
-    if cargo::is_rustc_test_suite() {
-        return;
-    }
-    let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
-
-    let mut command = Command::new(&*CLIPPY_PATH);
-    command
-        .current_dir(root_dir)
-        .env("CARGO_INCREMENTAL", "0")
-        .arg("clippy")
-        .arg("--all-targets")
-        .arg("--all-features")
-        .arg("--")
-        .args(&["-D", "clippy::all"])
-        .args(&["-D", "clippy::pedantic"])
-        .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
-
-    // internal lints only exist if we build with the internal-lints feature
-    if cfg!(feature = "internal-lints") {
-        command.args(&["-D", "clippy::internal"]);
-    }
-
-    let output = command.output().unwrap();
-
-    println!("status: {}", output.status);
-    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
-    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
-
-    assert!(output.status.success());
-}
-
-fn test_no_deps_ignores_path_deps_in_workspaces() {
-    if cargo::is_rustc_test_suite() {
+    if IS_RUSTC_TEST_SUITE {
         return;
     }
-    let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
-    let target_dir = root.join("target").join("dogfood");
-    let cwd = root.join("clippy_workspace_tests");
-
-    // Make sure we start with a clean state
-    Command::new("cargo")
-        .current_dir(&cwd)
-        .env("CARGO_TARGET_DIR", &target_dir)
-        .arg("clean")
-        .args(&["-p", "subcrate"])
-        .args(&["-p", "path_dep"])
-        .output()
-        .unwrap();
-
-    // `path_dep` is a path dependency of `subcrate` that would trigger a denied lint.
-    // Make sure that with the `--no-deps` argument Clippy does not run on `path_dep`.
-    let output = Command::new(&*CLIPPY_PATH)
-        .current_dir(&cwd)
-        .env("CARGO_INCREMENTAL", "0")
-        .arg("clippy")
-        .args(&["-p", "subcrate"])
-        .arg("--no-deps")
-        .arg("--")
-        .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
-        .args(&["--cfg", r#"feature="primary_package_test""#])
-        .output()
-        .unwrap();
-    println!("status: {}", output.status);
-    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
-    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
-
-    assert!(output.status.success());
-
-    let lint_path_dep = || {
-        // Test that without the `--no-deps` argument, `path_dep` is linted.
-        let output = Command::new(&*CLIPPY_PATH)
-            .current_dir(&cwd)
-            .env("CARGO_INCREMENTAL", "0")
-            .arg("clippy")
-            .args(&["-p", "subcrate"])
-            .arg("--")
-            .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
-            .args(&["--cfg", r#"feature="primary_package_test""#])
-            .output()
-            .unwrap();
-        println!("status: {}", output.status);
-        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
-        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
-
-        assert!(!output.status.success());
-        assert!(
-            String::from_utf8(output.stderr)
-                .unwrap()
-                .contains("error: empty `loop {}` wastes CPU cycles")
-        );
-    };
-
-    // Make sure Cargo is aware of the removal of `--no-deps`.
-    lint_path_dep();
-
-    let successful_build = || {
-        let output = Command::new(&*CLIPPY_PATH)
-            .current_dir(&cwd)
-            .env("CARGO_INCREMENTAL", "0")
-            .arg("clippy")
-            .args(&["-p", "subcrate"])
-            .arg("--")
-            .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
-            .output()
-            .unwrap();
-        println!("status: {}", output.status);
-        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
-        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
-
-        assert!(output.status.success());
-
-        output
-    };
-
-    // Trigger a sucessful build, so Cargo would like to cache the build result.
-    successful_build();
-
-    // Make sure there's no spurious rebuild when nothing changes.
-    let stderr = String::from_utf8(successful_build().stderr).unwrap();
-    assert!(!stderr.contains("Compiling"));
-    assert!(!stderr.contains("Checking"));
-    assert!(stderr.contains("Finished"));
-
-    // Make sure Cargo is aware of the new `--cfg` flag.
-    lint_path_dep();
-}
 
-#[test]
-fn dogfood_subprojects() {
-    // run clippy on remaining subprojects and fail the test if lint warnings are reported
-    if cargo::is_rustc_test_suite() {
-        return;
+    // "" is the root package
+    for package in &["", "clippy_dev", "clippy_lints", "clippy_utils", "rustc_tools_util"] {
+        run_clippy_for_package(package);
     }
-
-    // NOTE: `path_dep` crate is omitted on purpose here
-    for project in &[
-        "clippy_workspace_tests",
-        "clippy_workspace_tests/src",
-        "clippy_workspace_tests/subcrate",
-        "clippy_workspace_tests/subcrate/src",
-        "clippy_dev",
-        "clippy_lints",
-        "clippy_utils",
-        "rustc_tools_util",
-    ] {
-        run_clippy_for_project(project);
-    }
-
-    // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the
-    // same time, so we test this immediately after the dogfood for workspaces.
-    test_no_deps_ignores_path_deps_in_workspaces();
 }
 
 #[test]
 #[ignore]
-#[cfg(feature = "metadata-collector-lint")]
+#[cfg(feature = "internal")]
 fn run_metadata_collection_lint() {
     use std::fs::File;
     use std::time::SystemTime;
@@ -191,7 +38,7 @@ fn run_metadata_collection_lint() {
 
     // Run collection as is
     std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
-    run_clippy_for_project("clippy_lints");
+    run_clippy_for_package("clippy_lints");
 
     // Check if cargo caching got in the way
     if let Ok(file) = File::open(metadata_output_path) {
@@ -214,13 +61,13 @@ fn run_metadata_collection_lint() {
     .unwrap();
 
     // Running the collection again
-    run_clippy_for_project("clippy_lints");
+    run_clippy_for_package("clippy_lints");
 }
 
-fn run_clippy_for_project(project: &str) {
+fn run_clippy_for_package(project: &str) {
     let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
 
-    let mut command = Command::new(&*CLIPPY_PATH);
+    let mut command = Command::new(&*test_utils::CARGO_CLIPPY_PATH);
 
     command
         .current_dir(root_dir.join(project))
@@ -233,8 +80,8 @@ fn run_clippy_for_project(project: &str) {
         .args(&["-D", "clippy::pedantic"])
         .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
 
-    // internal lints only exist if we build with the internal-lints feature
-    if cfg!(feature = "internal-lints") {
+    // internal lints only exist if we build with the internal feature
+    if cfg!(feature = "internal") {
         command.args(&["-D", "clippy::internal"]);
     }
 
index 383702dd439cfb46acbd9c26f516adfab5d4d61c..0defd45b68b064745537b02321f5bb2b56c688aa 100644 (file)
@@ -10,14 +10,6 @@ fn fmt() {
         return;
     }
 
-    // Skip this test if nightly rustfmt is unavailable
-    let rustup_output = Command::new("rustup").args(&["component", "list"]).output().unwrap();
-    assert!(rustup_output.status.success());
-    let component_output = String::from_utf8_lossy(&rustup_output.stdout);
-    if !component_output.contains("rustfmt") {
-        return;
-    }
-
     let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
     let output = Command::new("cargo")
         .current_dir(root_dir)
diff --git a/src/tools/clippy/tests/test_utils/mod.rs b/src/tools/clippy/tests/test_utils/mod.rs
new file mode 100644 (file)
index 0000000..8a4de3f
--- /dev/null
@@ -0,0 +1,13 @@
+#![allow(dead_code)] // see https://github.com/rust-lang/rust/issues/46379
+
+use std::lazy::SyncLazy;
+use std::path::PathBuf;
+
+pub static CARGO_CLIPPY_PATH: SyncLazy<PathBuf> = SyncLazy::new(|| {
+    let mut path = std::env::current_exe().unwrap();
+    assert!(path.pop()); // deps
+    path.set_file_name("cargo-clippy");
+    path
+});
+
+pub const IS_RUSTC_TEST_SUITE: bool = option_env!("RUSTC_TEST_SUITE").is_some();
index 0a8e5427978f53d76fef2f88872ced4bb1af6b8a..0e85088691765820a5bc313ee9cd0a18a6801410 100644 (file)
@@ -1,10 +1,16 @@
+error: invalid path
+  --> $DIR/invalid_paths.rs:15:5
+   |
+LL |     pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::invalid-paths` implied by `-D warnings`
+
 error: invalid path
   --> $DIR/invalid_paths.rs:18:5
    |
 LL |     pub const BAD_CRATE_PATH: [&str; 2] = ["bad", "path"];
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `-D clippy::invalid-paths` implied by `-D warnings`
 
 error: invalid path
   --> $DIR/invalid_paths.rs:21:5
@@ -12,5 +18,5 @@ error: invalid path
 LL |     pub const BAD_MOD_PATH: [&str; 2] = ["std", "xxx"];
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
index f1d4a4619c5dc995105fd11715f4d422e5c4bec9..c902d21123dce0dc9d8200531fe6669275776aba 100644 (file)
@@ -1,6 +1,8 @@
 disallowed-methods = [
     # just a string is shorthand for path only
     "std::iter::Iterator::sum",
+    "f32::clamp",
+    "slice::sort_unstable",
     # can give path and reason with an inline table
     { path = "regex::Regex::is_match", reason = "no matching allowed" },
     # can use an inline table but omit reason
index cb449b45bde8539ead3d7b906a352fd4e3cc17bf..338b3b5b28f429b9700d5849886109698f758242 100644 (file)
@@ -7,6 +7,11 @@ fn main() {
     let re = Regex::new(r"ab.*c").unwrap();
     re.is_match("abc");
 
-    let a = vec![1, 2, 3, 4];
+    let mut a = vec![1, 2, 3, 4];
     a.iter().sum::<i32>();
+
+    a.sort_unstable();
+
+    let _ = 2.0f32.clamp(3.0f32, 4.0f32);
+    let _ = 2.0f64.clamp(3.0f64, 4.0f64);
 }
index 999ead10d51829dae9d73903f9cd2c92df6bb4be..5533676aea287b80677e8ec9f9cd0423dd52e405 100644 (file)
@@ -20,5 +20,17 @@ error: use of a disallowed method `std::iter::Iterator::sum`
 LL |     a.iter().sum::<i32>();
    |     ^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: use of a disallowed method `slice::sort_unstable`
+  --> $DIR/conf_disallowed_methods.rs:13:5
+   |
+LL |     a.sort_unstable();
+   |     ^^^^^^^^^^^^^^^^^
+
+error: use of a disallowed method `f32::clamp`
+  --> $DIR/conf_disallowed_methods.rs:15:13
+   |
+LL |     let _ = 2.0f32.clamp(3.0f32, 4.0f32);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
index cd745feec6d8acc81063dae1d74b6f0a0a4e85e2..ba4394defbf20d75f6f3c33bc47c48123b9fcb4b 100644 (file)
@@ -1,6 +1,7 @@
 // aux-build:macro_rules.rs
 
 #![warn(clippy::as_conversions)]
+#![allow(clippy::borrow_as_ptr)]
 
 #[macro_use]
 extern crate macro_rules;
index f5f75d3aee04a40f2032684353aa310418343389..d11b56171b07211b6bd6f6a4bda0d6947eb32ab7 100644 (file)
@@ -1,5 +1,5 @@
 error: using a potentially dangerous silent `as` conversion
-  --> $DIR/as_conversions.rs:14:13
+  --> $DIR/as_conversions.rs:15:13
    |
 LL |     let i = 0u32 as u64;
    |             ^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL |     let i = 0u32 as u64;
    = help: consider using a safe wrapper for this conversion
 
 error: using a potentially dangerous silent `as` conversion
-  --> $DIR/as_conversions.rs:16:13
+  --> $DIR/as_conversions.rs:17:13
    |
 LL |     let j = &i as *const u64 as *mut u64;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL |     let j = &i as *const u64 as *mut u64;
    = help: consider using a safe wrapper for this conversion
 
 error: using a potentially dangerous silent `as` conversion
-  --> $DIR/as_conversions.rs:16:13
+  --> $DIR/as_conversions.rs:17:13
    |
 LL |     let j = &i as *const u64 as *mut u64;
    |             ^^^^^^^^^^^^^^^^
index cb516d0f97783fee0b7b4a71c3cc9336a5072c64..7477c01ca78283e173392dd12c86c40a210ebe8d 100644 (file)
@@ -1,4 +1,3 @@
-//FIXME: suggestions are wrongly expanded, this should be fixed along with #7843
 #![allow(non_fmt_panics)]
 
 macro_rules! assert_const {
index ec80ec702fb574ad4cf6380b9e7b2179230a8c84..e1f818814d500105c2b69e3a0d979f6ed467fe55 100644 (file)
@@ -1,75 +1,75 @@
 error: `assert!(true)` will be optimized out by the compiler
-  --> $DIR/assertions_on_constants.rs:11:5
+  --> $DIR/assertions_on_constants.rs:10:5
    |
 LL |     assert!(true);
    |     ^^^^^^^^^^^^^
    |
    = note: `-D clippy::assertions-on-constants` implied by `-D warnings`
    = help: remove it
-   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `assert!(false)` should probably be replaced
-  --> $DIR/assertions_on_constants.rs:12:5
+  --> $DIR/assertions_on_constants.rs:11:5
    |
 LL |     assert!(false);
    |     ^^^^^^^^^^^^^^
    |
    = help: use `panic!()` or `unreachable!()`
-   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `assert!(true)` will be optimized out by the compiler
-  --> $DIR/assertions_on_constants.rs:13:5
+  --> $DIR/assertions_on_constants.rs:12:5
    |
 LL |     assert!(true, "true message");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: remove it
-   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
-  --> $DIR/assertions_on_constants.rs:14:5
+error: `assert!(false, ..)` should probably be replaced
+  --> $DIR/assertions_on_constants.rs:13:5
    |
 LL |     assert!(false, "false message");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
-   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = help: use `panic!(..)` or `unreachable!(..)`
+
+error: `assert!(false, ..)` should probably be replaced
+  --> $DIR/assertions_on_constants.rs:16:5
+   |
+LL |     assert!(false, "{}", msg.to_uppercase());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `panic!(..)` or `unreachable!(..)`
 
 error: `assert!(true)` will be optimized out by the compiler
-  --> $DIR/assertions_on_constants.rs:20:5
+  --> $DIR/assertions_on_constants.rs:19:5
    |
 LL |     assert!(B);
    |     ^^^^^^^^^^
    |
    = help: remove it
-   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `assert!(false)` should probably be replaced
-  --> $DIR/assertions_on_constants.rs:23:5
+  --> $DIR/assertions_on_constants.rs:22:5
    |
 LL |     assert!(C);
    |     ^^^^^^^^^^
    |
    = help: use `panic!()` or `unreachable!()`
-   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: `assert!(false, $crate::const_format_args!($($t)+))` should probably be replaced
-  --> $DIR/assertions_on_constants.rs:24:5
+error: `assert!(false, ..)` should probably be replaced
+  --> $DIR/assertions_on_constants.rs:23:5
    |
 LL |     assert!(C, "C message");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: use `panic!($crate::const_format_args!($($t)+))` or `unreachable!($crate::const_format_args!($($t)+))`
-   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = help: use `panic!(..)` or `unreachable!(..)`
 
 error: `debug_assert!(true)` will be optimized out by the compiler
-  --> $DIR/assertions_on_constants.rs:26:5
+  --> $DIR/assertions_on_constants.rs:25:5
    |
 LL |     debug_assert!(true);
    |     ^^^^^^^^^^^^^^^^^^^
    |
    = help: remove it
-   = note: this error originates in the macro `$crate::assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
index f16350e4b5e6d38121a036bb6720a09fd75edc07..471bbce4f4185e2184ca058174d6cfe5480b8006 100644 (file)
@@ -2,7 +2,8 @@ if_chain! {
     if let ExprKind::Repeat(value, length) = expr.kind;
     if let ExprKind::Lit(ref lit) = value.kind;
     if let LitKind::Int(1, LitIntType::Unsigned(UintTy::U8)) = lit.node;
-    let expr1 = &cx.tcx.hir().body(length.body).value;
+    if let ArrayLen::Body(anon_const) = length;
+    let expr1 = &cx.tcx.hir().body(anon_const.body).value;
     if let ExprKind::Lit(ref lit1) = expr1.kind;
     if let LitKind::Int(5, LitIntType::Unsuffixed) = lit1.node;
     then {
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
new file mode 100644 (file)
index 0000000..ff5c6a8
--- /dev/null
@@ -0,0 +1,10 @@
+// run-rustfix
+#![warn(clippy::borrow_as_ptr)]
+
+fn main() {
+    let val = 1;
+    let _p = std::ptr::addr_of!(val);
+
+    let mut val_mut = 1;
+    let _p_mut = std::ptr::addr_of_mut!(val_mut);
+}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs
new file mode 100644 (file)
index 0000000..0f62ec6
--- /dev/null
@@ -0,0 +1,10 @@
+// run-rustfix
+#![warn(clippy::borrow_as_ptr)]
+
+fn main() {
+    let val = 1;
+    let _p = &val as *const i32;
+
+    let mut val_mut = 1;
+    let _p_mut = &mut val_mut as *mut i32;
+}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
new file mode 100644 (file)
index 0000000..be1ed73
--- /dev/null
@@ -0,0 +1,16 @@
+error: borrow as raw pointer
+  --> $DIR/borrow_as_ptr.rs:6:14
+   |
+LL |     let _p = &val as *const i32;
+   |              ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of!(val)`
+   |
+   = note: `-D clippy::borrow-as-ptr` implied by `-D warnings`
+
+error: borrow as raw pointer
+  --> $DIR/borrow_as_ptr.rs:9:18
+   |
+LL |     let _p_mut = &mut val_mut as *mut i32;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed
new file mode 100644 (file)
index 0000000..eaba3b1
--- /dev/null
@@ -0,0 +1,22 @@
+// run-rustfix
+#![warn(clippy::borrow_as_ptr)]
+#![feature(lang_items, start, libc)]
+#![no_std]
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let val = 1;
+    let _p = core::ptr::addr_of!(val);
+
+    let mut val_mut = 1;
+    let _p_mut = core::ptr::addr_of_mut!(val_mut);
+    0
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs
new file mode 100644 (file)
index 0000000..d83f9d1
--- /dev/null
@@ -0,0 +1,22 @@
+// run-rustfix
+#![warn(clippy::borrow_as_ptr)]
+#![feature(lang_items, start, libc)]
+#![no_std]
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let val = 1;
+    let _p = &val as *const i32;
+
+    let mut val_mut = 1;
+    let _p_mut = &mut val_mut as *mut i32;
+    0
+}
+
+#[panic_handler]
+fn panic(_info: &core::panic::PanicInfo) -> ! {
+    loop {}
+}
+
+#[lang = "eh_personality"]
+extern "C" fn eh_personality() {}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr
new file mode 100644 (file)
index 0000000..84c8ba7
--- /dev/null
@@ -0,0 +1,16 @@
+error: borrow as raw pointer
+  --> $DIR/borrow_as_ptr_no_std.rs:9:14
+   |
+LL |     let _p = &val as *const i32;
+   |              ^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of!(val)`
+   |
+   = note: `-D clippy::borrow-as-ptr` implied by `-D warnings`
+
+error: borrow as raw pointer
+  --> $DIR/borrow_as_ptr_no_std.rs:12:18
+   |
+LL |     let _p_mut = &mut val_mut as *mut i32;
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of_mut!(val_mut)`
+
+error: aborting due to 2 previous errors
+
index d011e84b115a7aee99a7f049af33f3fac36be4d2..659591fffbecdb56993cdf8cbd8676430ec52e8c 100644 (file)
@@ -4,7 +4,13 @@
 extern crate libc;
 
 #[warn(clippy::cast_ptr_alignment)]
-#[allow(clippy::no_effect, clippy::unnecessary_operation, clippy::cast_lossless)]
+#[allow(
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::cast_lossless,
+    clippy::borrow_as_ptr
+)]
+
 fn main() {
     /* These should be warned against */
 
index 7998b787b91fbd70cb353d0c1ef990d11e6018d7..aedd368445554b05ad2d1744be82e682081534d4 100644 (file)
@@ -1,5 +1,5 @@
 error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) (1 < 2 bytes)
-  --> $DIR/cast_alignment.rs:12:5
+  --> $DIR/cast_alignment.rs:18:5
    |
 LL |     (&1u8 as *const u8) as *const u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,19 +7,19 @@ LL |     (&1u8 as *const u8) as *const u16;
    = note: `-D clippy::cast-ptr-alignment` implied by `-D warnings`
 
 error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes)
-  --> $DIR/cast_alignment.rs:13:5
+  --> $DIR/cast_alignment.rs:19:5
    |
 LL |     (&mut 1u8 as *mut u8) as *mut u16;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting from `*const u8` to a more-strictly-aligned pointer (`*const u16`) (1 < 2 bytes)
-  --> $DIR/cast_alignment.rs:16:5
+  --> $DIR/cast_alignment.rs:22:5
    |
 LL |     (&1u8 as *const u8).cast::<u16>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: casting from `*mut u8` to a more-strictly-aligned pointer (`*mut u16`) (1 < 2 bytes)
-  --> $DIR/cast_alignment.rs:17:5
+  --> $DIR/cast_alignment.rs:23:5
    |
 LL |     (&mut 1u8 as *mut u8).cast::<u16>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 089e5cfabe4b912fb6b819fa334d6476862a8455..c48a734ba32c26874a19c58d8c6d959fe9e7f066 100644 (file)
@@ -1,5 +1,5 @@
 #![warn(clippy::cast_ref_to_mut)]
-#![allow(clippy::no_effect)]
+#![allow(clippy::no_effect, clippy::borrow_as_ptr)]
 
 extern "C" {
     // N.B., mutability can be easily incorrect in FFI calls -- as
index 0029fc673f1107105b110987b20bd6ff236dfab9..2f489deb1ee1f5910b3acd8038c5de8ac531c877 100644 (file)
@@ -37,6 +37,8 @@ fn main() {
     let b = &a;
 
     let b = *aref;
+
+    let _ = unsafe { *core::ptr::addr_of!(a) };
 }
 
 #[rustfmt::skip]
index f2f02dd5e723d8a78c1918c4f8e597df4239c0aa..49f360b9a7f9e2ca7f7d6275d69f546f764b41d9 100644 (file)
@@ -37,6 +37,8 @@ fn main() {
     let b = *&&a;
 
     let b = **&aref;
+
+    let _ = unsafe { *core::ptr::addr_of!(a) };
 }
 
 #[rustfmt::skip]
index 5bc1cbfa215100e5bdf0c41648e40dc85722927e..75371fcdb9677f476dc1bfaebceaa78cc0685d38 100644 (file)
@@ -49,7 +49,7 @@ LL |     let b = **&aref;
    |              ^^^^^^ help: try this: `aref`
 
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:45:9
+  --> $DIR/deref_addrof.rs:47:9
    |
 LL |         *& $visitor
    |         ^^^^^^^^^^^ help: try this: `$visitor`
@@ -60,7 +60,7 @@ LL |         m!(self)
    = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: immediately dereferencing a reference
-  --> $DIR/deref_addrof.rs:52:9
+  --> $DIR/deref_addrof.rs:54:9
    |
 LL |         *& mut $visitor
    |         ^^^^^^^^^^^^^^^ help: try this: `$visitor`
index 885415b42c78735c2c12bdfe385a9aea8a821292..cd9f1826e59bf292d5b00cbe4381d6c178d12a71 100644 (file)
@@ -21,6 +21,28 @@ LL |     assert_in_macro_def!();
    |
    = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+error: identical args used in this `debug_assert_eq!` macro call
+  --> $DIR/eq_op_macros.rs:9:26
+   |
+LL |         debug_assert_eq!(a, a);
+   |                          ^^^^
+...
+LL |     assert_in_macro_def!();
+   |     ---------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: identical args used in this `debug_assert_ne!` macro call
+  --> $DIR/eq_op_macros.rs:10:26
+   |
+LL |         debug_assert_ne!(a, a);
+   |                          ^^^^
+...
+LL |     assert_in_macro_def!();
+   |     ---------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info)
+
 error: identical args used in this `assert_eq!` macro call
   --> $DIR/eq_op_macros.rs:22:16
    |
@@ -45,28 +67,6 @@ error: identical args used in this `assert_ne!` macro call
 LL |     assert_ne!(a + 1, a + 1);
    |                ^^^^^^^^^^^^
 
-error: identical args used in this `debug_assert_eq!` macro call
-  --> $DIR/eq_op_macros.rs:9:26
-   |
-LL |         debug_assert_eq!(a, a);
-   |                          ^^^^
-...
-LL |     assert_in_macro_def!();
-   |     ---------------------- in this macro invocation
-   |
-   = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: identical args used in this `debug_assert_ne!` macro call
-  --> $DIR/eq_op_macros.rs:10:26
-   |
-LL |         debug_assert_ne!(a, a);
-   |                          ^^^^
-...
-LL |     assert_in_macro_def!();
-   |     ---------------------- in this macro invocation
-   |
-   = note: this error originates in the macro `assert_in_macro_def` (in Nightly builds, run with -Z macro-backtrace for more info)
-
 error: identical args used in this `debug_assert_eq!` macro call
   --> $DIR/eq_op_macros.rs:38:22
    |
index 1540062a4bc3ea106dbe64d46462f7016e5caf25..ae2fad0086daa0af39d6838418b407dfcad2c1a9 100644 (file)
@@ -1,3 +1,34 @@
+struct Length(u8);
+struct Meter;
+
+impl core::ops::Mul<Meter> for u8 {
+    type Output = Length;
+    fn mul(self, _: Meter) -> Length {
+        Length(self)
+    }
+}
+
+#[derive(Clone, Default, PartialEq, Eq, Hash)]
+struct Vec1 {
+    x: i32,
+}
+
+impl core::ops::Mul<Vec1> for i32 {
+    type Output = Vec1;
+    fn mul(self, mut right: Vec1) -> Vec1 {
+        right.x *= self;
+        right
+    }
+}
+
+impl core::ops::Mul<i32> for Vec1 {
+    type Output = Vec1;
+    fn mul(mut self, right: i32) -> Vec1 {
+        self.x *= right;
+        self
+    }
+}
+
 #[allow(clippy::no_effect)]
 #[warn(clippy::erasing_op)]
 fn main() {
@@ -6,4 +37,7 @@ fn main() {
     x * 0;
     0 & x;
     0 / x;
+    0 * Meter; // no error: Output type is different from the non-zero argument
+    0 * Vec1 { x: 5 };
+    Vec1 { x: 5 } * 0;
 }
index e54ce85f98ec78b4ddf7730bd064ebfc9a258a4d..165ed9bfe58b1b0bda9f79560e47a457d2964a43 100644 (file)
@@ -1,5 +1,5 @@
 error: this operation will always return zero. This is likely not the intended outcome
-  --> $DIR/erasing_op.rs:6:5
+  --> $DIR/erasing_op.rs:37:5
    |
 LL |     x * 0;
    |     ^^^^^
@@ -7,16 +7,28 @@ LL |     x * 0;
    = note: `-D clippy::erasing-op` implied by `-D warnings`
 
 error: this operation will always return zero. This is likely not the intended outcome
-  --> $DIR/erasing_op.rs:7:5
+  --> $DIR/erasing_op.rs:38:5
    |
 LL |     0 & x;
    |     ^^^^^
 
 error: this operation will always return zero. This is likely not the intended outcome
-  --> $DIR/erasing_op.rs:8:5
+  --> $DIR/erasing_op.rs:39:5
    |
 LL |     0 / x;
    |     ^^^^^
 
-error: aborting due to 3 previous errors
+error: this operation will always return zero. This is likely not the intended outcome
+  --> $DIR/erasing_op.rs:41:5
+   |
+LL |     0 * Vec1 { x: 5 };
+   |     ^^^^^^^^^^^^^^^^^
+
+error: this operation will always return zero. This is likely not the intended outcome
+  --> $DIR/erasing_op.rs:42:5
+   |
+LL |     Vec1 { x: 5 } * 0;
+   |     ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
 
index 1de79667f55fb51132117565b5197338612f4b73..f938f7106884416bb1d748f94f90a85a85ac131d 100644 (file)
@@ -248,3 +248,14 @@ mod type_param_bound {
         take(X::fun as fn());
     }
 }
+
+// #8073 Don't replace closure with `Arc<F>` or `Rc<F>`
+fn arc_fp() {
+    let rc = std::rc::Rc::new(|| 7);
+    let arc = std::sync::Arc::new(|n| n + 1);
+    let ref_arc = &std::sync::Arc::new(|_| 5);
+
+    true.then(|| rc());
+    (0..5).map(|n| arc(n));
+    Some(4).map(|n| ref_arc(n));
+}
index 86abd347baa7885645fed4ebefe3f7d2d985d1ce..075bbc74922f91fa18b1ace10ec3689212e00a72 100644 (file)
@@ -248,3 +248,14 @@ fn test<X: Trait>() {
         take(X::fun as fn());
     }
 }
+
+// #8073 Don't replace closure with `Arc<F>` or `Rc<F>`
+fn arc_fp() {
+    let rc = std::rc::Rc::new(|| 7);
+    let arc = std::sync::Arc::new(|n| n + 1);
+    let ref_arc = &std::sync::Arc::new(|_| 5);
+
+    true.then(|| rc());
+    (0..5).map(|n| arc(n));
+    Some(4).map(|n| ref_arc(n));
+}
index 2ed4b5db574d42aabae78102fc94d00e24c9b4ce..12bbda71f434813ca78c1e499bb3d70e82106490 100644 (file)
@@ -11,6 +11,17 @@ fn shl(mut self, other: i32) -> Self {
         self
     }
 }
+
+struct Length(u8);
+struct Meter;
+
+impl core::ops::Mul<Meter> for u8 {
+    type Output = Length;
+    fn mul(self, _: Meter) -> Length {
+        Length(self)
+    }
+}
+
 #[allow(
     clippy::eq_op,
     clippy::no_effect,
@@ -53,4 +64,6 @@ fn main() {
 
     let mut a = A("".into());
     let b = a << 0; // no error: non-integer
+
+    1 * Meter; // no error: non-integer
 }
index ff34b38db015bbf49077a823bf35b03b5a45d050..0103cf5457e81a8a313dc1b78506497679903647 100644 (file)
@@ -1,5 +1,5 @@
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:26:5
+  --> $DIR/identity_op.rs:37:5
    |
 LL |     x + 0;
    |     ^^^^^
@@ -7,73 +7,73 @@ LL |     x + 0;
    = note: `-D clippy::identity-op` implied by `-D warnings`
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:27:5
+  --> $DIR/identity_op.rs:38:5
    |
 LL |     x + (1 - 1);
    |     ^^^^^^^^^^^
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:29:5
+  --> $DIR/identity_op.rs:40:5
    |
 LL |     0 + x;
    |     ^^^^^
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:32:5
+  --> $DIR/identity_op.rs:43:5
    |
 LL |     x | (0);
    |     ^^^^^^^
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:35:5
+  --> $DIR/identity_op.rs:46:5
    |
 LL |     x * 1;
    |     ^^^^^
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:36:5
+  --> $DIR/identity_op.rs:47:5
    |
 LL |     1 * x;
    |     ^^^^^
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:42:5
+  --> $DIR/identity_op.rs:53:5
    |
 LL |     -1 & x;
    |     ^^^^^^
 
 error: the operation is ineffective. Consider reducing it to `u`
-  --> $DIR/identity_op.rs:45:5
+  --> $DIR/identity_op.rs:56:5
    |
 LL |     u & 255;
    |     ^^^^^^^
 
 error: the operation is ineffective. Consider reducing it to `42`
-  --> $DIR/identity_op.rs:48:5
+  --> $DIR/identity_op.rs:59:5
    |
 LL |     42 << 0;
    |     ^^^^^^^
 
 error: the operation is ineffective. Consider reducing it to `1`
-  --> $DIR/identity_op.rs:49:5
+  --> $DIR/identity_op.rs:60:5
    |
 LL |     1 >> 0;
    |     ^^^^^^
 
 error: the operation is ineffective. Consider reducing it to `42`
-  --> $DIR/identity_op.rs:50:5
+  --> $DIR/identity_op.rs:61:5
    |
 LL |     42 >> 0;
    |     ^^^^^^^
 
 error: the operation is ineffective. Consider reducing it to `&x`
-  --> $DIR/identity_op.rs:51:5
+  --> $DIR/identity_op.rs:62:5
    |
 LL |     &x >> 0;
    |     ^^^^^^^
 
 error: the operation is ineffective. Consider reducing it to `x`
-  --> $DIR/identity_op.rs:52:5
+  --> $DIR/identity_op.rs:63:5
    |
 LL |     x >> &0;
    |     ^^^^^^^
index 20419457b47f0ee3018f9ec888939e1d96cfbae4..e5042aaa776b4dbceeaa9297cc91535d4a23cad2 100644 (file)
@@ -12,5 +12,14 @@ error: explicit lifetimes given in parameter types where they could be elided (o
 LL | async fn one_to_one<'a>(s: &'a str) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: methods called `new` usually take no `self`
+  --> $DIR/issue_4266.rs:27:22
+   |
+LL |     pub async fn new(&mut self) -> Self {
+   |                      ^^^^^^^^^
+   |
+   = note: `-D clippy::wrong-self-convention` implied by `-D warnings`
+   = help: consider choosing a less ambiguous name
+
+error: aborting due to 3 previous errors
 
index 377f760b3c4b20c26ad51cb0d3d1b5dd8169aa01..2c91e02e84223cd3257a4b898ac739ac9b675415 100644 (file)
@@ -44,4 +44,24 @@ fn next(&mut self) -> Option<Self::Item> {
     }
 }
 
+// Issue #8225
+trait Iter {
+    type I;
+    fn iter(&self) -> Self::I;
+}
+
+impl Iter for () {
+    type I = core::slice::Iter<'static, ()>;
+    fn iter(&self) -> Self::I {
+        [].iter()
+    }
+}
+
+struct S;
+impl S {
+    fn iter(&self) -> <() as Iter>::I {
+        ().iter()
+    }
+}
+
 fn main() {}
index 2273cd0be66ffe2c11562a78733726214feb951e..44f0295583695bfadd40376d53fd383c76ad0872 100644 (file)
@@ -12,5 +12,11 @@ error: this method is named `iter_mut` but its return type does not implement `I
 LL |     fn iter_mut(&self) -> Counter2 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: this method is named `iter` but its return type does not implement `Iterator`
+  --> $DIR/iter_not_returning_iterator.rs:50:5
+   |
+LL |     fn iter(&self) -> Self::I;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
 
index 9171558f3a2d74d1f79d2c9b62d6a3282db33b82..306ea50258da00ad0d133616dc85c1a0a4549450 100644 (file)
@@ -40,7 +40,7 @@ mod a {
     }
 }
 
-// issue #7015, ICE due to calling `item_children` with local `DefId`
+// issue #7015, ICE due to calling `module_children` with local `DefId`
 #[macro_use]
 use a as b;
 
index cd01fd43f6d325eefb79e07d1bc71753ef1a164c..e26a7545ea6f83fc054291bbdce5521d5c27c93d 100644 (file)
@@ -40,7 +40,7 @@ fn test() {
     }
 }
 
-// issue #7015, ICE due to calling `item_children` with local `DefId`
+// issue #7015, ICE due to calling `module_children` with local `DefId`
 #[macro_use]
 use a as b;
 
diff --git a/src/tools/clippy/tests/ui/manual_bits.fixed b/src/tools/clippy/tests/ui/manual_bits.fixed
new file mode 100644 (file)
index 0000000..4f1b19b
--- /dev/null
@@ -0,0 +1,48 @@
+// run-rustfix
+
+#![warn(clippy::manual_bits)]
+#![allow(clippy::no_effect, path_statements, unused_must_use, clippy::unnecessary_operation)]
+
+use std::mem::{size_of, size_of_val};
+
+fn main() {
+    i8::BITS;
+    i16::BITS;
+    i32::BITS;
+    i64::BITS;
+    i128::BITS;
+    isize::BITS;
+
+    u8::BITS;
+    u16::BITS;
+    u32::BITS;
+    u64::BITS;
+    u128::BITS;
+    usize::BITS;
+
+    i8::BITS;
+    i16::BITS;
+    i32::BITS;
+    i64::BITS;
+    i128::BITS;
+    isize::BITS;
+
+    u8::BITS;
+    u16::BITS;
+    u32::BITS;
+    u64::BITS;
+    u128::BITS;
+    usize::BITS;
+
+    size_of::<usize>() * 4;
+    4 * size_of::<usize>();
+    size_of::<bool>() * 8;
+    8 * size_of::<bool>();
+
+    size_of_val(&0u32) * 8;
+
+    type Word = u32;
+    Word::BITS;
+    type Bool = bool;
+    size_of::<Bool>() * 8;
+}
diff --git a/src/tools/clippy/tests/ui/manual_bits.rs b/src/tools/clippy/tests/ui/manual_bits.rs
new file mode 100644 (file)
index 0000000..f8a0131
--- /dev/null
@@ -0,0 +1,48 @@
+// run-rustfix
+
+#![warn(clippy::manual_bits)]
+#![allow(clippy::no_effect, path_statements, unused_must_use, clippy::unnecessary_operation)]
+
+use std::mem::{size_of, size_of_val};
+
+fn main() {
+    size_of::<i8>() * 8;
+    size_of::<i16>() * 8;
+    size_of::<i32>() * 8;
+    size_of::<i64>() * 8;
+    size_of::<i128>() * 8;
+    size_of::<isize>() * 8;
+
+    size_of::<u8>() * 8;
+    size_of::<u16>() * 8;
+    size_of::<u32>() * 8;
+    size_of::<u64>() * 8;
+    size_of::<u128>() * 8;
+    size_of::<usize>() * 8;
+
+    8 * size_of::<i8>();
+    8 * size_of::<i16>();
+    8 * size_of::<i32>();
+    8 * size_of::<i64>();
+    8 * size_of::<i128>();
+    8 * size_of::<isize>();
+
+    8 * size_of::<u8>();
+    8 * size_of::<u16>();
+    8 * size_of::<u32>();
+    8 * size_of::<u64>();
+    8 * size_of::<u128>();
+    8 * size_of::<usize>();
+
+    size_of::<usize>() * 4;
+    4 * size_of::<usize>();
+    size_of::<bool>() * 8;
+    8 * size_of::<bool>();
+
+    size_of_val(&0u32) * 8;
+
+    type Word = u32;
+    size_of::<Word>() * 8;
+    type Bool = bool;
+    size_of::<Bool>() * 8;
+}
diff --git a/src/tools/clippy/tests/ui/manual_bits.stderr b/src/tools/clippy/tests/ui/manual_bits.stderr
new file mode 100644 (file)
index 0000000..c4f5af2
--- /dev/null
@@ -0,0 +1,154 @@
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:9:5
+   |
+LL |     size_of::<i8>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS`
+   |
+   = note: `-D clippy::manual-bits` implied by `-D warnings`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:10:5
+   |
+LL |     size_of::<i16>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:11:5
+   |
+LL |     size_of::<i32>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:12:5
+   |
+LL |     size_of::<i64>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:13:5
+   |
+LL |     size_of::<i128>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:14:5
+   |
+LL |     size_of::<isize>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:16:5
+   |
+LL |     size_of::<u8>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:17:5
+   |
+LL |     size_of::<u16>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:18:5
+   |
+LL |     size_of::<u32>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:19:5
+   |
+LL |     size_of::<u64>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:20:5
+   |
+LL |     size_of::<u128>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:21:5
+   |
+LL |     size_of::<usize>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:23:5
+   |
+LL |     8 * size_of::<i8>();
+   |     ^^^^^^^^^^^^^^^^^^^ help: consider using: `i8::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:24:5
+   |
+LL |     8 * size_of::<i16>();
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i16::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:25:5
+   |
+LL |     8 * size_of::<i32>();
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i32::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:26:5
+   |
+LL |     8 * size_of::<i64>();
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `i64::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:27:5
+   |
+LL |     8 * size_of::<i128>();
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `i128::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:28:5
+   |
+LL |     8 * size_of::<isize>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `isize::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:30:5
+   |
+LL |     8 * size_of::<u8>();
+   |     ^^^^^^^^^^^^^^^^^^^ help: consider using: `u8::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:31:5
+   |
+LL |     8 * size_of::<u16>();
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u16::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:32:5
+   |
+LL |     8 * size_of::<u32>();
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u32::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:33:5
+   |
+LL |     8 * size_of::<u64>();
+   |     ^^^^^^^^^^^^^^^^^^^^ help: consider using: `u64::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:34:5
+   |
+LL |     8 * size_of::<u128>();
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `u128::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:35:5
+   |
+LL |     8 * size_of::<usize>();
+   |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `usize::BITS`
+
+error: usage of `mem::size_of::<T>()` to obtain the size of `T` in bits
+  --> $DIR/manual_bits.rs:45:5
+   |
+LL |     size_of::<Word>() * 8;
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `Word::BITS`
+
+error: aborting due to 25 previous errors
+
index 2e3ebadd7b5d2c580d2c89b09898d01b67f00adc..79d40c0bcb1d984d12415e109ad711e2d2d02103 100644 (file)
@@ -5,7 +5,7 @@ LL | /     for i in 3..src.len() {
 LL | |         dst[i] = src[count];
 LL | |         count += 1;
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)]);`
+   | |_____^ help: try replacing the loop by: `dst[3..src.len()].copy_from_slice(&src[..(src.len() - 3)]);`
    |
    = note: `-D clippy::manual-memcpy` implied by `-D warnings`
 
@@ -16,7 +16,7 @@ LL | /     for i in 3..src.len() {
 LL | |         dst[count] = src[i];
 LL | |         count += 1;
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[..(src.len() - 3)].clone_from_slice(&src[3..]);`
+   | |_____^ help: try replacing the loop by: `dst[..(src.len() - 3)].copy_from_slice(&src[3..]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/with_loop_counters.rs:17:5
@@ -25,7 +25,7 @@ LL | /     for i in 0..src.len() {
 LL | |         dst[count] = src[i];
 LL | |         count += 1;
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[3..(src.len() + 3)].clone_from_slice(&src[..]);`
+   | |_____^ help: try replacing the loop by: `dst[3..(src.len() + 3)].copy_from_slice(&src[..]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/with_loop_counters.rs:23:5
@@ -34,7 +34,7 @@ LL | /     for i in 0..src.len() {
 LL | |         dst[i] = src[count];
 LL | |         count += 1;
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[3..(src.len() + 3)]);`
+   | |_____^ help: try replacing the loop by: `dst[..src.len()].copy_from_slice(&src[3..(src.len() + 3)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/with_loop_counters.rs:29:5
@@ -43,7 +43,7 @@ LL | /     for i in 3..(3 + src.len()) {
 LL | |         dst[i] = src[count];
 LL | |         count += 1;
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[3..(3 + src.len())].clone_from_slice(&src[..(3 + src.len() - 3)]);`
+   | |_____^ help: try replacing the loop by: `dst[3..(3 + src.len())].copy_from_slice(&src[..(3 + src.len() - 3)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/with_loop_counters.rs:35:5
@@ -52,7 +52,7 @@ LL | /     for i in 5..src.len() {
 LL | |         dst[i] = src[count - 2];
 LL | |         count += 1;
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[5..src.len()].clone_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)]);`
+   | |_____^ help: try replacing the loop by: `dst[5..src.len()].copy_from_slice(&src[(3 - 2)..((src.len() - 2) + 3 - 5)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/with_loop_counters.rs:41:5
@@ -61,7 +61,7 @@ LL | /     for i in 0..dst.len() {
 LL | |         dst[i] = src[count];
 LL | |         count += 1;
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst.clone_from_slice(&src[2..(dst.len() + 2)]);`
+   | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[2..(dst.len() + 2)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/with_loop_counters.rs:47:5
@@ -70,7 +70,7 @@ LL | /     for i in 3..10 {
 LL | |         dst[i] = src[count];
 LL | |         count += 1;
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[3..10].clone_from_slice(&src[5..(10 + 5 - 3)]);`
+   | |_____^ help: try replacing the loop by: `dst[3..10].copy_from_slice(&src[5..(10 + 5 - 3)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/with_loop_counters.rs:54:5
@@ -85,8 +85,8 @@ LL | |     }
    |
 help: try replacing the loop by
    |
-LL ~     dst[3..(src.len() + 3)].clone_from_slice(&src[..]);
-LL +     dst2[30..(src.len() + 30)].clone_from_slice(&src[..]);
+LL ~     dst[3..(src.len() + 3)].copy_from_slice(&src[..]);
+LL +     dst2[30..(src.len() + 30)].copy_from_slice(&src[..]);
    |
 
 error: it looks like you're manually copying between slices
@@ -96,7 +96,7 @@ LL | /     for i in 0..1 << 1 {
 LL | |         dst[count] = src[i + 2];
 LL | |         count += 1;
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].clone_from_slice(&src[2..((1 << 1) + 2)]);`
+   | |_____^ help: try replacing the loop by: `dst[(0 << 1)..((1 << 1) + (0 << 1))].copy_from_slice(&src[2..((1 << 1) + 2)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/with_loop_counters.rs:71:5
@@ -105,7 +105,7 @@ LL | /     for i in 3..src.len() {
 LL | |         dst[i] = src[count];
 LL | |         count += 1
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[3..src.len()].clone_from_slice(&src[..(src.len() - 3)]);`
+   | |_____^ help: try replacing the loop by: `dst[3..src.len()].copy_from_slice(&src[..(src.len() - 3)]);`
 
 error: aborting due to 11 previous errors
 
index 0083f94798fe4b2c650998d439f05cda4e7b0d0c..ea0535d076b81911d99676b6d785afe22141544a 100644 (file)
@@ -113,6 +113,17 @@ fn index(&self, _: usize) -> &i32 {
     for i in 0.. {
         dst[i] = src[i];
     }
+
+    // VecDeque - ideally this would work, but would require something like `range_as_slices`
+    let mut dst = std::collections::VecDeque::from_iter([0; 5]);
+    let src = std::collections::VecDeque::from_iter([0, 1, 2, 3, 4]);
+    for i in 0..dst.len() {
+        dst[i] = src[i];
+    }
+    let src = vec![0, 1, 2, 3, 4];
+    for i in 0..dst.len() {
+        dst[i] = src[i];
+    }
 }
 
 #[warn(clippy::needless_range_loop, clippy::manual_memcpy)]
index 8ff0137a8120e1a413ce53da92a3cfac11675f55..c163ae061dfc934235b87a4b5ef0c8971ae370e5 100644 (file)
@@ -4,7 +4,7 @@ error: it looks like you're manually copying between slices
 LL | /     for i in 0..src.len() {
 LL | |         dst[i] = src[i];
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[..]);`
+   | |_____^ help: try replacing the loop by: `dst[..src.len()].copy_from_slice(&src[..]);`
    |
    = note: `-D clippy::manual-memcpy` implied by `-D warnings`
 
@@ -14,7 +14,7 @@ error: it looks like you're manually copying between slices
 LL | /     for i in 0..src.len() {
 LL | |         dst[i + 10] = src[i];
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[10..(src.len() + 10)].clone_from_slice(&src[..]);`
+   | |_____^ help: try replacing the loop by: `dst[10..(src.len() + 10)].copy_from_slice(&src[..]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/without_loop_counters.rs:17:5
@@ -22,7 +22,7 @@ error: it looks like you're manually copying between slices
 LL | /     for i in 0..src.len() {
 LL | |         dst[i] = src[i + 10];
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[..src.len()].clone_from_slice(&src[10..(src.len() + 10)]);`
+   | |_____^ help: try replacing the loop by: `dst[..src.len()].copy_from_slice(&src[10..(src.len() + 10)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/without_loop_counters.rs:22:5
@@ -30,7 +30,7 @@ error: it looks like you're manually copying between slices
 LL | /     for i in 11..src.len() {
 LL | |         dst[i] = src[i - 10];
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[11..src.len()].clone_from_slice(&src[(11 - 10)..(src.len() - 10)]);`
+   | |_____^ help: try replacing the loop by: `dst[11..src.len()].copy_from_slice(&src[(11 - 10)..(src.len() - 10)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/without_loop_counters.rs:27:5
@@ -38,7 +38,7 @@ error: it looks like you're manually copying between slices
 LL | /     for i in 0..dst.len() {
 LL | |         dst[i] = src[i];
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst.clone_from_slice(&src[..dst.len()]);`
+   | |_____^ help: try replacing the loop by: `dst.copy_from_slice(&src[..dst.len()]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/without_loop_counters.rs:40:5
@@ -51,8 +51,8 @@ LL | |     }
    |
 help: try replacing the loop by
    |
-LL ~     dst[10..256].clone_from_slice(&src[(10 - 5)..(256 - 5)]);
-LL +     dst2[(10 + 500)..(256 + 500)].clone_from_slice(&src[10..256]);
+LL ~     dst[10..256].copy_from_slice(&src[(10 - 5)..(256 - 5)]);
+LL +     dst2[(10 + 500)..(256 + 500)].copy_from_slice(&src[10..256]);
    |
 
 error: it looks like you're manually copying between slices
@@ -61,7 +61,7 @@ error: it looks like you're manually copying between slices
 LL | /     for i in 10..LOOP_OFFSET {
 LL | |         dst[i + LOOP_OFFSET] = src[i - some_var];
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].clone_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)]);`
+   | |_____^ help: try replacing the loop by: `dst[(10 + LOOP_OFFSET)..(LOOP_OFFSET + LOOP_OFFSET)].copy_from_slice(&src[(10 - some_var)..(LOOP_OFFSET - some_var)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/without_loop_counters.rs:65:5
@@ -69,7 +69,7 @@ error: it looks like you're manually copying between slices
 LL | /     for i in 0..src_vec.len() {
 LL | |         dst_vec[i] = src_vec[i];
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst_vec[..src_vec.len()].clone_from_slice(&src_vec[..]);`
+   | |_____^ help: try replacing the loop by: `dst_vec[..src_vec.len()].copy_from_slice(&src_vec[..]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/without_loop_counters.rs:94:5
@@ -77,7 +77,7 @@ error: it looks like you're manually copying between slices
 LL | /     for i in from..from + src.len() {
 LL | |         dst[i] = src[i - from];
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[from..(from + src.len())].clone_from_slice(&src[..(from + src.len() - from)]);`
+   | |_____^ help: try replacing the loop by: `dst[from..(from + src.len())].copy_from_slice(&src[..(from + src.len() - from)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/without_loop_counters.rs:98:5
@@ -85,7 +85,7 @@ error: it looks like you're manually copying between slices
 LL | /     for i in from..from + 3 {
 LL | |         dst[i] = src[i - from];
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[from..(from + 3)].clone_from_slice(&src[..(from + 3 - from)]);`
+   | |_____^ help: try replacing the loop by: `dst[from..(from + 3)].copy_from_slice(&src[..(from + 3 - from)]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/without_loop_counters.rs:103:5
@@ -93,7 +93,7 @@ error: it looks like you're manually copying between slices
 LL | /     for i in 0..5 {
 LL | |         dst[i - 0] = src[i];
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[..5].clone_from_slice(&src[..5]);`
+   | |_____^ help: try replacing the loop by: `dst[..5].copy_from_slice(&src[..5]);`
 
 error: it looks like you're manually copying between slices
   --> $DIR/without_loop_counters.rs:108:5
@@ -101,10 +101,10 @@ error: it looks like you're manually copying between slices
 LL | /     for i in 0..0 {
 LL | |         dst[i] = src[i];
 LL | |     }
-   | |_____^ help: try replacing the loop by: `dst[..0].clone_from_slice(&src[..0]);`
+   | |_____^ help: try replacing the loop by: `dst[..0].copy_from_slice(&src[..0]);`
 
 error: it looks like you're manually copying between slices
-  --> $DIR/without_loop_counters.rs:120:5
+  --> $DIR/without_loop_counters.rs:131:5
    |
 LL | /     for i in 0..src.len() {
 LL | |         dst[i] = src[i].clone();
index 8bccbaefe23c5611d4e00ec7c9a177c303f23ffd..91ebd695238bb8db80da5f73388c0659768b64a9 100644 (file)
@@ -27,7 +27,6 @@ note: first possible panic found here
    |
 LL |     panic!("This function panics")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: docs for function which may panic missing `# Panics` section
   --> $DIR/missing_panics_doc.rs:17:1
@@ -42,7 +41,6 @@ note: first possible panic found here
    |
 LL |     todo!()
    |     ^^^^^^^
-   = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: docs for function which may panic missing `# Panics` section
   --> $DIR/missing_panics_doc.rs:22:1
@@ -61,7 +59,6 @@ note: first possible panic found here
    |
 LL |             panic!()
    |             ^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: docs for function which may panic missing `# Panics` section
   --> $DIR/missing_panics_doc.rs:31:1
@@ -76,7 +73,6 @@ note: first possible panic found here
    |
 LL |     if true { unreachable!() } else { panic!() }
    |                                       ^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: docs for function which may panic missing `# Panics` section
   --> $DIR/missing_panics_doc.rs:36:1
@@ -92,7 +88,6 @@ note: first possible panic found here
    |
 LL |     assert_eq!(x, 0);
    |     ^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: docs for function which may panic missing `# Panics` section
   --> $DIR/missing_panics_doc.rs:42:1
@@ -108,7 +103,6 @@ note: first possible panic found here
    |
 LL |     assert_ne!(x, 0);
    |     ^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 7 previous errors
 
index b9d78b7f47924840a10793dbd7b1df58ea759fd9..47b3dad3989779188290cf5ede5cf10a443e076b 100644 (file)
@@ -1,5 +1,7 @@
 #![warn(clippy::all)]
 #![warn(clippy::mutex_integer)]
+#![warn(clippy::mutex_atomic)]
+#![allow(clippy::borrow_as_ptr)]
 
 fn main() {
     use std::sync::Mutex;
index a3511ba708a885f808e6f4afd7d257149951c891..262028a8723a3f9a2931d13f3a3ef08c0a8ad70a 100644 (file)
@@ -1,5 +1,5 @@
 error: consider using an `AtomicBool` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> $DIR/mutex_atomic.rs:6:5
+  --> $DIR/mutex_atomic.rs:8:5
    |
 LL |     Mutex::new(true);
    |     ^^^^^^^^^^^^^^^^
@@ -7,31 +7,31 @@ LL |     Mutex::new(true);
    = note: `-D clippy::mutex-atomic` implied by `-D warnings`
 
 error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> $DIR/mutex_atomic.rs:7:5
+  --> $DIR/mutex_atomic.rs:9:5
    |
 LL |     Mutex::new(5usize);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> $DIR/mutex_atomic.rs:8:5
+  --> $DIR/mutex_atomic.rs:10:5
    |
 LL |     Mutex::new(9isize);
    |     ^^^^^^^^^^^^^^^^^^
 
 error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> $DIR/mutex_atomic.rs:10:5
+  --> $DIR/mutex_atomic.rs:12:5
    |
 LL |     Mutex::new(&x as *const u32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> $DIR/mutex_atomic.rs:11:5
+  --> $DIR/mutex_atomic.rs:13:5
    |
 LL |     Mutex::new(&mut x as *mut u32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> $DIR/mutex_atomic.rs:12:5
+  --> $DIR/mutex_atomic.rs:14:5
    |
 LL |     Mutex::new(0u32);
    |     ^^^^^^^^^^^^^^^^
@@ -39,7 +39,7 @@ LL |     Mutex::new(0u32);
    = note: `-D clippy::mutex-integer` implied by `-D warnings`
 
 error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
-  --> $DIR/mutex_atomic.rs:13:5
+  --> $DIR/mutex_atomic.rs:15:5
    |
 LL |     Mutex::new(0i32);
    |     ^^^^^^^^^^^^^^^^
index d6d6ab49734e782ba7887824e86d41a8f29bcc22..87cdb3ace47cb68176d4f4f6921313f55017cc9e 100644 (file)
@@ -2,7 +2,7 @@
 
 #![warn(clippy::or_fun_call)]
 #![allow(dead_code)]
-#![allow(clippy::unnecessary_wraps)]
+#![allow(clippy::unnecessary_wraps, clippy::borrow_as_ptr)]
 
 use std::collections::BTreeMap;
 use std::collections::HashMap;
index 8eadc6ce3b47acace2c3fcf4cea29fd2db831b92..3f69cef301c8b1b96d262067a2e719b1b6056735 100644 (file)
@@ -2,7 +2,7 @@
 
 #![warn(clippy::or_fun_call)]
 #![allow(dead_code)]
-#![allow(clippy::unnecessary_wraps)]
+#![allow(clippy::unnecessary_wraps, clippy::borrow_as_ptr)]
 
 use std::collections::BTreeMap;
 use std::collections::HashMap;
index 78d09b8b2108a134b0c91a4c37e5bbd238de6387..561503ae54fa22d67995e7dc8f60f88036f94bb5 100644 (file)
@@ -14,7 +14,6 @@ note: return Err() instead of panicking
    |
 LL |         panic!("error");
    |         ^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
   --> $DIR/panic_in_result_fn.rs:11:5
@@ -31,7 +30,6 @@ note: return Err() instead of panicking
    |
 LL |         unimplemented!();
    |         ^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
   --> $DIR/panic_in_result_fn.rs:16:5
@@ -48,7 +46,6 @@ note: return Err() instead of panicking
    |
 LL |         unreachable!();
    |         ^^^^^^^^^^^^^^
-   = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
   --> $DIR/panic_in_result_fn.rs:21:5
@@ -65,7 +62,6 @@ note: return Err() instead of panicking
    |
 LL |         todo!("Finish this");
    |         ^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
   --> $DIR/panic_in_result_fn.rs:52:1
@@ -82,7 +78,6 @@ note: return Err() instead of panicking
    |
 LL |     panic!("error");
    |     ^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
   --> $DIR/panic_in_result_fn.rs:67:1
@@ -99,7 +94,6 @@ note: return Err() instead of panicking
    |
 LL |     todo!("finish main method");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 6 previous errors
 
index 7501d6d85edd78f1e0c1d375af6bc4d570cac889..b6aa005e7b521364cce80a4c6b4014eef9d83ad2 100644 (file)
@@ -15,7 +15,6 @@ note: return Err() instead of panicking
    |
 LL |         assert!(x == 5, "wrong argument");
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
   --> $DIR/panic_in_result_fn_assertions.rs:13:5
@@ -33,7 +32,6 @@ note: return Err() instead of panicking
    |
 LL |         assert_eq!(x, 5);
    |         ^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: used `unimplemented!()`, `unreachable!()`, `todo!()`, `panic!()` or assertion in a function that returns `Result`
   --> $DIR/panic_in_result_fn_assertions.rs:19:5
@@ -51,7 +49,6 @@ note: return Err() instead of panicking
    |
 LL |         assert_ne!(x, 1);
    |         ^^^^^^^^^^^^^^^^
-   = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 3 previous errors
 
index 2b607ff5888958bffad99388acc43754d1524264..bfd1c7a380149b2cb89f6480f96b6ed1d1669808 100644 (file)
@@ -25,23 +25,18 @@ LL |     todo!();
    |     ^^^^^^^
    |
    = note: `-D clippy::todo` implied by `-D warnings`
-   = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `todo` should not be present in production code
   --> $DIR/panicking_macros.rs:17:5
    |
 LL |     todo!("message");
    |     ^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `todo` should not be present in production code
   --> $DIR/panicking_macros.rs:18:5
    |
 LL |     todo!("{} {}", "panic with", "multiple arguments");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `unimplemented` should not be present in production code
   --> $DIR/panicking_macros.rs:24:5
@@ -50,23 +45,18 @@ LL |     unimplemented!();
    |     ^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::unimplemented` implied by `-D warnings`
-   = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `unimplemented` should not be present in production code
   --> $DIR/panicking_macros.rs:25:5
    |
 LL |     unimplemented!("message");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `unimplemented` should not be present in production code
   --> $DIR/panicking_macros.rs:26:5
    |
 LL |     unimplemented!("{} {}", "panic with", "multiple arguments");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `unreachable!` macro
   --> $DIR/panicking_macros.rs:32:5
@@ -75,23 +65,18 @@ LL |     unreachable!();
    |     ^^^^^^^^^^^^^^
    |
    = note: `-D clippy::unreachable` implied by `-D warnings`
-   = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `unreachable!` macro
   --> $DIR/panicking_macros.rs:33:5
    |
 LL |     unreachable!("message");
    |     ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `$crate::unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `unreachable!` macro
   --> $DIR/panicking_macros.rs:34:5
    |
 LL |     unreachable!("{} {}", "panic with", "multiple arguments");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `panic` should not be present in production code
   --> $DIR/panicking_macros.rs:40:5
@@ -104,24 +89,18 @@ error: `todo` should not be present in production code
    |
 LL |     todo!();
    |     ^^^^^^^
-   |
-   = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `unimplemented` should not be present in production code
   --> $DIR/panicking_macros.rs:42:5
    |
 LL |     unimplemented!();
    |     ^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `unimplemented` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: usage of the `unreachable!` macro
   --> $DIR/panicking_macros.rs:43:5
    |
 LL |     unreachable!();
    |     ^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `unreachable` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 16 previous errors
 
index 3793a5559ba55394fcc6497bf113a88e5aadd6e0..8af10cb65c40670202da1fd459fea989382ccafc 100644 (file)
@@ -5,6 +5,7 @@ LL |     fn what(&self) -> Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::return-self-not-must-use` implied by `-D warnings`
+   = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type
 
 error: missing `#[must_use]` attribute on a method returning `Self`
   --> $DIR/return_self_not_must_use.rs:17:5
@@ -13,6 +14,8 @@ LL | /     pub fn foo(&self) -> Self {
 LL | |         Self
 LL | |     }
    | |_____^
+   |
+   = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type
 
 error: missing `#[must_use]` attribute on a method returning `Self`
   --> $DIR/return_self_not_must_use.rs:20:5
@@ -21,6 +24,8 @@ LL | /     pub fn bar(self) -> Self {
 LL | |         self
 LL | |     }
    | |_____^
+   |
+   = help: consider adding the `#[must_use]` attribute to the method or directly to the `Self` type
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/single_char_lifetime_names.rs b/src/tools/clippy/tests/ui/single_char_lifetime_names.rs
new file mode 100644 (file)
index 0000000..261d8bc
--- /dev/null
@@ -0,0 +1,43 @@
+#![warn(clippy::single_char_lifetime_names)]
+
+// Lifetimes should only be linted when they're introduced
+struct DiagnosticCtx<'a, 'b>
+where
+    'a: 'b,
+{
+    _source: &'a str,
+    _unit: &'b (),
+}
+
+// Only the lifetimes on the `impl`'s generics should be linted
+impl<'a, 'b> DiagnosticCtx<'a, 'b> {
+    fn new(source: &'a str, unit: &'b ()) -> DiagnosticCtx<'a, 'b> {
+        Self {
+            _source: source,
+            _unit: unit,
+        }
+    }
+}
+
+// No lifetimes should be linted here
+impl<'src, 'unit> DiagnosticCtx<'src, 'unit> {
+    fn new_pass(source: &'src str, unit: &'unit ()) -> DiagnosticCtx<'src, 'unit> {
+        Self {
+            _source: source,
+            _unit: unit,
+        }
+    }
+}
+
+// Only 'a should be linted here
+fn split_once<'a>(base: &'a str, other: &'_ str) -> (&'a str, Option<&'a str>) {
+    base.split_once(other)
+        .map(|(left, right)| (left, Some(right)))
+        .unwrap_or((base, None))
+}
+
+fn main() {
+    let src = "loop {}";
+    let unit = ();
+    DiagnosticCtx::new(src, &unit);
+}
diff --git a/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr b/src/tools/clippy/tests/ui/single_char_lifetime_names.stderr
new file mode 100644 (file)
index 0000000..013b64f
--- /dev/null
@@ -0,0 +1,43 @@
+error: single-character lifetime names are likely uninformative
+  --> $DIR/single_char_lifetime_names.rs:4:22
+   |
+LL | struct DiagnosticCtx<'a, 'b>
+   |                      ^^
+   |
+   = note: `-D clippy::single-char-lifetime-names` implied by `-D warnings`
+   = help: use a more informative name
+
+error: single-character lifetime names are likely uninformative
+  --> $DIR/single_char_lifetime_names.rs:4:26
+   |
+LL | struct DiagnosticCtx<'a, 'b>
+   |                          ^^
+   |
+   = help: use a more informative name
+
+error: single-character lifetime names are likely uninformative
+  --> $DIR/single_char_lifetime_names.rs:13:6
+   |
+LL | impl<'a, 'b> DiagnosticCtx<'a, 'b> {
+   |      ^^
+   |
+   = help: use a more informative name
+
+error: single-character lifetime names are likely uninformative
+  --> $DIR/single_char_lifetime_names.rs:13:10
+   |
+LL | impl<'a, 'b> DiagnosticCtx<'a, 'b> {
+   |          ^^
+   |
+   = help: use a more informative name
+
+error: single-character lifetime names are likely uninformative
+  --> $DIR/single_char_lifetime_names.rs:33:15
+   |
+LL | fn split_once<'a>(base: &'a str, other: &'_ str) -> (&'a str, Option<&'a str>) {
+   |               ^^
+   |
+   = help: use a more informative name
+
+error: aborting due to 5 previous errors
+
index ef518359ec5f373614727442c65526c05a5c1899..3329efbd4ff429f1daabef797cf9793513b010c0 100644 (file)
@@ -122,3 +122,36 @@ fn main() {
 
     ; std::mem::swap(&mut c.0, &mut a);
 }
+
+fn issue_8154() {
+    struct S1 {
+        x: i32,
+        y: i32,
+    }
+    struct S2(S1);
+    struct S3<'a, 'b>(&'a mut &'b mut S1);
+
+    impl std::ops::Deref for S2 {
+        type Target = S1;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    impl std::ops::DerefMut for S2 {
+        fn deref_mut(&mut self) -> &mut Self::Target {
+            &mut self.0
+        }
+    }
+
+    // Don't lint. `s.0` is mutably borrowed by `s.x` and `s.y` via the deref impl.
+    let mut s = S2(S1 { x: 0, y: 0 });
+    let t = s.x;
+    s.x = s.y;
+    s.y = t;
+
+    // Accessing through a mutable reference is fine
+    let mut s = S1 { x: 0, y: 0 };
+    let mut s = &mut s;
+    let s = S3(&mut s);
+    std::mem::swap(&mut s.0.x, &mut s.0.y);
+}
index 8518659ccf316dbbf41ce2e9941b3874c5878092..8179ac1f2ab028a7a5d5eb26a0adcb6a24c811c7 100644 (file)
@@ -144,3 +144,38 @@ fn main() {
     c.0 = a;
     a = t;
 }
+
+fn issue_8154() {
+    struct S1 {
+        x: i32,
+        y: i32,
+    }
+    struct S2(S1);
+    struct S3<'a, 'b>(&'a mut &'b mut S1);
+
+    impl std::ops::Deref for S2 {
+        type Target = S1;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    impl std::ops::DerefMut for S2 {
+        fn deref_mut(&mut self) -> &mut Self::Target {
+            &mut self.0
+        }
+    }
+
+    // Don't lint. `s.0` is mutably borrowed by `s.x` and `s.y` via the deref impl.
+    let mut s = S2(S1 { x: 0, y: 0 });
+    let t = s.x;
+    s.x = s.y;
+    s.y = t;
+
+    // Accessing through a mutable reference is fine
+    let mut s = S1 { x: 0, y: 0 };
+    let mut s = &mut s;
+    let s = S3(&mut s);
+    let t = s.0.x;
+    s.0.x = s.0.y;
+    s.0.y = t;
+}
index 614d16ced40f1b5fd02cf899f86f5a0f38a9b6a5..2b556b475cee9da92ba55ebc79139ff980231ed0 100644 (file)
@@ -108,5 +108,15 @@ LL | |     a = c.0;
    |
    = note: or maybe you should use `std::mem::replace`?
 
-error: aborting due to 12 previous errors
+error: this looks like you are swapping `s.0.x` and `s.0.y` manually
+  --> $DIR/swap.rs:178:5
+   |
+LL | /     let t = s.0.x;
+LL | |     s.0.x = s.0.y;
+LL | |     s.0.y = t;
+   | |_____________^ help: try: `std::mem::swap(&mut s.0.x, &mut s.0.y)`
+   |
+   = note: or maybe you should use `std::mem::replace`?
+
+error: aborting due to 13 previous errors
 
index cb2b0054e352b4b951dd23f0444bc0c760caf87b..2edb202892afcaf4c1b65a7b3e91337a8779f3b8 100644 (file)
@@ -28,4 +28,49 @@ fn good_foobar<T: Default>(arg: T)
     unimplemented!();
 }
 
+trait T: Default {
+    fn f()
+    where
+        Self: Default;
+}
+
+trait U: Default {
+    fn f()
+    where
+        Self: Clone;
+}
+
+trait ZZ: Default {
+    fn g();
+    fn h();
+    fn f()
+    where
+        Self: Default + Clone;
+}
+
+trait BadTrait: Default + Clone {
+    fn f()
+    where
+        Self: Default + Clone;
+    fn g()
+    where
+        Self: Default;
+    fn h()
+    where
+        Self: Copy;
+}
+
+#[derive(Default, Clone)]
+struct Life {}
+
+impl T for Life {
+    // this should not warn
+    fn f() {}
+}
+
+impl U for Life {
+    // this should not warn
+    fn f() {}
+}
+
 fn main() {}
index 027e1c752041214d756a812f2308e335d1ff6154..e0c7a7ec618ed932223b8fb8a17f3e5ca61b0eab 100644 (file)
@@ -19,5 +19,45 @@ LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
    |
    = help: consider removing this trait bound
 
-error: aborting due to 2 previous errors
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds.rs:34:15
+   |
+LL |         Self: Default;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds.rs:48:15
+   |
+LL |         Self: Default + Clone;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds.rs:54:15
+   |
+LL |         Self: Default + Clone;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds.rs:54:25
+   |
+LL |         Self: Default + Clone;
+   |                         ^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds.rs:57:15
+   |
+LL |         Self: Default;
+   |               ^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: aborting due to 7 previous errors
 
index 6a7037d8f3826e962594836a03ee0ed9ffce9a7f..9b681a79aae7a385f922a6c04aaf2cd06b37bd94 100644 (file)
@@ -1,4 +1,4 @@
-#![allow(dead_code)]
+#![allow(dead_code, clippy::borrow_as_ptr)]
 
 extern crate core;
 
index 9e213aab68c5704a2d2079391a6e0a56a7e2bc6f..f06ffab5d9be966df12a1fd93267c5be60f96135 100644 (file)
@@ -1,4 +1,5 @@
 #![warn(clippy::transmute_ptr_to_ptr)]
+#![allow(clippy::borrow_as_ptr)]
 
 // Make sure we can modify lifetimes, which is one of the recommended uses
 // of transmute
index 4d1b8fcc199e80b0860876026fa2febf28105a26..49a8a3347e40497fede9a81d9d9ab0979ae7d9be 100644 (file)
@@ -1,5 +1,5 @@
 error: transmute from a pointer to a pointer
-  --> $DIR/transmute_ptr_to_ptr.rs:29:29
+  --> $DIR/transmute_ptr_to_ptr.rs:30:29
    |
 LL |         let _: *const f32 = std::mem::transmute(ptr);
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr as *const f32`
@@ -7,31 +7,31 @@ LL |         let _: *const f32 = std::mem::transmute(ptr);
    = note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings`
 
 error: transmute from a pointer to a pointer
-  --> $DIR/transmute_ptr_to_ptr.rs:30:27
+  --> $DIR/transmute_ptr_to_ptr.rs:31:27
    |
 LL |         let _: *mut f32 = std::mem::transmute(mut_ptr);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `mut_ptr as *mut f32`
 
 error: transmute from a reference to a reference
-  --> $DIR/transmute_ptr_to_ptr.rs:32:23
+  --> $DIR/transmute_ptr_to_ptr.rs:33:23
    |
 LL |         let _: &f32 = std::mem::transmute(&1u32);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1u32 as *const u32 as *const f32)`
 
 error: transmute from a reference to a reference
-  --> $DIR/transmute_ptr_to_ptr.rs:33:23
+  --> $DIR/transmute_ptr_to_ptr.rs:34:23
    |
 LL |         let _: &f64 = std::mem::transmute(&1f32);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&1f32 as *const f32 as *const f64)`
 
 error: transmute from a reference to a reference
-  --> $DIR/transmute_ptr_to_ptr.rs:36:27
+  --> $DIR/transmute_ptr_to_ptr.rs:37:27
    |
 LL |         let _: &mut f32 = std::mem::transmute(&mut 1u32);
    |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(&mut 1u32 as *mut u32 as *mut f32)`
 
 error: transmute from a reference to a reference
-  --> $DIR/transmute_ptr_to_ptr.rs:37:37
+  --> $DIR/transmute_ptr_to_ptr.rs:38:37
    |
 LL |         let _: &GenericParam<f32> = std::mem::transmute(&GenericParam { t: 1u32 });
    |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(&GenericParam { t: 1u32 } as *const GenericParam<u32> as *const GenericParam<f32>)`
index b6f1e83181ccb4cb2bce5d89d5ec24df478fcdc5..9ae0ed0b13f1e779a8ee08e82d3a9b4d1505a065 100644 (file)
@@ -4,8 +4,7 @@
 // would otherwise be responsible for
 #![warn(clippy::useless_transmute)]
 #![warn(clippy::transmute_ptr_to_ptr)]
-#![allow(unused_unsafe)]
-#![allow(dead_code)]
+#![allow(dead_code, unused_unsafe, clippy::borrow_as_ptr)]
 
 use std::mem::{size_of, transmute};
 
index 0205d1ece60d58c3e3fab1c55de5638b8f8011e6..985cf9a075d312899d88409f78cb93b40a81529e 100644 (file)
@@ -4,8 +4,7 @@
 // would otherwise be responsible for
 #![warn(clippy::useless_transmute)]
 #![warn(clippy::transmute_ptr_to_ptr)]
-#![allow(unused_unsafe)]
-#![allow(dead_code)]
+#![allow(dead_code, unused_unsafe, clippy::borrow_as_ptr)]
 
 use std::mem::{size_of, transmute};
 
index 1157b179317e20e9725fe4ef403cd7e9bd320c9e..e8496a325d6dc670178d789d13e73e60bb302848 100644 (file)
@@ -1,5 +1,5 @@
 error: transmute from an integer to a pointer
-  --> $DIR/transmutes_expressible_as_ptr_casts.rs:19:39
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:18:39
    |
 LL |     let _ptr_i32_transmute = unsafe { transmute::<usize, *const i32>(usize::MAX) };
    |                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `usize::MAX as *const i32`
@@ -7,7 +7,7 @@ LL |     let _ptr_i32_transmute = unsafe { transmute::<usize, *const i32>(usize:
    = note: `-D clippy::useless-transmute` implied by `-D warnings`
 
 error: transmute from a pointer to a pointer
-  --> $DIR/transmutes_expressible_as_ptr_casts.rs:23:38
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:22:38
    |
 LL |     let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr_i32) };
    |                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as *const i8`
@@ -15,13 +15,13 @@ LL |     let _ptr_i8_transmute = unsafe { transmute::<*const i32, *const i8>(ptr
    = note: `-D clippy::transmute-ptr-to-ptr` implied by `-D warnings`
 
 error: transmute from a pointer to a pointer
-  --> $DIR/transmutes_expressible_as_ptr_casts.rs:29:46
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:28:46
    |
 LL |     let _ptr_to_unsized_transmute = unsafe { transmute::<*const [i32], *const [u16]>(slice_ptr) };
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `slice_ptr as *const [u16]`
 
 error: transmute from `*const i32` to `usize` which could be expressed as a pointer cast instead
-  --> $DIR/transmutes_expressible_as_ptr_casts.rs:35:50
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:34:50
    |
 LL |     let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, usize>(ptr_i32) };
    |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `ptr_i32 as usize`
@@ -29,25 +29,25 @@ LL |     let _usize_from_int_ptr_transmute = unsafe { transmute::<*const i32, us
    = note: `-D clippy::transmutes-expressible-as-ptr-casts` implied by `-D warnings`
 
 error: transmute from a reference to a pointer
-  --> $DIR/transmutes_expressible_as_ptr_casts.rs:41:41
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:40:41
    |
 LL |     let _array_ptr_transmute = unsafe { transmute::<&[i32; 4], *const [i32; 4]>(array_ref) };
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `array_ref as *const [i32; 4]`
 
 error: transmute from `fn(usize) -> u8 {main::foo}` to `*const usize` which could be expressed as a pointer cast instead
-  --> $DIR/transmutes_expressible_as_ptr_casts.rs:49:41
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:48:41
    |
 LL |     let _usize_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, *const usize>(foo) };
    |                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as *const usize`
 
 error: transmute from `fn(usize) -> u8 {main::foo}` to `usize` which could be expressed as a pointer cast instead
-  --> $DIR/transmutes_expressible_as_ptr_casts.rs:53:49
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:52:49
    |
 LL |     let _usize_from_fn_ptr_transmute = unsafe { transmute::<fn(usize) -> u8, usize>(foo) };
    |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `foo as usize`
 
 error: transmute from a reference to a pointer
-  --> $DIR/transmutes_expressible_as_ptr_casts.rs:65:14
+  --> $DIR/transmutes_expressible_as_ptr_casts.rs:64:14
    |
 LL |     unsafe { transmute::<&[i32; 1], *const u8>(in_param) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `in_param as *const [i32; 1] as *const u8`
index 766190f209977fcec1a70bd9f5ae9a4ec467c603..fc740ee11d6ab7b815ab274dd283c76b44055da6 100644 (file)
@@ -69,4 +69,14 @@ struct Bar<S>
     }
 }
 
+// Issue #7360
+struct Foo<T, U>
+where
+    T: Clone,
+    U: Clone,
+{
+    t: T,
+    u: U,
+}
+
 fn main() {}
index 2b5a7b348b982c13d6a9f6eda9faefc1d3cdfb23..824506a4257efdf11a64220a7b0f513c5eeebc41 100644 (file)
@@ -33,8 +33,6 @@ LL | |         },
 LL | |         }
 LL | |     );
    | |_____^
-   |
-   = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `debug_assert_eq` of unit values detected. This will always succeed
   --> $DIR/unit_cmp.rs:32:5
@@ -47,8 +45,6 @@ LL | |         },
 LL | |         }
 LL | |     );
    | |_____^
-   |
-   = note: this error originates in the macro `$crate::assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `assert_ne` of unit values detected. This will always fail
   --> $DIR/unit_cmp.rs:41:5
@@ -61,8 +57,6 @@ LL | |         },
 LL | |         }
 LL | |     );
    | |_____^
-   |
-   = note: this error originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `debug_assert_ne` of unit values detected. This will always fail
   --> $DIR/unit_cmp.rs:49:5
@@ -75,8 +69,6 @@ LL | |         },
 LL | |         }
 LL | |     );
    | |_____^
-   |
-   = note: this error originates in the macro `$crate::assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 6 previous errors
 
index bda0f2c47cdd525a97a62f5e080334dc20e627c8..3332f49c80c9758c2f8cbd61fc19d48a7681dfee 100644 (file)
@@ -1,7 +1,12 @@
 // run-rustfix
 
 #![warn(clippy::unnecessary_cast)]
-#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::nonstandard_macro_braces)]
+#![allow(
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::nonstandard_macro_braces,
+    clippy::borrow_as_ptr
+)]
 
 fn main() {
     // casting integer literal to float is unnecessary
index f7a4f2a5988fd42c38fc5dca1c255a7a556e07ba..ec01e93877927af3f51217fe4f194bfb6d8d9645 100644 (file)
@@ -1,7 +1,12 @@
 // run-rustfix
 
 #![warn(clippy::unnecessary_cast)]
-#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::nonstandard_macro_braces)]
+#![allow(
+    clippy::no_effect,
+    clippy::unnecessary_operation,
+    clippy::nonstandard_macro_braces,
+    clippy::borrow_as_ptr
+)]
 
 fn main() {
     // casting integer literal to float is unnecessary
index 3695a8f819c4a9da2ab2c364d29cf4f34a2a3c2b..a281143281b54fa591f29d71559da82fd7fca74f 100644 (file)
@@ -1,5 +1,5 @@
 error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:8:5
+  --> $DIR/unnecessary_cast_fixable.rs:13:5
    |
 LL |     100 as f32;
    |     ^^^^^^^^^^ help: try: `100_f32`
@@ -7,97 +7,97 @@ LL |     100 as f32;
    = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:9:5
+  --> $DIR/unnecessary_cast_fixable.rs:14:5
    |
 LL |     100 as f64;
    |     ^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:10:5
+  --> $DIR/unnecessary_cast_fixable.rs:15:5
    |
 LL |     100_i32 as f64;
    |     ^^^^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:11:13
+  --> $DIR/unnecessary_cast_fixable.rs:16:13
    |
 LL |     let _ = -100 as f32;
    |             ^^^^^^^^^^^ help: try: `-100_f32`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:12:13
+  --> $DIR/unnecessary_cast_fixable.rs:17:13
    |
 LL |     let _ = -100 as f64;
    |             ^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting integer literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:13:13
+  --> $DIR/unnecessary_cast_fixable.rs:18:13
    |
 LL |     let _ = -100_i32 as f64;
    |             ^^^^^^^^^^^^^^^ help: try: `-100_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:14:5
+  --> $DIR/unnecessary_cast_fixable.rs:19:5
    |
 LL |     100. as f32;
    |     ^^^^^^^^^^^ help: try: `100_f32`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:15:5
+  --> $DIR/unnecessary_cast_fixable.rs:20:5
    |
 LL |     100. as f64;
    |     ^^^^^^^^^^^ help: try: `100_f64`
 
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:27:5
+  --> $DIR/unnecessary_cast_fixable.rs:32:5
    |
 LL |     1 as u32;
    |     ^^^^^^^^ help: try: `1_u32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:28:5
+  --> $DIR/unnecessary_cast_fixable.rs:33:5
    |
 LL |     0x10 as i32;
    |     ^^^^^^^^^^^ help: try: `0x10_i32`
 
 error: casting integer literal to `usize` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:29:5
+  --> $DIR/unnecessary_cast_fixable.rs:34:5
    |
 LL |     0b10 as usize;
    |     ^^^^^^^^^^^^^ help: try: `0b10_usize`
 
 error: casting integer literal to `u16` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:30:5
+  --> $DIR/unnecessary_cast_fixable.rs:35:5
    |
 LL |     0o73 as u16;
    |     ^^^^^^^^^^^ help: try: `0o73_u16`
 
 error: casting integer literal to `u32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:31:5
+  --> $DIR/unnecessary_cast_fixable.rs:36:5
    |
 LL |     1_000_000_000 as u32;
    |     ^^^^^^^^^^^^^^^^^^^^ help: try: `1_000_000_000_u32`
 
 error: casting float literal to `f64` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:33:5
+  --> $DIR/unnecessary_cast_fixable.rs:38:5
    |
 LL |     1.0 as f64;
    |     ^^^^^^^^^^ help: try: `1.0_f64`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:34:5
+  --> $DIR/unnecessary_cast_fixable.rs:39:5
    |
 LL |     0.5 as f32;
    |     ^^^^^^^^^^ help: try: `0.5_f32`
 
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:38:13
+  --> $DIR/unnecessary_cast_fixable.rs:43:13
    |
 LL |     let _ = -1 as i32;
    |             ^^^^^^^^^ help: try: `-1_i32`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast_fixable.rs:39:13
+  --> $DIR/unnecessary_cast_fixable.rs:44:13
    |
 LL |     let _ = -1.0 as f32;
    |             ^^^^^^^^^^^ help: try: `-1.0_f32`
index 8b141e25942d7f74a6eb90685def758340ce46ee..4b059558173fb783044655ef7358f968cd633d88 100644 (file)
@@ -1,6 +1,8 @@
 #![allow(dead_code)]
 #![warn(clippy::unused_io_amount)]
 
+extern crate futures;
+use futures::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
 use std::io::{self, Read};
 
 fn question_mark<T: io::Read + io::Write>(s: &mut T) -> io::Result<()> {
@@ -61,4 +63,55 @@ fn combine_or(file: &str) -> Result<(), Error> {
     Ok(())
 }
 
+async fn bad_async_write<W: AsyncWrite + Unpin>(w: &mut W) {
+    w.write(b"hello world").await.unwrap();
+}
+
+async fn bad_async_read<R: AsyncRead + Unpin>(r: &mut R) {
+    let mut buf = [0u8; 0];
+    r.read(&mut buf[..]).await.unwrap();
+}
+
+async fn io_not_ignored_async_write<W: AsyncWrite + Unpin>(mut w: W) {
+    // Here we're forgetting to await the future, so we should get a
+    // warning about _that_ (or we would, if it were enabled), but we
+    // won't get one about ignoring the return value.
+    w.write(b"hello world");
+}
+
+fn bad_async_write_closure<W: AsyncWrite + Unpin + 'static>(w: W) -> impl futures::Future<Output = io::Result<()>> {
+    let mut w = w;
+    async move {
+        w.write(b"hello world").await?;
+        Ok(())
+    }
+}
+
+async fn async_read_nested_or<R: AsyncRead + Unpin>(r: &mut R, do_it: bool) -> Result<[u8; 1], Error> {
+    let mut buf = [0u8; 1];
+    if do_it {
+        r.read(&mut buf[..]).await.or(Err(Error::Kind))?;
+    }
+    Ok(buf)
+}
+
+use tokio::io::{AsyncRead as TokioAsyncRead, AsyncReadExt as _, AsyncWrite as TokioAsyncWrite, AsyncWriteExt as _};
+
+async fn bad_async_write_tokio<W: TokioAsyncWrite + Unpin>(w: &mut W) {
+    w.write(b"hello world").await.unwrap();
+}
+
+async fn bad_async_read_tokio<R: TokioAsyncRead + Unpin>(r: &mut R) {
+    let mut buf = [0u8; 0];
+    r.read(&mut buf[..]).await.unwrap();
+}
+
+async fn undetected_bad_async_write<W: AsyncWrite + Unpin>(w: &mut W) {
+    // It would be good to detect this case some day, but the current lint
+    // doesn't handle it. (The documentation says that this lint "detects
+    // only common patterns".)
+    let future = w.write(b"Hello world");
+    future.await.unwrap();
+}
+
 fn main() {}
index d8dfc0e5a798c53edd720d8583f0a2d0745d2206..e5bdd993aa1ad260736e52313562233762107b36 100644 (file)
@@ -1,61 +1,74 @@
-error: written amount is not handled. Use `Write::write_all` instead
-  --> $DIR/unused_io_amount.rs:7:5
+error: written amount is not handled
+  --> $DIR/unused_io_amount.rs:9:5
    |
 LL |     s.write(b"test")?;
    |     ^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::unused-io-amount` implied by `-D warnings`
+   = help: use `Write::write_all` instead, or handle partial writes
 
-error: read amount is not handled. Use `Read::read_exact` instead
-  --> $DIR/unused_io_amount.rs:9:5
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:11:5
    |
 LL |     s.read(&mut buf)?;
    |     ^^^^^^^^^^^^^^^^^
+   |
+   = help: use `Read::read_exact` instead, or handle partial reads
 
-error: written amount is not handled. Use `Write::write_all` instead
-  --> $DIR/unused_io_amount.rs:14:5
+error: written amount is not handled
+  --> $DIR/unused_io_amount.rs:16:5
    |
 LL |     s.write(b"test").unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `Write::write_all` instead, or handle partial writes
 
-error: read amount is not handled. Use `Read::read_exact` instead
-  --> $DIR/unused_io_amount.rs:16:5
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:18:5
    |
 LL |     s.read(&mut buf).unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `Read::read_exact` instead, or handle partial reads
 
 error: read amount is not handled
-  --> $DIR/unused_io_amount.rs:20:5
+  --> $DIR/unused_io_amount.rs:22:5
    |
 LL |     s.read_vectored(&mut [io::IoSliceMut::new(&mut [])])?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: written amount is not handled
-  --> $DIR/unused_io_amount.rs:21:5
+  --> $DIR/unused_io_amount.rs:23:5
    |
 LL |     s.write_vectored(&[io::IoSlice::new(&[])])?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: read amount is not handled. Use `Read::read_exact` instead
-  --> $DIR/unused_io_amount.rs:28:5
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:30:5
    |
 LL |     reader.read(&mut result).ok()?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `Read::read_exact` instead, or handle partial reads
 
-error: read amount is not handled. Use `Read::read_exact` instead
-  --> $DIR/unused_io_amount.rs:37:5
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:39:5
    |
 LL |     reader.read(&mut result).or_else(|err| Err(err))?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `Read::read_exact` instead, or handle partial reads
 
-error: read amount is not handled. Use `Read::read_exact` instead
-  --> $DIR/unused_io_amount.rs:49:5
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:51:5
    |
 LL |     reader.read(&mut result).or(Err(Error::Kind))?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `Read::read_exact` instead, or handle partial reads
 
-error: read amount is not handled. Use `Read::read_exact` instead
-  --> $DIR/unused_io_amount.rs:56:5
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:58:5
    |
 LL | /     reader
 LL | |         .read(&mut result)
@@ -63,6 +76,56 @@ LL | |         .or(Err(Error::Kind))
 LL | |         .or(Err(Error::Kind))
 LL | |         .expect("error");
    | |________________________^
+   |
+   = help: use `Read::read_exact` instead, or handle partial reads
+
+error: written amount is not handled
+  --> $DIR/unused_io_amount.rs:67:5
+   |
+LL |     w.write(b"hello world").await.unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `AsyncWriteExt::write_all` instead, or handle partial writes
+
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:72:5
+   |
+LL |     r.read(&mut buf[..]).await.unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `AsyncReadExt::read_exact` instead, or handle partial reads
+
+error: written amount is not handled
+  --> $DIR/unused_io_amount.rs:85:9
+   |
+LL |         w.write(b"hello world").await?;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `AsyncWriteExt::write_all` instead, or handle partial writes
+
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:93:9
+   |
+LL |         r.read(&mut buf[..]).await.or(Err(Error::Kind))?;
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `AsyncReadExt::read_exact` instead, or handle partial reads
+
+error: written amount is not handled
+  --> $DIR/unused_io_amount.rs:101:5
+   |
+LL |     w.write(b"hello world").await.unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `AsyncWriteExt::write_all` instead, or handle partial writes
+
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:106:5
+   |
+LL |     r.read(&mut buf[..]).await.unwrap();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `AsyncReadExt::read_exact` instead, or handle partial reads
 
-error: aborting due to 10 previous errors
+error: aborting due to 16 previous errors
 
index c91d96ee18a31972c1856196c149856634d8dbba..a9a4a0f5a6b5c8da75d41c3d0fe318d1cac553d0 100644 (file)
@@ -4,6 +4,8 @@
 use std::sync::Arc;
 
 #[warn(clippy::vtable_address_comparisons)]
+#[allow(clippy::borrow_as_ptr)]
+
 fn main() {
     let a: *const dyn Debug = &1 as &dyn Debug;
     let b: *const dyn Debug = &1 as &dyn Debug;
index 76bd57217d784323c9a86f2b2881f033daad7e13..2f1be61e5df72acd660326acd0d4db83deecf58d 100644 (file)
@@ -1,5 +1,5 @@
 error: comparing trait object pointers compares a non-unique vtable address
-  --> $DIR/vtable_address_comparisons.rs:12:13
+  --> $DIR/vtable_address_comparisons.rs:14:13
    |
 LL |     let _ = a == b;
    |             ^^^^^^
@@ -8,7 +8,7 @@ LL |     let _ = a == b;
    = help: consider extracting and comparing data pointers only
 
 error: comparing trait object pointers compares a non-unique vtable address
-  --> $DIR/vtable_address_comparisons.rs:13:13
+  --> $DIR/vtable_address_comparisons.rs:15:13
    |
 LL |     let _ = a != b;
    |             ^^^^^^
@@ -16,7 +16,7 @@ LL |     let _ = a != b;
    = help: consider extracting and comparing data pointers only
 
 error: comparing trait object pointers compares a non-unique vtable address
-  --> $DIR/vtable_address_comparisons.rs:14:13
+  --> $DIR/vtable_address_comparisons.rs:16:13
    |
 LL |     let _ = a < b;
    |             ^^^^^
@@ -24,7 +24,7 @@ LL |     let _ = a < b;
    = help: consider extracting and comparing data pointers only
 
 error: comparing trait object pointers compares a non-unique vtable address
-  --> $DIR/vtable_address_comparisons.rs:15:13
+  --> $DIR/vtable_address_comparisons.rs:17:13
    |
 LL |     let _ = a <= b;
    |             ^^^^^^
@@ -32,7 +32,7 @@ LL |     let _ = a <= b;
    = help: consider extracting and comparing data pointers only
 
 error: comparing trait object pointers compares a non-unique vtable address
-  --> $DIR/vtable_address_comparisons.rs:16:13
+  --> $DIR/vtable_address_comparisons.rs:18:13
    |
 LL |     let _ = a > b;
    |             ^^^^^
@@ -40,7 +40,7 @@ LL |     let _ = a > b;
    = help: consider extracting and comparing data pointers only
 
 error: comparing trait object pointers compares a non-unique vtable address
-  --> $DIR/vtable_address_comparisons.rs:17:13
+  --> $DIR/vtable_address_comparisons.rs:19:13
    |
 LL |     let _ = a >= b;
    |             ^^^^^^
@@ -48,7 +48,7 @@ LL |     let _ = a >= b;
    = help: consider extracting and comparing data pointers only
 
 error: comparing trait object pointers compares a non-unique vtable address
-  --> $DIR/vtable_address_comparisons.rs:18:5
+  --> $DIR/vtable_address_comparisons.rs:20:5
    |
 LL |     ptr::eq(a, b);
    |     ^^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |     ptr::eq(a, b);
    = help: consider extracting and comparing data pointers only
 
 error: comparing trait object pointers compares a non-unique vtable address
-  --> $DIR/vtable_address_comparisons.rs:22:5
+  --> $DIR/vtable_address_comparisons.rs:24:5
    |
 LL |     ptr::eq(a, b);
    |     ^^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     ptr::eq(a, b);
    = help: consider extracting and comparing data pointers only
 
 error: comparing trait object pointers compares a non-unique vtable address
-  --> $DIR/vtable_address_comparisons.rs:25:5
+  --> $DIR/vtable_address_comparisons.rs:27:5
    |
 LL |     Rc::ptr_eq(&a, &a);
    |     ^^^^^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL |     Rc::ptr_eq(&a, &a);
    = help: consider extracting and comparing data pointers only
 
 error: comparing trait object pointers compares a non-unique vtable address
-  --> $DIR/vtable_address_comparisons.rs:28:5
+  --> $DIR/vtable_address_comparisons.rs:30:5
    |
 LL |     Arc::ptr_eq(&a, &a);
    |     ^^^^^^^^^^^^^^^^^^^
index 1e74ad2de655aa53c624c6c98bcf1be915f269dc..cb8892a3f009bdb99bbbc5c2ba6d4b3e4e02558e 100644 (file)
@@ -372,6 +372,36 @@ fn exact_match_with_single_field() {
     }
 }
 
+fn custom_deref() {
+    struct S1<T> {
+        x: T,
+    }
+    struct S2<T>(S1<T>);
+    impl<T> core::ops::Deref for S2<T> {
+        type Target = S1<T>;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    impl<T> core::ops::DerefMut for S2<T> {
+        fn deref_mut(&mut self) -> &mut Self::Target {
+            &mut self.0
+        }
+    }
+
+    let mut s = S2(S1 { x: 0..10 });
+    for x in s.x.by_ref() {
+        println!("{}", x);
+    }
+}
+
+fn issue_8113() {
+    let mut x = [0..10];
+    for x in x[0].by_ref() {
+        println!("{}", x);
+    }
+}
+
 fn main() {
     let mut it = 0..20;
     for _ in it {
index 69cb636cee8260bb31ce151a97f2ea9a11118955..d91571844959e1439fbc743d300fd037812c68f9 100644 (file)
@@ -372,6 +372,36 @@ fn exact_match_with_single_field() {
     }
 }
 
+fn custom_deref() {
+    struct S1<T> {
+        x: T,
+    }
+    struct S2<T>(S1<T>);
+    impl<T> core::ops::Deref for S2<T> {
+        type Target = S1<T>;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    impl<T> core::ops::DerefMut for S2<T> {
+        fn deref_mut(&mut self) -> &mut Self::Target {
+            &mut self.0
+        }
+    }
+
+    let mut s = S2(S1 { x: 0..10 });
+    while let Some(x) = s.x.next() {
+        println!("{}", x);
+    }
+}
+
+fn issue_8113() {
+    let mut x = [0..10];
+    while let Some(x) = x[0].next() {
+        println!("{}", x);
+    }
+}
+
 fn main() {
     let mut it = 0..20;
     while let Some(..) = it.next() {
index 1a11ba26eef0ffdc7c5c4d9bf75432ca9ad7aff4..fb2b0f2467c0d115924aa232f40e8d6b6706d3ef 100644 (file)
@@ -123,10 +123,22 @@ LL |     while let Some(x) = it.0.next() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in it.0.by_ref()`
 
 error: this loop could be written as a `for` loop
-  --> $DIR/while_let_on_iterator.rs:377:5
+  --> $DIR/while_let_on_iterator.rs:393:5
+   |
+LL |     while let Some(x) = s.x.next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in s.x.by_ref()`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:400:5
+   |
+LL |     while let Some(x) = x[0].next() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x in x[0].by_ref()`
+
+error: this loop could be written as a `for` loop
+  --> $DIR/while_let_on_iterator.rs:407:5
    |
 LL |     while let Some(..) = it.next() {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it`
 
-error: aborting due to 21 previous errors
+error: aborting due to 23 previous errors
 
index 1b9da8a55e53fe8796ff7b92ee9b393db29b25bd..f8fee4b3ab2d8fb420c66ada277a88a046a4bc2d 100644 (file)
@@ -188,3 +188,24 @@ fn to_u64_v2(&self) -> u64 {
         }
     }
 }
+
+pub mod issue8142 {
+    struct S;
+
+    impl S {
+        // Should lint: is_ methods should only take &self, or no self at all.
+        fn is_still_buggy(&mut self) -> bool {
+            false
+        }
+
+        // Should not lint: "no self at all" is allowed.
+        fn is_forty_two(x: u32) -> bool {
+            x == 42
+        }
+
+        // Should not lint: &self is allowed.
+        fn is_test_code(&self) -> bool {
+            true
+        }
+    }
+}
index 590ee6d9c529d6493b8e29b755c2d3e07f982b2b..5493a99572e068746d2900921ca208595e99f9ad 100644 (file)
@@ -191,5 +191,13 @@ LL |         fn to_u64(self) -> u64 {
    |
    = help: consider choosing a less ambiguous name
 
-error: aborting due to 24 previous errors
+error: methods called `is_*` usually take `self` by reference or no `self`
+  --> $DIR/wrong_self_convention.rs:197:27
+   |
+LL |         fn is_still_buggy(&mut self) -> bool {
+   |                           ^^^^^^^^^
+   |
+   = help: consider choosing a less ambiguous name
+
+error: aborting due to 25 previous errors
 
index 6c190a4c86c48a3175f5b94a0c22312757de088d..fd9ac1fa7663b897333d1453e604e44a3143d1e7 100644 (file)
@@ -1,3 +1,4 @@
+#[allow(clippy::borrow_as_ptr)]
 fn main() {
     unsafe {
         let m = &mut () as *mut ();
index b12c8e9a73c6dab3692dc2bc97cbce8ea81b3bc2..481a446571ab0880bece640007231774cf253cf6 100644 (file)
@@ -1,5 +1,5 @@
 error: offset calculation on zero-sized value
-  --> $DIR/zero_offset.rs:4:9
+  --> $DIR/zero_offset.rs:5:9
    |
 LL |         m.offset(0);
    |         ^^^^^^^^^^^
@@ -7,43 +7,43 @@ LL |         m.offset(0);
    = note: `#[deny(clippy::zst_offset)]` on by default
 
 error: offset calculation on zero-sized value
-  --> $DIR/zero_offset.rs:5:9
+  --> $DIR/zero_offset.rs:6:9
    |
 LL |         m.wrapping_add(0);
    |         ^^^^^^^^^^^^^^^^^
 
 error: offset calculation on zero-sized value
-  --> $DIR/zero_offset.rs:6:9
+  --> $DIR/zero_offset.rs:7:9
    |
 LL |         m.sub(0);
    |         ^^^^^^^^
 
 error: offset calculation on zero-sized value
-  --> $DIR/zero_offset.rs:7:9
+  --> $DIR/zero_offset.rs:8:9
    |
 LL |         m.wrapping_sub(0);
    |         ^^^^^^^^^^^^^^^^^
 
 error: offset calculation on zero-sized value
-  --> $DIR/zero_offset.rs:10:9
+  --> $DIR/zero_offset.rs:11:9
    |
 LL |         c.offset(0);
    |         ^^^^^^^^^^^
 
 error: offset calculation on zero-sized value
-  --> $DIR/zero_offset.rs:11:9
+  --> $DIR/zero_offset.rs:12:9
    |
 LL |         c.wrapping_add(0);
    |         ^^^^^^^^^^^^^^^^^
 
 error: offset calculation on zero-sized value
-  --> $DIR/zero_offset.rs:12:9
+  --> $DIR/zero_offset.rs:13:9
    |
 LL |         c.sub(0);
    |         ^^^^^^^^
 
 error: offset calculation on zero-sized value
-  --> $DIR/zero_offset.rs:13:9
+  --> $DIR/zero_offset.rs:14:9
    |
 LL |         c.wrapping_sub(0);
    |         ^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/workspace.rs b/src/tools/clippy/tests/workspace.rs
new file mode 100644 (file)
index 0000000..677b4a4
--- /dev/null
@@ -0,0 +1,107 @@
+#![feature(once_cell)]
+
+use std::path::PathBuf;
+use std::process::Command;
+use test_utils::{CARGO_CLIPPY_PATH, IS_RUSTC_TEST_SUITE};
+
+mod test_utils;
+
+#[test]
+fn test_no_deps_ignores_path_deps_in_workspaces() {
+    if IS_RUSTC_TEST_SUITE {
+        return;
+    }
+    let root = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
+    let target_dir = root.join("target").join("workspace_test");
+    let cwd = root.join("tests/workspace_test");
+
+    // Make sure we start with a clean state
+    Command::new("cargo")
+        .current_dir(&cwd)
+        .env("CARGO_TARGET_DIR", &target_dir)
+        .arg("clean")
+        .args(&["-p", "subcrate"])
+        .args(&["-p", "path_dep"])
+        .output()
+        .unwrap();
+
+    // `path_dep` is a path dependency of `subcrate` that would trigger a denied lint.
+    // Make sure that with the `--no-deps` argument Clippy does not run on `path_dep`.
+    let output = Command::new(&*CARGO_CLIPPY_PATH)
+        .current_dir(&cwd)
+        .env("CARGO_INCREMENTAL", "0")
+        .env("CARGO_TARGET_DIR", &target_dir)
+        .arg("clippy")
+        .args(&["-p", "subcrate"])
+        .arg("--no-deps")
+        .arg("--")
+        .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
+        .args(&["--cfg", r#"feature="primary_package_test""#])
+        .output()
+        .unwrap();
+    println!("status: {}", output.status);
+    println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
+    println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
+
+    assert!(output.status.success());
+
+    let lint_path_dep = || {
+        // Test that without the `--no-deps` argument, `path_dep` is linted.
+        let output = Command::new(&*CARGO_CLIPPY_PATH)
+            .current_dir(&cwd)
+            .env("CARGO_INCREMENTAL", "0")
+            .env("CARGO_TARGET_DIR", &target_dir)
+            .arg("clippy")
+            .args(&["-p", "subcrate"])
+            .arg("--")
+            .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
+            .args(&["--cfg", r#"feature="primary_package_test""#])
+            .output()
+            .unwrap();
+        println!("status: {}", output.status);
+        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
+        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
+
+        assert!(!output.status.success());
+        assert!(
+            String::from_utf8(output.stderr)
+                .unwrap()
+                .contains("error: empty `loop {}` wastes CPU cycles")
+        );
+    };
+
+    // Make sure Cargo is aware of the removal of `--no-deps`.
+    lint_path_dep();
+
+    let successful_build = || {
+        let output = Command::new(&*CARGO_CLIPPY_PATH)
+            .current_dir(&cwd)
+            .env("CARGO_INCREMENTAL", "0")
+            .env("CARGO_TARGET_DIR", &target_dir)
+            .arg("clippy")
+            .args(&["-p", "subcrate"])
+            .arg("--")
+            .arg("-Cdebuginfo=0") // disable debuginfo to generate less data in the target dir
+            .output()
+            .unwrap();
+        println!("status: {}", output.status);
+        println!("stdout: {}", String::from_utf8_lossy(&output.stdout));
+        println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
+
+        assert!(output.status.success());
+
+        output
+    };
+
+    // Trigger a sucessful build, so Cargo would like to cache the build result.
+    successful_build();
+
+    // Make sure there's no spurious rebuild when nothing changes.
+    let stderr = String::from_utf8(successful_build().stderr).unwrap();
+    assert!(!stderr.contains("Compiling"));
+    assert!(!stderr.contains("Checking"));
+    assert!(stderr.contains("Finished"));
+
+    // Make sure Cargo is aware of the new `--cfg` flag.
+    lint_path_dep();
+}
diff --git a/src/tools/clippy/tests/workspace_test/Cargo.toml b/src/tools/clippy/tests/workspace_test/Cargo.toml
new file mode 100644 (file)
index 0000000..bf5b4ca
--- /dev/null
@@ -0,0 +1,7 @@
+[package]
+name = "workspace_test"
+version = "0.1.0"
+edition = "2018"
+
+[workspace]
+members = ["subcrate"]
diff --git a/src/tools/clippy/tests/workspace_test/build.rs b/src/tools/clippy/tests/workspace_test/build.rs
new file mode 100644 (file)
index 0000000..3507168
--- /dev/null
@@ -0,0 +1,7 @@
+#![deny(clippy::print_stdout)]
+
+fn main() {
+    // Test for #6041
+    println!("Hello");
+    print!("Hello");
+}
diff --git a/src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml b/src/tools/clippy/tests/workspace_test/path_dep/Cargo.toml
new file mode 100644 (file)
index 0000000..85a91cd
--- /dev/null
@@ -0,0 +1,3 @@
+[package]
+name = "path_dep"
+version = "0.1.0"
diff --git a/src/tools/clippy/tests/workspace_test/path_dep/src/lib.rs b/src/tools/clippy/tests/workspace_test/path_dep/src/lib.rs
new file mode 100644 (file)
index 0000000..35ce524
--- /dev/null
@@ -0,0 +1,6 @@
+#![deny(clippy::empty_loop)]
+
+#[cfg(feature = "primary_package_test")]
+pub fn lint_me() {
+    loop {}
+}
diff --git a/src/tools/clippy/tests/workspace_test/src/main.rs b/src/tools/clippy/tests/workspace_test/src/main.rs
new file mode 100644 (file)
index 0000000..b322eca
--- /dev/null
@@ -0,0 +1,3 @@
+#![deny(rust_2018_idioms)]
+
+fn main() {}
diff --git a/src/tools/clippy/tests/workspace_test/subcrate/Cargo.toml b/src/tools/clippy/tests/workspace_test/subcrate/Cargo.toml
new file mode 100644 (file)
index 0000000..45362c1
--- /dev/null
@@ -0,0 +1,6 @@
+[package]
+name = "subcrate"
+version = "0.1.0"
+
+[dependencies]
+path_dep = { path = "../path_dep" }
diff --git a/src/tools/clippy/tests/workspace_test/subcrate/src/lib.rs b/src/tools/clippy/tests/workspace_test/subcrate/src/lib.rs
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
index d307e6c1970d1edb63d6a08d332e0acdb72c5cc5..deb9bfd24648d50142ab29b810175837c4718885 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d307e6c1970d1edb63d6a08d332e0acdb72c5cc5
+Subproject commit deb9bfd24648d50142ab29b810175837c4718885
index 68319187d63707fa36d7c215ed0e444e87d9652a..0f8c96c92689af8378dbe9f466c6bf15a3a27458 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 68319187d63707fa36d7c215ed0e444e87d9652a
+Subproject commit 0f8c96c92689af8378dbe9f466c6bf15a3a27458
index a89fbe863e65283ce47ca0e36f87a0267058eb52..4476f2a449b1f815d56c56fb0ef1ba1c68d5d04c 100644 (file)
@@ -929,9 +929,9 @@ fn add_one(x: i32) -> i32 {
 ## `format_generated_files`
 
 Format generated files. A file is considered generated
-if any of the first five lines contains `@generated` marker.
+if any of the first five lines contain a `@generated` comment marker.
 
-- **Default value**: `false`
+- **Default value**: `true`
 - **Possible values**: `true`, `false`
 - **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080))
 
index 5dbe532ac388fee287d48ee200e7d2bed65e8206..cd90e0904b6cd540d82c95548e614a6dc02847b5 100644 (file)
     inline_attribute_width: usize, 0, false,
         "Write an item and its attribute on the same line \
         if their combined width is below a threshold";
-    format_generated_files: bool, false, false, "Format generated files";
+    format_generated_files: bool, true, false, "Format generated files";
 
     // Options that can change the source code beyond whitespace/blocks (somewhat linty things)
     merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
@@ -606,7 +606,7 @@ fn test_dump_default_config() {
 edition = "2015"
 version = "One"
 inline_attribute_width = 0
-format_generated_files = false
+format_generated_files = true
 merge_derives = true
 use_try_shorthand = false
 use_field_init_shorthand = false
index 67cf1232f66abe93f3905070f965ad72a70066c5..ca93955a549dd4069f0f68ba6e1a5d41ebb28648 100644 (file)
@@ -80,7 +80,9 @@ fn should_skip_module<T: FormatHandler>(
         return true;
     }
 
-    if !config.format_generated_files() {
+    // FIXME(calebcartwright) - we need to determine how we'll handle the
+    // `format_generated_files` option with stdin based input.
+    if !input_is_stdin && !config.format_generated_files() {
         let source_file = context.parse_session.span_to_file_contents(module.span);
         let src = source_file.src.as_ref().expect("SourceFile without src");
 
index ad23b16e02ec19d11c1e7cacd3ac27e81bc5fd71..fae8080c02e413c09f12a7adf91076022448a5c9 100644 (file)
@@ -3,6 +3,7 @@
 #![warn(unreachable_pub)]
 #![recursion_limit = "256"]
 #![allow(clippy::match_like_matches_macro)]
+#![allow(unreachable_pub)]
 
 #[macro_use]
 extern crate derive_new;
index cceb28dfea6d7e82e06d3051983cc0a377fca9a2..c50d18644b0910e3d3e968f6db904e3626da27fa 100644 (file)
@@ -487,6 +487,24 @@ fn stdin_disable_all_formatting_test() {
     assert_eq!(input, String::from_utf8(output.stdout).unwrap());
 }
 
+#[test]
+fn stdin_generated_files_issue_5172() {
+    init_log();
+    let input = Input::Text("//@generated\nfn   main() {}".to_owned());
+    let mut config = Config::default();
+    config.set().emit_mode(EmitMode::Stdout);
+    config.set().format_generated_files(false);
+    config.set().newline_style(NewlineStyle::Unix);
+    let mut buf: Vec<u8> = vec![];
+    {
+        let mut session = Session::new(config, Some(&mut buf));
+        session.format(input).unwrap();
+        assert!(session.has_no_errors());
+    }
+    // N.B. this should be changed once `format_generated_files` is supported with stdin
+    assert_eq!(buf, "stdin:\n\n//@generated\nfn main() {}\n".as_bytes());
+}
+
 #[test]
 fn format_lines_errors_are_reported() {
     init_log();
index edc6f52db3bbab52772d8d105028e01287352b0a..3bdd6a29537944a057f651bf91db5536a6aca955 100644 (file)
 /// tooling. It is _crucial_ that no exception crates be dependencies
 /// of the Rust runtime (std/test).
 const EXCEPTIONS: &[(&str, &str)] = &[
-    ("mdbook", "MPL-2.0"),                                  // mdbook
-    ("openssl", "Apache-2.0"),                              // cargo, mdbook
-    ("colored", "MPL-2.0"),                                 // rustfmt
-    ("ordslice", "Apache-2.0"),                             // rls
-    ("ryu", "Apache-2.0 OR BSL-1.0"),                       // rls/cargo/... (because of serde)
-    ("bytesize", "Apache-2.0"),                             // cargo
-    ("im-rc", "MPL-2.0+"),                                  // cargo
-    ("sized-chunks", "MPL-2.0+"),                           // cargo via im-rc
-    ("bitmaps", "MPL-2.0+"),                                // cargo via im-rc
-    ("crossbeam-queue", "MIT/Apache-2.0 AND BSD-2-Clause"), // rls via rayon
-    ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot
-    ("snap", "BSD-3-Clause"),    // rustc
+    ("mdbook", "MPL-2.0"),            // mdbook
+    ("openssl", "Apache-2.0"),        // cargo, mdbook
+    ("colored", "MPL-2.0"),           // rustfmt
+    ("ordslice", "Apache-2.0"),       // rls
+    ("ryu", "Apache-2.0 OR BSL-1.0"), // rls/cargo/... (because of serde)
+    ("bytesize", "Apache-2.0"),       // cargo
+    ("im-rc", "MPL-2.0+"),            // cargo
+    ("sized-chunks", "MPL-2.0+"),     // cargo via im-rc
+    ("bitmaps", "MPL-2.0+"),          // cargo via im-rc
+    ("instant", "BSD-3-Clause"),      // rustc_driver/tracing-subscriber/parking_lot
+    ("snap", "BSD-3-Clause"),         // rustc
     // FIXME: this dependency violates the documentation comment above:
     ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target
 ];
@@ -73,6 +72,7 @@
 const PERMITTED_DEPENDENCIES: &[&str] = &[
     "addr2line",
     "adler",
+    "ahash",
     "aho-corasick",
     "annotate-snippets",
     "ansi_term",
@@ -97,7 +97,6 @@
     "crc32fast",
     "crossbeam-deque",
     "crossbeam-epoch",
-    "crossbeam-queue",
     "crossbeam-utils",
     "cstr",
     "datafrog",
     "env_logger",
     "expect-test",
     "fake-simd",
+    "fallible-iterator", // dependency of `thorin`
     "filetime",
     "fixedbitset",
     "flate2",
     "lock_api",
     "log",
     "matchers",
-    "maybe-uninit",
     "md-5",
     "measureme",
     "memchr",
     "tempfile",
     "termcolor",
     "termize",
+    "thorin-dwp",
     "thread_local",
     "time",
     "tinyvec",
index f610dbd806aea658bdd6d429ce612702f90c2b2c..b0abee459869cc5d5b4981c2fe44f660f72a231f 100644 (file)
@@ -2,11 +2,6 @@
 
 use std::path::Path;
 
-fn is_edition_2018(mut line: &str) -> bool {
-    line = line.trim();
-    line == "edition = \"2018\""
-}
-
 fn is_edition_2021(mut line: &str) -> bool {
     line = line.trim();
     line == "edition = \"2021\""
@@ -23,27 +18,13 @@ pub fn check(path: &Path, bad: &mut bool) {
                 return;
             }
 
-            // Not all library crates are ready to migrate to 2021.
-            if file.components().any(|c| c.as_os_str() == "library")
-                && file.components().all(|c| c.as_os_str() != "std")
-            {
-                let has = contents.lines().any(is_edition_2018);
-                if !has {
-                    tidy_error!(
-                        bad,
-                        "{} doesn't have `edition = \"2018\"` on a separate line",
-                        file.display()
-                    );
-                }
-            } else {
-                let is_2021 = contents.lines().any(is_edition_2021);
-                if !is_2021 {
-                    tidy_error!(
-                        bad,
-                        "{} doesn't have `edition = \"2021\"` on a separate line",
-                        file.display()
-                    );
-                }
+            let is_2021 = contents.lines().any(is_edition_2021);
+            if !is_2021 {
+                tidy_error!(
+                    bad,
+                    "{} doesn't have `edition = \"2021\"` on a separate line",
+                    file.display()
+                );
             }
         },
     );
index bb120e876c620345b6e6704bf5eb2578a2b044ed..4d5fde5bd1654ede0a88357828dadf00d79472c5 100644 (file)
@@ -1 +1 @@
-1.59.0
+1.60.0