]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #92704 - 5225225:std_mem_transmute_ref_t_mut_t, r=michaelwoerister
authorMatthias Krüger <matthias.krueger@famsik.de>
Thu, 20 Jan 2022 16:10:37 +0000 (17:10 +0100)
committerGitHub <noreply@github.com>
Thu, 20 Jan 2022 16:10:37 +0000 (17:10 +0100)
Change lint message to be stronger for &T -> &mut T transmute

The old message implied that it's only UB if you use the reference to mutate, which (as far as I know) is not true. As in, the following program has UB, and a &T -> &mut T transmute is effectively an `unreachable_unchecked`.

```rust
fn main() {
    #[allow(mutable_transmutes)]
    unsafe {
        let _ = std::mem::transmute::<&i32, &mut i32>(&0);
    }
}
```

In the future, it might be a good idea to use the edition system to make this a hard error, since I don't think it is *ever* defined behaviour? Unless we rule that `&UnsafeCell<i32> -> &mut i32` is fine. (That, and you always could just use `.get()`, so you're not losing anything)

1221 files changed:
.github/workflows/ci.yml
.mailmap
Cargo.lock
RELEASES.md
compiler/rustc_ast/src/ast.rs
compiler/rustc_ast/src/mut_visit.rs
compiler/rustc_ast/src/util/comments.rs
compiler/rustc_ast/src/visit.rs
compiler/rustc_ast_lowering/src/asm.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/path.rs
compiler/rustc_ast_passes/src/ast_validation.rs
compiler/rustc_ast_passes/src/feature_gate.rs
compiler/rustc_ast_passes/src/node_count.rs
compiler/rustc_ast_pretty/Cargo.toml
compiler/rustc_ast_pretty/src/pp.rs
compiler/rustc_ast_pretty/src/pp/ring.rs [new file with mode: 0644]
compiler/rustc_ast_pretty/src/pprust/state.rs
compiler/rustc_ast_pretty/src/pprust/state/expr.rs [new file with mode: 0644]
compiler/rustc_ast_pretty/src/pprust/state/item.rs [new file with mode: 0644]
compiler/rustc_borrowck/src/dataflow.rs
compiler/rustc_borrowck/src/def_use.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/invalidation.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/lib.rs
compiler/rustc_builtin_macros/src/llvm_asm.rs [deleted file]
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_cranelift/src/inline_asm.rs
compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
compiler/rustc_codegen_gcc/src/asm.rs
compiler/rustc_codegen_gcc/src/type_of.rs
compiler/rustc_codegen_llvm/src/asm.rs
compiler/rustc_codegen_llvm/src/back/archive.rs
compiler/rustc_codegen_llvm/src/back/lto.rs
compiler/rustc_codegen_llvm/src/builder.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/analyze.rs
compiler/rustc_codegen_ssa/src/mir/block.rs
compiler/rustc_codegen_ssa/src/mir/mod.rs
compiler/rustc_codegen_ssa/src/mir/place.rs
compiler/rustc_codegen_ssa/src/mir/rvalue.rs
compiler/rustc_codegen_ssa/src/mir/statement.rs
compiler/rustc_codegen_ssa/src/traits/asm.rs
compiler/rustc_codegen_ssa/src/traits/builder.rs
compiler/rustc_const_eval/src/const_eval/fn_queries.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_const_eval/src/transform/validate.rs
compiler/rustc_data_structures/Cargo.toml
compiler/rustc_data_structures/src/stable_hasher.rs
compiler/rustc_data_structures/src/thin_vec/tests.rs
compiler/rustc_data_structures/src/vec_map/tests.rs
compiler/rustc_driver/src/lib.rs
compiler/rustc_error_codes/src/error_codes/E0038.md
compiler/rustc_error_codes/src/error_codes/E0183.md
compiler/rustc_error_codes/src/error_codes/E0521.md
compiler/rustc_error_codes/src/error_codes/E0581.md
compiler/rustc_error_codes/src/error_codes/E0660.md
compiler/rustc_error_codes/src/error_codes/E0661.md
compiler/rustc_error_codes/src/error_codes/E0662.md
compiler/rustc_error_codes/src/error_codes/E0663.md
compiler/rustc_error_codes/src/error_codes/E0664.md
compiler/rustc_error_codes/src/error_codes/E0668.md
compiler/rustc_error_codes/src/error_codes/E0669.md
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/proc_macro_server.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_feature/src/builtin_attrs.rs
compiler/rustc_graphviz/src/tests.rs
compiler/rustc_hir/src/arena.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/lib.rs
compiler/rustc_hir/src/weak_lang_items.rs
compiler/rustc_hir_pretty/src/lib.rs
compiler/rustc_incremental/src/assert_dep_graph.rs
compiler/rustc_incremental/src/persist/dirty_clean.rs
compiler/rustc_incremental/src/persist/file_format.rs
compiler/rustc_incremental/src/persist/fs/tests.rs
compiler/rustc_index/src/lib.rs
compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
compiler/rustc_infer/src/infer/canonical/mod.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/different_lifetimes.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
compiler/rustc_infer/src/infer/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/obligations.rs
compiler/rustc_infer/src/infer/outlives/verify.rs
compiler/rustc_infer/src/infer/projection.rs
compiler/rustc_infer/src/infer/resolve.rs
compiler/rustc_infer/src/traits/util.rs
compiler/rustc_interface/Cargo.toml
compiler/rustc_interface/src/tests.rs
compiler/rustc_interface/src/util.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
compiler/rustc_lint/src/internal.rs
compiler/rustc_lint/src/late.rs
compiler/rustc_lint/src/levels.rs
compiler/rustc_lint/src/lib.rs
compiler/rustc_lint/src/noop_method_call.rs
compiler/rustc_lint/src/pass_by_value.rs [new file with mode: 0644]
compiler/rustc_lint/src/types.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_metadata/src/native_libs.rs
compiler/rustc_metadata/src/rmeta/decoder.rs
compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
compiler/rustc_metadata/src/rmeta/encoder.rs
compiler/rustc_metadata/src/rmeta/mod.rs
compiler/rustc_middle/Cargo.toml
compiler/rustc_middle/src/dep_graph/mod.rs
compiler/rustc_middle/src/hir/map/mod.rs
compiler/rustc_middle/src/hir/mod.rs
compiler/rustc_middle/src/hir/nested_filter.rs [new file with mode: 0644]
compiler/rustc_middle/src/infer/canonical.rs
compiler/rustc_middle/src/middle/privacy.rs
compiler/rustc_middle/src/middle/stability.rs
compiler/rustc_middle/src/mir/interpret/queries.rs
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/mono.rs
compiler/rustc_middle/src/mir/pretty.rs
compiler/rustc_middle/src/mir/spanview.rs
compiler/rustc_middle/src/mir/terminator.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_middle/src/thir.rs
compiler/rustc_middle/src/thir/visit.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/diagnostics.rs
compiler/rustc_middle/src/ty/erase_regions.rs
compiler/rustc_middle/src/ty/error.rs
compiler/rustc_middle/src/ty/flags.rs
compiler/rustc_middle/src/ty/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/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/expr/as_rvalue.rs
compiler/rustc_mir_build/src/build/expr/category.rs
compiler/rustc_mir_build/src/build/expr/into.rs
compiler/rustc_mir_build/src/build/expr/stmt.rs
compiler/rustc_mir_build/src/build/matches/mod.rs
compiler/rustc_mir_build/src/build/matches/test.rs
compiler/rustc_mir_build/src/build/mod.rs
compiler/rustc_mir_build/src/build/scope.rs
compiler/rustc_mir_build/src/check_unsafety.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/impls/liveness.rs
compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
compiler/rustc_mir_dataflow/src/move_paths/builder.rs
compiler/rustc_mir_transform/src/check_unsafety.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/coverage/spans.rs
compiler/rustc_mir_transform/src/dest_prop.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/remove_noop_landing_pads.rs
compiler/rustc_mir_transform/src/separate_const_switch.rs
compiler/rustc_mir_transform/src/shim.rs
compiler/rustc_mir_transform/src/simplify.rs
compiler/rustc_mir_transform/src/simplify_try.rs
compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
compiler/rustc_mir_transform/src/unreachable_prop.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/expr.rs
compiler/rustc_parse/src/parser/path.rs
compiler/rustc_parse/src/parser/ty.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/hir_stats.rs
compiler/rustc_passes/src/intrinsicck.rs
compiler/rustc_passes/src/lang_items.rs
compiler/rustc_passes/src/lib.rs
compiler/rustc_passes/src/lib_features.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_passes/src/loops.rs
compiler/rustc_passes/src/naked_functions.rs
compiler/rustc_passes/src/reachable.rs
compiler/rustc_passes/src/region.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_passes/src/upvars.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_resolve/src/access_levels.rs [new file with mode: 0644]
compiler/rustc_resolve/src/build_reduced_graph.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/imports.rs
compiler/rustc_resolve/src/late.rs
compiler/rustc_resolve/src/late/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_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/asm/aarch64.rs
compiler/rustc_target/src/asm/arm.rs
compiler/rustc_target/src/asm/avr.rs
compiler/rustc_target/src/asm/bpf.rs
compiler/rustc_target/src/asm/hexagon.rs
compiler/rustc_target/src/asm/mips.rs
compiler/rustc_target/src/asm/mod.rs
compiler/rustc_target/src/asm/nvptx.rs
compiler/rustc_target/src/asm/powerpc.rs
compiler/rustc_target/src/asm/riscv.rs
compiler/rustc_target/src/asm/s390x.rs
compiler/rustc_target/src/asm/spirv.rs
compiler/rustc_target/src/asm/wasm.rs
compiler/rustc_target/src/asm/x86.rs
compiler/rustc_target/src/spec/armv6k_nintendo_3ds.rs
compiler/rustc_target/src/spec/avr_gnu_base.rs
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_trait_selection/src/traits/auto_trait.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/relationships.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/specialize/mod.rs
compiler/rustc_trait_selection/src/traits/structural_match.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_traits/src/chalk/lowering.rs
compiler/rustc_traits/src/chalk/mod.rs
compiler/rustc_ty_utils/src/assoc.rs
compiler/rustc_ty_utils/src/instance.rs
compiler/rustc_ty_utils/src/representability.rs
compiler/rustc_ty_utils/src/ty.rs
compiler/rustc_type_ir/src/lib.rs
compiler/rustc_typeck/src/astconv/errors.rs
compiler/rustc_typeck/src/astconv/mod.rs
compiler/rustc_typeck/src/bounds.rs
compiler/rustc_typeck/src/check/check.rs
compiler/rustc_typeck/src/check/closure.rs
compiler/rustc_typeck/src/check/coercion.rs
compiler/rustc_typeck/src/check/compare_method.rs
compiler/rustc_typeck/src/check/demand.rs
compiler/rustc_typeck/src/check/dropck.rs
compiler/rustc_typeck/src/check/expr.rs
compiler/rustc_typeck/src/check/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/gather_locals.rs
compiler/rustc_typeck/src/check/generator_interior.rs
compiler/rustc_typeck/src/check/intrinsic.rs
compiler/rustc_typeck/src/check/method/confirm.rs
compiler/rustc_typeck/src/check/method/mod.rs
compiler/rustc_typeck/src/check/method/probe.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/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/item_bounds.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/hir_wf_check.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/mem_categorization.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/src/collections/btree/map.rs
library/alloc/src/collections/btree/map/tests.rs
library/alloc/src/collections/btree/set.rs
library/alloc/src/collections/mod.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/lib.rs
library/alloc/src/macros.rs
library/alloc/src/raw_vec.rs
library/alloc/src/slice.rs
library/alloc/src/vec/into_iter.rs
library/alloc/src/vec/mod.rs
library/alloc/src/vec/spec_from_iter_nested.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/src/cmp.rs
library/core/src/convert/mod.rs
library/core/src/future/pending.rs
library/core/src/hash/mod.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/sources/empty.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/lib.rs
library/core/src/macros/mod.rs
library/core/src/mem/maybe_uninit.rs
library/core/src/num/bignum.rs
library/core/src/num/f32.rs
library/core/src/num/f64.rs
library/core/src/num/int_log10.rs
library/core/src/num/int_macros.rs
library/core/src/num/mod.rs
library/core/src/num/nonzero.rs
library/core/src/num/saturating.rs
library/core/src/num/uint_macros.rs
library/core/src/option.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/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/proc_macro/src/bridge/client.rs
library/proc_macro/src/lib.rs
library/std/src/collections/hash/map/tests.rs
library/std/src/collections/mod.rs
library/std/src/error.rs
library/std/src/error/tests.rs
library/std/src/ffi/c_str.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/macros.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/path.rs
library/std/src/prelude/v1.rs
library/std/src/thread/local.rs
library/std/src/thread/mod.rs
library/std/src/time.rs
library/stdarch
library/test/src/tests.rs
src/bootstrap/bootstrap.py
src/bootstrap/bootstrap_test.py
src/bootstrap/compile.rs
src/bootstrap/dist.rs
src/ci/docker/scripts/musl-toolchain.sh
src/ci/github-actions/ci.yml
src/doc/book
src/doc/nomicon
src/doc/reference
src/doc/rustc-dev-guide
src/doc/rustc/src/SUMMARY.md
src/doc/rustc/src/command-line-arguments.md
src/doc/rustc/src/platform-support/TEMPLATE.md [new file with mode: 0644]
src/doc/rustc/src/target-tier-policy.md
src/doc/rustdoc/src/documentation-tests.md
src/doc/rustdoc/src/unstable-features.md
src/doc/unstable-book/src/library-features/llvm-asm.md [deleted file]
src/etc/check_missing_items.py
src/etc/htmldocck.py
src/librustdoc/Cargo.toml
src/librustdoc/askama.toml [new file with mode: 0644]
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/simplify.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/config.rs
src/librustdoc/core.rs
src/librustdoc/doctest.rs
src/librustdoc/formats/cache.rs
src/librustdoc/html/format.rs
src/librustdoc/html/layout.rs
src/librustdoc/html/markdown.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/span_map.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/js/settings.js
src/librustdoc/html/static/js/source-script.js
src/librustdoc/html/static/js/storage.js
src/librustdoc/html/static_files.rs
src/librustdoc/html/templates/page.html
src/librustdoc/html/templates/print_item.html
src/librustdoc/html/tests.rs
src/librustdoc/html/url_parts_builder.rs
src/librustdoc/html/url_parts_builder/tests.rs
src/librustdoc/json/conversions.rs
src/librustdoc/json/mod.rs
src/librustdoc/lib.rs
src/librustdoc/passes/collect_intra_doc_links.rs
src/librustdoc/passes/stripper.rs
src/librustdoc/scrape_examples.rs
src/librustdoc/visit_ast.rs
src/rustdoc-json-types/lib.rs
src/test/codegen/async-fn-debug-msvc.rs
src/test/codegen/async-fn-debug.rs
src/test/codegen/no-output-asm-is-volatile.rs [deleted file]
src/test/codegen/thread-local.rs
src/test/incremental/cache_file_headers.rs
src/test/incremental/hashes/inline_asm.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/mir-opt/unreachable_asm.main.UnreachablePropagation.diff [deleted file]
src/test/mir-opt/unreachable_asm.rs [deleted file]
src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff [deleted file]
src/test/mir-opt/unreachable_asm_2.rs [deleted file]
src/test/pretty/llvm-asm-clobbers.rs [deleted file]
src/test/pretty/llvm-asm-options.rs [deleted file]
src/test/pretty/raw-str-nonexpr.rs
src/test/run-make-fulldeps/codegen-options-parsing/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/crate-hash-rustc-version/Makefile
src/test/run-make-fulldeps/interdependent-c-libraries/Makefile
src/test/run-make-fulldeps/intrinsic-unreachable/exit-ret.rs
src/test/run-make-fulldeps/intrinsic-unreachable/exit-unreachable.rs
src/test/run-make-fulldeps/link-arg/Makefile
src/test/run-make-fulldeps/metadata-flag-frobs-symbols/Makefile
src/test/run-make-fulldeps/no-builtins-lto/Makefile
src/test/run-make-fulldeps/redundant-libs/Makefile
src/test/run-make-fulldeps/static-nobundle/Makefile
src/test/run-make/raw-dylib-c/Makefile
src/test/run-make/raw-dylib-link-ordinal/Makefile
src/test/run-make/raw-dylib-stdcall-ordinal/Makefile [new file with mode: 0644]
src/test/run-make/raw-dylib-stdcall-ordinal/driver.rs [new file with mode: 0644]
src/test/run-make/raw-dylib-stdcall-ordinal/expected_output.txt [new file with mode: 0644]
src/test/run-make/raw-dylib-stdcall-ordinal/exporter-gnu.def [new file with mode: 0644]
src/test/run-make/raw-dylib-stdcall-ordinal/exporter-msvc.def [new file with mode: 0644]
src/test/run-make/raw-dylib-stdcall-ordinal/exporter.c [new file with mode: 0644]
src/test/run-make/raw-dylib-stdcall-ordinal/lib.rs [new file with mode: 0644]
src/test/rustdoc-gui/anchors.goml
src/test/rustdoc-gui/code-blocks-overflow.goml
src/test/rustdoc-gui/docblock-table-overflow.goml
src/test/rustdoc-gui/headings.goml
src/test/rustdoc-gui/item-info-width.goml
src/test/rustdoc-gui/rust-logo.goml [new file with mode: 0644]
src/test/rustdoc-gui/search-result-display.goml
src/test/rustdoc-gui/sidebar-mobile.goml
src/test/rustdoc-gui/sidebar-source-code.goml
src/test/rustdoc-gui/sidebar.goml
src/test/rustdoc-gui/src/staged_api/Cargo.lock [new file with mode: 0644]
src/test/rustdoc-gui/src/staged_api/Cargo.toml [new file with mode: 0644]
src/test/rustdoc-gui/src/staged_api/lib.rs [new file with mode: 0644]
src/test/rustdoc-gui/toggle-docs-mobile.goml
src/test/rustdoc-gui/toggle-docs.goml
src/test/rustdoc-gui/type-declation-overflow.goml
src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
src/test/rustdoc/cap-lints.rs
src/test/rustdoc/const-display.rs
src/test/rustdoc/crate-version-escape.rs
src/test/rustdoc/crate-version.rs
src/test/rustdoc/decl_macro.rs
src/test/rustdoc/deref-const-fn.rs
src/test/rustdoc/ensure-src-link.rs
src/test/rustdoc/external-macro-src.rs
src/test/rustdoc/intra-doc/extern-type.rs
src/test/rustdoc/intra-doc/generic-trait-impl.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/prim-self.rs [new file with mode: 0644]
src/test/rustdoc/intra-doc/self-cache.rs [new file with mode: 0644]
src/test/rustdoc/intra-link-prim-self.rs [deleted file]
src/test/rustdoc/intra-link-self-cache.rs [deleted file]
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/source-version-separator.rs [new file with mode: 0644]
src/test/rustdoc/src-links-auto-impls.rs
src/test/rustdoc/structfields.rs
src/test/rustdoc/thread-local-src.rs
src/test/rustdoc/titles.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/typedef.rs
src/test/rustdoc/union.rs
src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs [deleted file]
src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr [deleted file]
src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs [deleted file]
src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr [deleted file]
src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs [new file with mode: 0644]
src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr [new file with mode: 0644]
src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs [new file with mode: 0644]
src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr [new file with mode: 0644]
src/test/ui/abi/abi-sysv64-register-usage.rs
src/test/ui/asm/naked-functions.rs
src/test/ui/asm/naked-functions.stderr
src/test/ui/associated-consts/assoc-const.rs [new file with mode: 0644]
src/test/ui/associated-consts/assoc-const.stderr [new file with mode: 0644]
src/test/ui/associated-types/substs-ppaux.rs
src/test/ui/associated-types/substs-ppaux.verbose.stderr
src/test/ui/ast-json/ast-json-ice.rs
src/test/ui/async-await/interior-with-const-generic-expr.rs [new file with mode: 0644]
src/test/ui/async-await/issue-76547.stderr
src/test/ui/async-await/issues/issue-63388-1.stderr
src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr
src/test/ui/autoref-autoderef/deref-into-array.rs [new file with mode: 0644]
src/test/ui/borrowck/borrowck-asm.rs [deleted file]
src/test/ui/borrowck/borrowck-asm.stderr [deleted file]
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/const-generics/deref-into-array-generic.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/array-in-sig.rs [deleted file]
src/test/ui/const-generics/generic_arg_infer/array-in-sig.stderr [deleted file]
src/test/ui/const-generics/generic_arg_infer/in-signature.rs [new file with mode: 0644]
src/test/ui/const-generics/generic_arg_infer/in-signature.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/const-generics/issues/issue-92186.rs [new file with mode: 0644]
src/test/ui/const-generics/min_const_generics/const-expression-suggest-missing-braces-without-turbofish.stderr
src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs
src/test/ui/const-generics/parser-error-recovery/issue-89013-no-kw.stderr
src/test/ui/const-generics/parser-error-recovery/issue-89013.rs
src/test/ui/const-generics/parser-error-recovery/issue-89013.stderr
src/test/ui/const-generics/types-mismatch-const-args.full.stderr
src/test/ui/const-generics/types-mismatch-const-args.min.stderr
src/test/ui/const-generics/types-mismatch-const-args.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/consts/miri_unleashed/inline_asm.rs
src/test/ui/consts/miri_unleashed/inline_asm.stderr
src/test/ui/derive-uninhabited-enum-38885.stderr
src/test/ui/derives/clone-debug-dead-code.stderr
src/test/ui/did_you_mean/bad-assoc-ty.rs
src/test/ui/did_you_mean/bad-assoc-ty.stderr
src/test/ui/did_you_mean/compatible-variants.rs
src/test/ui/did_you_mean/compatible-variants.stderr
src/test/ui/did_you_mean/issue-40396.stderr
src/test/ui/error-codes/E0121.stderr
src/test/ui/error-codes/E0660.rs [deleted file]
src/test/ui/error-codes/E0660.stderr [deleted file]
src/test/ui/error-codes/E0661.rs [deleted file]
src/test/ui/error-codes/E0661.stderr [deleted file]
src/test/ui/error-codes/E0662.rs [deleted file]
src/test/ui/error-codes/E0662.stderr [deleted file]
src/test/ui/error-codes/E0663.rs [deleted file]
src/test/ui/error-codes/E0663.stderr [deleted file]
src/test/ui/error-codes/E0664.rs [deleted file]
src/test/ui/error-codes/E0664.stderr [deleted file]
src/test/ui/expr/if/attrs/let-chains-attr.rs
src/test/ui/expr/if/attrs/let-chains-attr.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-asm.rs [deleted file]
src/test/ui/feature-gates/feature-gate-asm.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-asm2.rs [deleted file]
src/test/ui/feature-gates/feature-gate-asm2.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-associated_const_equality.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-associated_const_equality.stderr [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-cfg-target-abi.rs
src/test/ui/feature-gates/feature-gate-cfg-target-abi.stderr
src/test/ui/feature-gates/feature-gate-in_band_lifetimes.stderr
src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs [deleted file]
src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs [deleted file]
src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr [deleted file]
src/test/ui/feature-gates/feature-gate-raw-dylib.rs [new file with mode: 0644]
src/test/ui/feature-gates/feature-gate-raw-dylib.stderr [new file with mode: 0644]
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/feature-gates/issue-43106-gating-of-builtin-attrs.rs
src/test/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
src/test/ui/fn/issue-80179.rs
src/test/ui/fn/issue-80179.stderr
src/test/ui/generic-associated-types/issue-89352.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-92096.migrate.stderr [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-92096.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/issue-92280.rs [new file with mode: 0644]
src/test/ui/generic-associated-types/self-outlives-lint.rs
src/test/ui/inference/deref-suggestion.stderr
src/test/ui/infinite/infinite-autoderef.stderr
src/test/ui/issues/issue-3214.rs
src/test/ui/issues/issue-3214.stderr
src/test/ui/issues/issue-69396-const-no-type-in-macro.rs
src/test/ui/issues/issue-69396-const-no-type-in-macro.stderr
src/test/ui/issues/issue-9129.rs
src/test/ui/lint/dead-code/unused-variant.stderr
src/test/ui/lint/lint-pub-unreachable-for-nested-glob.rs [new file with mode: 0644]
src/test/ui/llvm-asm/asm-src-loc-codegen-units.rs [deleted file]
src/test/ui/llvm-asm/asm-src-loc.rs [deleted file]
src/test/ui/llvm-asm/inline-asm-bad-constraint.rs [deleted file]
src/test/ui/llvm-asm/inline-asm-bad-constraint.stderr [deleted file]
src/test/ui/llvm-asm/inline-asm-bad-operand.rs [deleted file]
src/test/ui/llvm-asm/inline-asm-bad-operand.stderr [deleted file]
src/test/ui/llvm-asm/issue-14936.rs [deleted file]
src/test/ui/llvm-asm/issue-23458.rs [deleted file]
src/test/ui/llvm-asm/issue-23458.stderr [deleted file]
src/test/ui/llvm-asm/issue-33264.rs [deleted file]
src/test/ui/llvm-asm/issue-37366.rs [deleted file]
src/test/ui/llvm-asm/issue-37433.rs [deleted file]
src/test/ui/llvm-asm/issue-37433.stderr [deleted file]
src/test/ui/llvm-asm/issue-51431.rs [deleted file]
src/test/ui/llvm-asm/issue-51431.stderr [deleted file]
src/test/ui/llvm-asm/issue-53787-inline-assembler-macro.rs [deleted file]
src/test/ui/llvm-asm/issue-53787-inline-assembler-macro.stderr [deleted file]
src/test/ui/llvm-asm/issue-54067.rs [deleted file]
src/test/ui/llvm-asm/issue-62046.rs [deleted file]
src/test/ui/llvm-asm/issue-62046.stderr [deleted file]
src/test/ui/llvm-asm/issue-69092.rs [deleted file]
src/test/ui/llvm-asm/issue-69092.stderr [deleted file]
src/test/ui/llvm-asm/llvm-asm-bad-clobber.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-bad-clobber.stderr [deleted file]
src/test/ui/llvm-asm/llvm-asm-concat-src.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-in-bad-modifier.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-in-bad-modifier.stderr [deleted file]
src/test/ui/llvm-asm/llvm-asm-in-moved.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-indirect-memory.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-literal-escaping.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-misplaced-option.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-misplaced-option.stderr [deleted file]
src/test/ui/llvm-asm/llvm-asm-out-assign-imm.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-out-assign-imm.stderr [deleted file]
src/test/ui/llvm-asm/llvm-asm-out-assign.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-out-no-modifier.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-out-no-modifier.stderr [deleted file]
src/test/ui/llvm-asm/llvm-asm-out-read-uninit.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-out-read-uninit.stderr [deleted file]
src/test/ui/llvm-asm/llvm-asm-parse-errors.rs [deleted file]
src/test/ui/llvm-asm/llvm-asm-parse-errors.stderr [deleted file]
src/test/ui/macros/macro-interpolation.rs
src/test/ui/macros/macros-nonfatal-errors.rs
src/test/ui/macros/macros-nonfatal-errors.stderr
src/test/ui/macros/stringify.rs
src/test/ui/mir/mir_let_chains_drop_order.rs [new file with mode: 0644]
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/occurs-check-2.stderr
src/test/ui/occurs-check.stderr
src/test/ui/panics/panic-handler-chain-update-hook.rs [new file with mode: 0644]
src/test/ui/parser/issues/issue-35813-postfix-after-cast.rs
src/test/ui/parser/issues/issue-35813-postfix-after-cast.stderr
src/test/ui/parser/issues/issue-84148-1.rs
src/test/ui/parser/issues/issue-84148-1.stderr
src/test/ui/parser/issues/issue-84148-2.rs
src/test/ui/parser/issues/issue-84148-2.stderr
src/test/ui/parser/recover-assoc-const-constraint.rs
src/test/ui/parser/recover-assoc-const-constraint.stderr
src/test/ui/parser/require-parens-for-chained-comparison.rs
src/test/ui/parser/require-parens-for-chained-comparison.stderr
src/test/ui/parser/trailing-question-in-type.fixed [new file with mode: 0644]
src/test/ui/parser/trailing-question-in-type.rs [new file with mode: 0644]
src/test/ui/parser/trailing-question-in-type.stderr [new file with mode: 0644]
src/test/ui/pattern/issue-82290.rs [deleted file]
src/test/ui/pattern/issue-82290.stderr [deleted file]
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/proc-macro/cfg-eval-fail.rs
src/test/ui/proc-macro/cfg-eval-fail.stderr
src/test/ui/return/tail-expr-as-potential-return.rs
src/test/ui/return/tail-expr-as-potential-return.stderr
src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.rs
src/test/ui/rfc-2497-if-let-chains/ast-pretty-check.stdout
src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs
src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr
src/test/ui/rfc-2497-if-let-chains/feature-gate.rs
src/test/ui/rfc-2497-if-let-chains/feature-gate.stderr
src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/issue-88498.rs [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/issue-90722.rs [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/issue-92145.rs [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs [new file with mode: 0644]
src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs [new file with mode: 0644]
src/test/ui/rfc-2627-raw-dylib/link-ordinal-multiple.rs
src/test/ui/rfc-2627-raw-dylib/multiple-declarations.rs
src/test/ui/rfc-2627-raw-dylib/multiple-declarations.stderr
src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs [deleted file]
src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr [deleted file]
src/test/ui/rfc-2627-raw-dylib/unsupported-abi.rs
src/test/ui/rfc-2627-raw-dylib/unsupported-abi.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/runtime/out-of-stack.rs
src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
src/test/ui/self/elision/lt-ref-self-async.stderr
src/test/ui/self/elision/ref-mut-self-async.stderr
src/test/ui/self/elision/ref-mut-struct-async.stderr
src/test/ui/self/elision/ref-self-async.stderr
src/test/ui/self/elision/ref-struct-async.stderr
src/test/ui/self/self-infer.rs
src/test/ui/self/self-infer.stderr
src/test/ui/simd/intrinsic/generic-as.rs [new file with mode: 0644]
src/test/ui/simd/intrinsic/generic-cast-pointer-width.rs [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/specialization/min_specialization/repeated_projection_type.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/issue-82566-1.stderr
src/test/ui/suggestions/issue-82566-2.stderr
src/test/ui/suggestions/unnamable-types.rs
src/test/ui/suggestions/unnamable-types.stderr
src/test/ui/symbol-names/foreign-types.rs [new file with mode: 0644]
src/test/ui/symbol-names/foreign-types.stderr [new file with mode: 0644]
src/test/ui/terr-sorts.stderr
src/test/ui/traits/default-method/rustc_must_implement_one_of.rs [new file with mode: 0644]
src/test/ui/traits/default-method/rustc_must_implement_one_of.stderr [new file with mode: 0644]
src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs [new file with mode: 0644]
src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.stderr [new file with mode: 0644]
src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.rs [new file with mode: 0644]
src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr [new file with mode: 0644]
src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs [new file with mode: 0644]
src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr [new file with mode: 0644]
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/test/ui/type-alias-impl-trait/issue-77179.rs
src/test/ui/type-alias-impl-trait/issue-77179.stderr
src/test/ui/typeck/issue-74086.rs
src/test/ui/typeck/issue-74086.stderr
src/test/ui/typeck/issue-75883.rs
src/test/ui/typeck/issue-75883.stderr
src/test/ui/typeck/issue-75889.stderr
src/test/ui/typeck/issue-80779.rs
src/test/ui/typeck/issue-80779.stderr
src/test/ui/typeck/issue-81885.rs
src/test/ui/typeck/issue-81885.stderr
src/test/ui/typeck/issue-83621-placeholder-static-in-extern.stderr
src/test/ui/typeck/issue-91450-inner-ty-error.rs
src/test/ui/typeck/issue-91450-inner-ty-error.stderr
src/test/ui/typeck/type-placeholder-fn-in-const.rs
src/test/ui/typeck/type-placeholder-fn-in-const.stderr
src/test/ui/typeck/typeck_type_placeholder_item.rs
src/test/ui/typeck/typeck_type_placeholder_item.stderr
src/test/ui/typeck/typeck_type_placeholder_item_help.rs
src/test/ui/typeck/typeck_type_placeholder_item_help.stderr
src/test/ui/unsafe/inline_asm.mir.stderr
src/test/ui/unsafe/inline_asm.rs
src/test/ui/unsafe/inline_asm.thir.stderr
src/tools/build-manifest/Cargo.toml
src/tools/build-manifest/README.md
src/tools/build-manifest/src/main.rs
src/tools/build-manifest/src/versions.rs
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/COPYRIGHT
src/tools/clippy/Cargo.toml
src/tools/clippy/LICENSE-APACHE
src/tools/clippy/LICENSE-MIT
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/assign_ops.rs
src/tools/clippy/clippy_lints/src/attrs.rs
src/tools/clippy/clippy_lints/src/bit_mask.rs
src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
src/tools/clippy/clippy_lints/src/booleans.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/cognitive_complexity.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/derive.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/eval_order_dependence.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_let_mutex.rs
src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
src/tools/clippy/clippy_lints/src/implicit_hasher.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.register_suspicious.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/utils.rs
src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.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_async_fn.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_strip.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/implicit_clone.rs
src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs [new file with mode: 0644]
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
src/tools/clippy/clippy_lints/src/methods/unnecessary_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/mut_mut.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_closure_call.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/slow_vector_initialization.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/types/type_complexity.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_return_expecting_ord.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_async.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/unwrap.rs
src/tools/clippy/clippy_lints/src/unwrap_in_result.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/usage.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/rustc_tools_util/README.md
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/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/cmp_owned/comparison_flip.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr [new file with mode: 0644]
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/format.fixed
src/tools/clippy/tests/ui/format.rs
src/tools/clippy/tests/ui/format.stderr
src/tools/clippy/tests/ui/functions.rs
src/tools/clippy/tests/ui/functions.stderr
src/tools/clippy/tests/ui/identity_op.rs
src/tools/clippy/tests/ui/identity_op.stderr
src/tools/clippy/tests/ui/if_same_then_else2.rs
src/tools/clippy/tests/ui/implicit_clone.rs
src/tools/clippy/tests/ui/implicit_clone.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/iter_overeager_cloned.fixed [new file with mode: 0644]
src/tools/clippy/tests/ui/iter_overeager_cloned.rs [new file with mode: 0644]
src/tools/clippy/tests/ui/iter_overeager_cloned.stderr [new file with mode: 0644]
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/or_fun_call.stderr
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.rs
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/clippy/util/gh-pages/index.html
src/tools/miri
src/tools/rls
src/tools/rust-demangler/tests/lib.rs
src/tools/rustfmt/Configurations.md
src/tools/rustfmt/src/config/mod.rs
src/tools/rustfmt/src/expr.rs
src/tools/rustfmt/src/formatting.rs
src/tools/rustfmt/src/lib.rs
src/tools/rustfmt/src/test/mod.rs
src/tools/rustfmt/src/types.rs
src/tools/rustfmt/src/utils.rs
src/tools/tidy/src/deps.rs

index 67deb3d97794222b76c59e78ef8d4f2386843870..fe5dedb6ba4b73be4d4c8c3de58cf85d683e6c12 100644 (file)
@@ -320,7 +320,7 @@ jobs:
           - name: dist-aarch64-apple
             env:
               SCRIPT: "./x.py dist --stage 2"
-              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --disable-docs --set rust.jemalloc --set llvm.ninja=false"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               USE_XCODE_CLANG: 1
               MACOSX_DEPLOYMENT_TARGET: 11.0
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 50a5d78731febc6ebab8d2c5151b9f2e5d3c5362..a7496e61b8bebf6360cbde303dfdb889234e623d 100644 (file)
@@ -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"
@@ -103,6 +114,49 @@ 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",
+ "serde",
+ "syn",
+ "toml",
+]
+
 [[package]]
 name = "atty"
 version = "0.2.14"
@@ -274,7 +328,7 @@ dependencies = [
 
 [[package]]
 name = "cargo"
-version = "0.60.0"
+version = "0.61.0"
 dependencies = [
  "anyhow",
  "atty",
@@ -283,9 +337,9 @@ dependencies = [
  "cargo-test-macro",
  "cargo-test-support",
  "cargo-util",
- "clap",
+ "clap 3.0.10",
  "crates-io",
- "crossbeam-utils 0.8.3",
+ "crossbeam-utils",
  "curl",
  "curl-sys",
  "env_logger 0.9.0",
@@ -563,16 +617,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.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a30c3bf9ff12dfe5dae53f0a96e0febcd18420d1c0e7fad77796d9d5c4b5375"
+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",
@@ -580,6 +649,7 @@ dependencies = [
  "compiletest_rs",
  "derive-new",
  "filetime",
+ "futures 0.3.12",
  "if_chain",
  "itertools 0.10.1",
  "parking_lot",
@@ -592,6 +662,7 @@ dependencies = [
  "syn",
  "tempfile",
  "tester",
+ "tokio",
 ]
 
 [[package]]
@@ -600,7 +671,7 @@ version = "0.0.1"
 dependencies = [
  "bytecount",
  "cargo_metadata 0.14.0",
- "clap",
+ "clap 2.34.0",
  "indoc",
  "itertools 0.10.1",
  "opener",
@@ -611,7 +682,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.59"
+version = "0.1.60"
 dependencies = [
  "cargo_metadata 0.14.0",
  "clippy_utils",
@@ -632,8 +703,9 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.59"
+version = "0.1.60"
 dependencies = [
+ "arrayvec",
  "if_chain",
  "rustc-semver",
 ]
@@ -766,7 +838,7 @@ checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
 
 [[package]]
 name = "crates-io"
-version = "0.33.1"
+version = "0.34.0"
 dependencies = [
  "anyhow",
  "curl",
@@ -787,69 +859,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"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
-dependencies = [
- "autocfg",
- "cfg-if 0.1.10",
- "lazy_static",
-]
-
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.3"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49"
+checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120"
 dependencies = [
- "autocfg",
  "cfg-if 1.0.0",
  "lazy_static",
 ]
@@ -1509,17 +1556,6 @@ 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.2"
@@ -1549,6 +1585,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",
@@ -1665,7 +1702,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",
@@ -1716,7 +1753,7 @@ name = "installer"
 version = "0.0.0"
 dependencies = [
  "anyhow",
- "clap",
+ "clap 2.34.0",
  "flate2",
  "lazy_static",
  "num_cpus",
@@ -2135,12 +2172,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"
@@ -2161,7 +2192,7 @@ dependencies = [
  "ammonia",
  "anyhow",
  "chrono",
- "clap",
+ "clap 2.34.0",
  "elasticlunr-rs",
  "env_logger 0.7.1",
  "handlebars",
@@ -2229,9 +2260,9 @@ 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",
 ]
@@ -2245,6 +2276,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"
@@ -2304,6 +2341,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"
@@ -2349,8 +2397,6 @@ 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",
@@ -2368,6 +2414,18 @@ dependencies = [
  "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"
@@ -2465,6 +2523,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,25 +2931,18 @@ dependencies = [
 
 [[package]]
 name = "racer"
-version = "2.1.48"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fec2e85e7a30f8fd31b7cf288ad363b5e51fd2cb6f53b416b0cfaabd84e1ccb"
+checksum = "b0b4b5faaf07040474e8af74a9e19ff167d5d204df5db5c5c765edecfb900358"
 dependencies = [
  "bitflags",
- "clap",
+ "clap 2.34.0",
  "derive_more",
  "env_logger 0.7.1",
  "humantime 2.0.1",
  "lazy_static",
  "log",
  "rls-span",
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_parse",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
 ]
 
 [[package]]
@@ -3005,9 +3065,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",
@@ -3017,13 +3077,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",
 ]
@@ -3097,15 +3157,15 @@ dependencies = [
  "anyhow",
  "cargo",
  "cargo-util",
- "cargo_metadata 0.12.0",
+ "cargo_metadata 0.14.0",
  "clippy_lints",
  "crossbeam-channel",
  "difference",
- "env_logger 0.7.1",
+ "env_logger 0.9.0",
  "futures 0.3.12",
  "heck",
  "home",
- "itertools 0.9.0",
+ "itertools 0.10.1",
  "jsonrpc-core",
  "lazy_static",
  "log",
@@ -3114,7 +3174,7 @@ dependencies = [
  "num_cpus",
  "ordslice",
  "racer",
- "rand 0.7.3",
+ "rand 0.8.4",
  "rayon",
  "regex",
  "rls-analysis",
@@ -3144,9 +3204,9 @@ name = "rls-analysis"
 version = "0.18.2"
 dependencies = [
  "derive-new",
- "env_logger 0.7.1",
+ "env_logger 0.9.0",
  "fst",
- "itertools 0.9.0",
+ "itertools 0.10.1",
  "json",
  "lazy_static",
  "log",
@@ -3183,10 +3243,10 @@ name = "rls-rustc"
 version = "0.6.0"
 dependencies = [
  "clippy_lints",
- "env_logger 0.7.1",
+ "env_logger 0.9.0",
  "futures 0.3.12",
  "log",
- "rand 0.7.3",
+ "rand 0.8.4",
  "rls-data",
  "rls-ipc",
  "serde",
@@ -3224,257 +3284,11 @@ dependencies = [
 name = "rustbook"
 version = "0.1.0"
 dependencies = [
- "clap",
+ "clap 2.34.0",
  "env_logger 0.7.1",
  "mdbook",
 ]
 
-[[package]]
-name = "rustc-ap-rustc_arena"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "550ca1a0925d31a0af089b18c89f5adf3b286e319e3e1f1a5204c21bd2f17371"
-dependencies = [
- "rustc-ap-rustc_data_structures",
- "smallvec",
-]
-
-[[package]]
-name = "rustc-ap-rustc_ast"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4aa53b68080df17994a54747f7c37b0686288a670efb9ba3b382ce62e744aed2"
-dependencies = [
- "bitflags",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_index",
- "rustc-ap-rustc_lexer",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_serialize",
- "rustc-ap-rustc_span",
- "smallvec",
- "tracing",
-]
-
-[[package]]
-name = "rustc-ap-rustc_ast_pretty"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ae71e68fada466a4b2c39c79ca6aee3226587abe6787170d2f6c92237569565"
-dependencies = [
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_span",
- "tracing",
-]
-
-[[package]]
-name = "rustc-ap-rustc_data_structures"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "faa484d6e0ca32d1d82303647275c696f745599b3d97e686f396ceef5b99d7ae"
-dependencies = [
- "arrayvec",
- "bitflags",
- "cfg-if 0.1.10",
- "crossbeam-utils 0.8.3",
- "ena",
- "indexmap",
- "jobserver",
- "libc",
- "measureme 9.1.2",
- "memmap2",
- "parking_lot",
- "rustc-ap-rustc_graphviz",
- "rustc-ap-rustc_index",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_serialize",
- "rustc-hash",
- "rustc-rayon",
- "rustc-rayon-core",
- "smallvec",
- "stable_deref_trait",
- "stacker",
- "tempfile",
- "tracing",
- "winapi",
-]
-
-[[package]]
-name = "rustc-ap-rustc_errors"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f85ba19cca320ad797e3a29c35cab9bddfff0e7adbde336a436249e54cee7b1"
-dependencies = [
- "annotate-snippets",
- "atty",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_lint_defs",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_serialize",
- "rustc-ap-rustc_span",
- "termcolor",
- "termize",
- "tracing",
- "unicode-width",
- "winapi",
-]
-
-[[package]]
-name = "rustc-ap-rustc_feature"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97d538adab96b8b2b1ca9fcd4c8c47d4e23e862a23d1a38b6c15cd8fd52b34b1"
-dependencies = [
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_span",
-]
-
-[[package]]
-name = "rustc-ap-rustc_fs_util"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ad6f13d240944fa8f360d2f3b849a7cadaec75e477829e7dde61e838deda83d"
-
-[[package]]
-name = "rustc-ap-rustc_graphviz"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08b3451153cc5828c02cc4f1a0df146d25ac4b3382a112e25fd9d3f5bff15cdc"
-
-[[package]]
-name = "rustc-ap-rustc_index"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd39a9f01b442c629bdff5778cb3dd29b7c2ea4afe62d5ab61d216bd1b556692"
-dependencies = [
- "arrayvec",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_serialize",
-]
-
-[[package]]
-name = "rustc-ap-rustc_lexer"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5de290c44a90e671d2cd730062b9ef73d11155da7e44e7741d633e1e51e616e"
-dependencies = [
- "unicode-xid",
-]
-
-[[package]]
-name = "rustc-ap-rustc_lint_defs"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69570b4beb61088926b131579865bbe70d124d30778c46307a62ec8b310ae462"
-dependencies = [
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_serialize",
- "rustc-ap-rustc_span",
- "rustc-ap-rustc_target",
- "tracing",
-]
-
-[[package]]
-name = "rustc-ap-rustc_macros"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86bd877df37f15c5a44d9679d1b5207ebc95f3943fbc336eeac670195ac58610"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
- "synstructure",
-]
-
-[[package]]
-name = "rustc-ap-rustc_parse"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02502d8522ba31d0bcad28a78822b68c1b6ba947a2b4aa6a2341b30594379b80"
-dependencies = [
- "bitflags",
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_ast_pretty",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_feature",
- "rustc-ap-rustc_lexer",
- "rustc-ap-rustc_session",
- "rustc-ap-rustc_span",
- "smallvec",
- "tracing",
- "unicode-normalization",
-]
-
-[[package]]
-name = "rustc-ap-rustc_serialize"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f741f8e9aee6323fbe127329490608a5a250cc0072ac91e684ef62518cdb1ff"
-dependencies = [
- "indexmap",
- "smallvec",
-]
-
-[[package]]
-name = "rustc-ap-rustc_session"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dba61eca749f4fced4427ad1cc7f23342cfc6527c3bcc624e3aa56abc1f81298"
-dependencies = [
- "bitflags",
- "getopts",
- "num_cpus",
- "rustc-ap-rustc_ast",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_errors",
- "rustc-ap-rustc_feature",
- "rustc-ap-rustc_fs_util",
- "rustc-ap-rustc_lint_defs",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_serialize",
- "rustc-ap-rustc_span",
- "rustc-ap-rustc_target",
- "tracing",
-]
-
-[[package]]
-name = "rustc-ap-rustc_span"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a642e8d6fc883f34e0778e079f8242ac40c6614a6b7a0ef61681333e847f5e62"
-dependencies = [
- "cfg-if 0.1.10",
- "md-5",
- "rustc-ap-rustc_arena",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_index",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_serialize",
- "scoped-tls",
- "sha-1 0.9.1",
- "sha2",
- "tracing",
- "unicode-width",
-]
-
-[[package]]
-name = "rustc-ap-rustc_target"
-version = "722.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80feebd8c323b80dd73a395fa7fabba9e2098b6277670ff89c473f618ffa07de"
-dependencies = [
- "bitflags",
- "rustc-ap-rustc_data_structures",
- "rustc-ap-rustc_index",
- "rustc-ap-rustc_macros",
- "rustc-ap-rustc_serialize",
- "rustc-ap-rustc_span",
- "tracing",
-]
-
 [[package]]
 name = "rustc-demangle"
 version = "0.1.21"
@@ -3503,9 +3317,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",
@@ -3514,13 +3328,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",
 ]
@@ -3558,7 +3371,7 @@ version = "1.0.0"
 dependencies = [
  "bstr",
  "byteorder",
- "crossbeam-utils 0.8.3",
+ "crossbeam-utils",
  "libc",
  "libz-sys",
  "proc-macro2",
@@ -3646,7 +3459,6 @@ version = "0.0.0"
 dependencies = [
  "rustc_ast",
  "rustc_span",
- "tracing",
 ]
 
 [[package]]
@@ -3754,7 +3566,7 @@ dependencies = [
  "itertools 0.9.0",
  "jobserver",
  "libc",
- "object 0.26.2",
+ "object 0.28.1",
  "pathdiff",
  "regex",
  "rustc_apfloat",
@@ -4631,6 +4443,8 @@ name = "rustdoc"
 version = "0.0.0"
 dependencies = [
  "arrayvec",
+ "askama",
+ "atty",
  "expect-test",
  "itertools 0.9.0",
  "minifier",
@@ -4642,7 +4456,6 @@ dependencies = [
  "serde_json",
  "smallvec",
  "tempfile",
- "tera",
  "tracing",
  "tracing-subscriber",
  "tracing-tree",
@@ -5086,13 +4899,19 @@ 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.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "40b9788f4202aa75c240ecc9c15c65185e6a39ccdeb0fd5d008b98825464c87c"
 dependencies = [
- "clap",
+ "clap 2.34.0",
  "lazy_static",
  "structopt-derive",
 ]
@@ -5187,21 +5006,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"
@@ -5278,6 +5082,12 @@ 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.30"
@@ -5324,7 +5134,7 @@ name = "tidy"
 version = "0.1.0"
 dependencies = [
  "cargo_metadata 0.12.0",
- "crossbeam-utils 0.8.3",
+ "crossbeam-utils",
  "lazy_static",
  "regex",
  "walkdir",
index d6f5909a2ebc016eaf1fb4c354468843207fb3a3..460c78b14d13815004f7cfd57a8394a9e3f5cd10 100644 (file)
@@ -41,7 +41,9 @@ Stabilized APIs
 - [`Path::is_symlink`]
 - [`{integer}::saturating_div`]
 - [`Option::unwrap_unchecked`]
-- [`NonZero{unsigned}::is_power_of_two`]
+- [`Result::unwrap_unchecked`]
+- [`Result::unwrap_err_unchecked`]
+- [`File::options`]
 
 These APIs are now usable in const contexts:
 
@@ -53,10 +55,6 @@ These APIs are now usable in const contexts:
 - [`Duration::checked_mul`]
 - [`Duration::saturating_mul`]
 - [`Duration::checked_div`]
-- [`MaybeUninit::as_ptr`]
-- [`MaybeUninit::as_mut_ptr`]
-- [`MaybeUninit::assume_init`]
-- [`MaybeUninit::assume_init_ref`]
 
 Cargo
 -----
@@ -97,19 +95,14 @@ and related tools.
 [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/
-[88300]: https://github.com/rust-lang/rust/pull/88300/
 [88447]: https://github.com/rust-lang/rust/pull/88447/
 [88601]: https://github.com/rust-lang/rust/pull/88601/
-[88624]: https://github.com/rust-lang/rust/pull/88624/
 [89062]: https://github.com/rust-lang/rust/pull/89062/
 [89174]: https://github.com/rust-lang/rust/pull/89174/
-[89542]: https://github.com/rust-lang/rust/pull/89542/
 [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/
-[89677]: https://github.com/rust-lang/rust/pull/89677/
-[89951]: https://github.com/rust-lang/rust/pull/89951/
 [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/
@@ -125,44 +118,19 @@ and related tools.
 [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/
-[90896]: https://github.com/rust-lang/rust/pull/90896/
 [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/
-[91301]: https://github.com/rust-lang/rust/pull/91301/
 [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
-[`NonZero{unsigned}::is_power_of_two`]: https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html#method.is_power_of_two
-[`unix::process::ExitStatusExt::core_dumped`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.core_dumped
-[`unix::process::ExitStatusExt::stopped_signal`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.stopped_signal
-[`unix::process::ExitStatusExt::continued`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.continued
-[`unix::process::ExitStatusExt::into_raw`]: https://doc.rust-lang.org/stable/std/os/unix/process/trait.ExitStatusExt.html#tymethod.into_raw
+[`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
-[`Duration::checked_add`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_add
-[`Duration::saturating_add`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_add
-[`Duration::checked_sub`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_sub
-[`Duration::saturating_sub`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_sub
-[`Duration::checked_mul`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_mul
-[`Duration::saturating_mul`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.saturating_mul
-[`Duration::checked_div`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.checked_div
-[`Duration::as_secs_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.as_secs_f64
-[`Duration::as_secs_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.as_secs_f32
-[`Duration::from_secs_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_secs_f64
-[`Duration::from_secs_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_secs_f32
-[`Duration::mul_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.mul_f64
-[`Duration::mul_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.mul_f32
-[`Duration::div_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_f64
-[`Duration::div_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_f32
-[`Duration::div_duration_f64`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f64
-[`Duration::div_duration_f32`]: https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.div_duration_f32
-[`MaybeUninit::as_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_ptr
-[`MaybeUninit::as_mut_ptr`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.as_mut_ptr
-[`MaybeUninit::assume_init`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init
-[`MaybeUninit::assume_init_ref`]: https://doc.rust-lang.org/stable/std/mem/union.MaybeUninit.html#method.assume_init_ref
 
 Version 1.57.0 (2021-12-02)
 ==========================
@@ -244,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/
@@ -400,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
@@ -423,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
@@ -439,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
@@ -569,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
@@ -591,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
@@ -695,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
@@ -897,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
@@ -1228,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
@@ -1542,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
@@ -1789,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/
@@ -1805,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/
@@ -1816,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
@@ -2584,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
 --------
@@ -2658,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/
@@ -2794,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
@@ -2927,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/
@@ -3162,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
@@ -3661,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/
@@ -4061,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/
@@ -4183,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/
@@ -4191,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/
@@ -4299,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/
@@ -4444,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/
@@ -4625,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/
@@ -4835,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
@@ -4852,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
@@ -5102,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
@@ -5114,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
@@ -5285,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
@@ -5515,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
 -------------------
@@ -5559,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
@@ -5852,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]
@@ -5887,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
@@ -6183,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/
 
 
@@ -6254,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.
@@ -6320,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
@@ -6328,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
@@ -6378,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)
@@ -6593,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
@@ -6782,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
@@ -7010,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
@@ -7067,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
@@ -7099,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
@@ -8017,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,
@@ -8067,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
@@ -8990,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
@@ -9035,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
@@ -9043,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
@@ -9316,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
@@ -9346,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)
 ========================
@@ -9399,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
@@ -9407,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].
@@ -9426,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
@@ -9474,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
@@ -9482,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
@@ -9500,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 a2d32cdc00fb001b2c03077f9d99ccdf78bd4935..565488ab6a52d20cefd6b5b569aae45f1432427c 100644 (file)
@@ -224,7 +224,7 @@ pub enum AngleBracketedArg {
     /// Argument for a generic parameter.
     Arg(GenericArg),
     /// Constraint for an associated item.
-    Constraint(AssocTyConstraint),
+    Constraint(AssocConstraint),
 }
 
 impl AngleBracketedArg {
@@ -1266,7 +1266,7 @@ pub fn precedence(&self) -> ExprPrecedence {
             ExprKind::Break(..) => ExprPrecedence::Break,
             ExprKind::Continue(..) => ExprPrecedence::Continue,
             ExprKind::Ret(..) => ExprPrecedence::Ret,
-            ExprKind::InlineAsm(..) | ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
+            ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
             ExprKind::MacCall(..) => ExprPrecedence::Mac,
             ExprKind::Struct(..) => ExprPrecedence::Struct,
             ExprKind::Repeat(..) => ExprPrecedence::Repeat,
@@ -1423,8 +1423,6 @@ pub enum ExprKind {
 
     /// Output of the `asm!()` macro.
     InlineAsm(P<InlineAsm>),
-    /// Output of the `llvm_asm!()` macro.
-    LlvmInlineAsm(P<LlvmInlineAsm>),
 
     /// A macro invocation; pre-expansion.
     MacCall(MacCall),
@@ -1845,19 +1843,38 @@ pub fn name(&self) -> Symbol {
 /// A constraint on an associated type (e.g., `A = Bar` in `Foo<A = Bar>` or
 /// `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`).
 #[derive(Clone, Encodable, Decodable, Debug)]
-pub struct AssocTyConstraint {
+pub struct AssocConstraint {
     pub id: NodeId,
     pub ident: Ident,
     pub gen_args: Option<GenericArgs>,
-    pub kind: AssocTyConstraintKind,
+    pub kind: AssocConstraintKind,
     pub span: Span,
 }
 
-/// The kinds of an `AssocTyConstraint`.
+/// The kinds of an `AssocConstraint`.
 #[derive(Clone, Encodable, Decodable, Debug)]
-pub enum AssocTyConstraintKind {
-    /// E.g., `A = Bar` in `Foo<A = Bar>`.
-    Equality { ty: P<Ty> },
+pub enum Term {
+    Ty(P<Ty>),
+    Const(AnonConst),
+}
+
+impl From<P<Ty>> for Term {
+    fn from(v: P<Ty>) -> Self {
+        Term::Ty(v)
+    }
+}
+
+impl From<AnonConst> for Term {
+    fn from(v: AnonConst) -> Self {
+        Term::Const(v)
+    }
+}
+
+/// The kinds of an `AssocConstraint`.
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub enum AssocConstraintKind {
+    /// E.g., `A = Bar`, `A = 3` in `Foo<A = Bar>` where A is an associated type.
+    Equality { term: Term },
     /// E.g. `A: TraitA + TraitB` in `Foo<A: TraitA + TraitB>`.
     Bound { bounds: GenericBounds },
 }
@@ -1989,7 +2006,7 @@ pub struct InlineAsmOptions: u16 {
     }
 }
 
-#[derive(Clone, PartialEq, PartialOrd, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
+#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
 pub enum InlineAsmTemplatePiece {
     String(String),
     Placeholder { operand_idx: usize, modifier: Option<char>, span: Span },
@@ -2076,41 +2093,6 @@ pub struct InlineAsm {
     pub line_spans: Vec<Span>,
 }
 
-/// Inline assembly dialect.
-///
-/// E.g., `"intel"` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
-#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Hash, HashStable_Generic)]
-pub enum LlvmAsmDialect {
-    Att,
-    Intel,
-}
-
-/// LLVM-style inline assembly.
-///
-/// E.g., `"={eax}"(result)` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
-#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct LlvmInlineAsmOutput {
-    pub constraint: Symbol,
-    pub expr: P<Expr>,
-    pub is_rw: bool,
-    pub is_indirect: bool,
-}
-
-/// LLVM-style inline assembly.
-///
-/// E.g., `llvm_asm!("NOP");`.
-#[derive(Clone, Encodable, Decodable, Debug)]
-pub struct LlvmInlineAsm {
-    pub asm: Symbol,
-    pub asm_str_style: StrStyle,
-    pub outputs: Vec<LlvmInlineAsmOutput>,
-    pub inputs: Vec<(Symbol, P<Expr>)>,
-    pub clobbers: Vec<Symbol>,
-    pub volatile: bool,
-    pub alignstack: bool,
-    pub dialect: LlvmAsmDialect,
-}
-
 /// A parameter in a function header.
 ///
 /// E.g., `bar: usize` as in `fn foo(bar: usize)`.
@@ -2229,7 +2211,7 @@ pub enum IsAuto {
     No,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Debug)]
 #[derive(HashStable_Generic)]
 pub enum Unsafe {
     Yes(Span),
index 9ef78aaf6673aaec316d006fa25ac37cf552fbc6..a81a227629539a06f52f55a639378b99cff9945d 100644 (file)
@@ -165,8 +165,8 @@ fn visit_lifetime(&mut self, l: &mut Lifetime) {
         noop_visit_lifetime(l, self);
     }
 
-    fn visit_ty_constraint(&mut self, t: &mut AssocTyConstraint) {
-        noop_visit_ty_constraint(t, self);
+    fn visit_constraint(&mut self, t: &mut AssocConstraint) {
+        noop_visit_constraint(t, self);
     }
 
     fn visit_foreign_mod(&mut self, nm: &mut ForeignMod) {
@@ -430,8 +430,8 @@ pub fn noop_visit_use_tree<T: MutVisitor>(use_tree: &mut UseTree, vis: &mut T) {
     smallvec![arm]
 }
 
-pub fn noop_visit_ty_constraint<T: MutVisitor>(
-    AssocTyConstraint { id, ident, gen_args, kind, span }: &mut AssocTyConstraint,
+pub fn noop_visit_constraint<T: MutVisitor>(
+    AssocConstraint { id, ident, gen_args, kind, span }: &mut AssocConstraint,
     vis: &mut T,
 ) {
     vis.visit_id(id);
@@ -440,12 +440,11 @@ pub fn noop_visit_ty_constraint<T: MutVisitor>(
         vis.visit_generic_args(gen_args);
     }
     match kind {
-        AssocTyConstraintKind::Equality { ref mut ty } => {
-            vis.visit_ty(ty);
-        }
-        AssocTyConstraintKind::Bound { ref mut bounds } => {
-            visit_bounds(bounds, vis);
-        }
+        AssocConstraintKind::Equality { ref mut term } => match term {
+            Term::Ty(ty) => vis.visit_ty(ty),
+            Term::Const(c) => vis.visit_anon_const(c),
+        },
+        AssocConstraintKind::Bound { ref mut bounds } => visit_bounds(bounds, vis),
     }
     vis.visit_span(span);
 }
@@ -555,7 +554,7 @@ pub fn noop_visit_angle_bracketed_parameter_data<T: MutVisitor>(
     let AngleBracketedArgs { args, span } = data;
     visit_vec(args, |arg| match arg {
         AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
-        AngleBracketedArg::Constraint(constraint) => vis.visit_ty_constraint(constraint),
+        AngleBracketedArg::Constraint(constraint) => vis.visit_constraint(constraint),
     });
     vis.visit_span(span);
 }
@@ -1350,23 +1349,6 @@ pub fn noop_visit_expr<T: MutVisitor>(
             visit_opt(expr, |expr| vis.visit_expr(expr));
         }
         ExprKind::InlineAsm(asm) => noop_visit_inline_asm(asm, vis),
-        ExprKind::LlvmInlineAsm(asm) => {
-            let LlvmInlineAsm {
-                asm: _,
-                asm_str_style: _,
-                outputs,
-                inputs,
-                clobbers: _,
-                volatile: _,
-                alignstack: _,
-                dialect: _,
-            } = asm.deref_mut();
-            for out in outputs {
-                let LlvmInlineAsmOutput { constraint: _, expr, is_rw: _, is_indirect: _ } = out;
-                vis.visit_expr(expr);
-            }
-            visit_vec(inputs, |(_c, expr)| vis.visit_expr(expr));
-        }
         ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
         ExprKind::Struct(se) => {
             let StructExpr { qself, path, fields, rest } = se.deref_mut();
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 6840f092da61ba8d7e678f11609c761fa26dcf1a..73e9297549cd4877de19f41d92d5cb5711a84bfb 100644 (file)
@@ -190,8 +190,8 @@ fn visit_generic_args(&mut self, path_span: Span, generic_args: &'ast GenericArg
     fn visit_generic_arg(&mut self, generic_arg: &'ast GenericArg) {
         walk_generic_arg(self, generic_arg)
     }
-    fn visit_assoc_ty_constraint(&mut self, constraint: &'ast AssocTyConstraint) {
-        walk_assoc_ty_constraint(self, constraint)
+    fn visit_assoc_constraint(&mut self, constraint: &'ast AssocConstraint) {
+        walk_assoc_constraint(self, constraint)
     }
     fn visit_attribute(&mut self, attr: &'ast Attribute) {
         walk_attribute(self, attr)
@@ -464,7 +464,7 @@ pub fn walk_generic_args<'a, V>(visitor: &mut V, _path_span: Span, generic_args:
             for arg in &data.args {
                 match arg {
                     AngleBracketedArg::Arg(a) => visitor.visit_generic_arg(a),
-                    AngleBracketedArg::Constraint(c) => visitor.visit_assoc_ty_constraint(c),
+                    AngleBracketedArg::Constraint(c) => visitor.visit_assoc_constraint(c),
                 }
             }
         }
@@ -486,19 +486,17 @@ pub fn walk_generic_arg<'a, V>(visitor: &mut V, generic_arg: &'a GenericArg)
     }
 }
 
-pub fn walk_assoc_ty_constraint<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    constraint: &'a AssocTyConstraint,
-) {
+pub fn walk_assoc_constraint<'a, V: Visitor<'a>>(visitor: &mut V, constraint: &'a AssocConstraint) {
     visitor.visit_ident(constraint.ident);
     if let Some(ref gen_args) = constraint.gen_args {
         visitor.visit_generic_args(gen_args.span(), gen_args);
     }
     match constraint.kind {
-        AssocTyConstraintKind::Equality { ref ty } => {
-            visitor.visit_ty(ty);
-        }
-        AssocTyConstraintKind::Bound { ref bounds } => {
+        AssocConstraintKind::Equality { ref term } => match term {
+            Term::Ty(ty) => visitor.visit_ty(ty),
+            Term::Const(c) => visitor.visit_anon_const(c),
+        },
+        AssocConstraintKind::Bound { ref bounds } => {
             walk_list!(visitor, visit_param_bound, bounds);
         }
     }
@@ -864,14 +862,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
         ExprKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
         ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
         ExprKind::InlineAsm(ref asm) => walk_inline_asm(visitor, asm),
-        ExprKind::LlvmInlineAsm(ref ia) => {
-            for &(_, ref input) in &ia.inputs {
-                visitor.visit_expr(input)
-            }
-            for output in &ia.outputs {
-                visitor.visit_expr(&output.expr)
-            }
-        }
         ExprKind::Yield(ref optional_expression) => {
             walk_list!(visitor, visit_expr, optional_expression);
         }
index 9c28f3c7f5899c36f5a0029102ba61e84cb31b87..89d411d4b36fe78a2f60e5bac14f7417e56bb5d3 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_session::parse::feature_err;
-use rustc_span::{sym, Span, Symbol};
+use rustc_span::{sym, Span};
 use rustc_target::asm;
 use std::collections::hash_map::Entry;
 use std::fmt::Write;
@@ -66,7 +66,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             for (abi_name, abi_span) in &asm.clobber_abis {
                 match asm::InlineAsmClobberAbi::parse(
                     asm_arch,
-                    |feature| self.sess.target_features.contains(&Symbol::intern(feature)),
+                    &self.sess.target_features,
                     &self.sess.target,
                     *abi_name,
                 ) {
@@ -134,7 +134,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
                             asm::InlineAsmReg::parse(
                                 asm_arch,
-                                |feature| sess.target_features.contains(&Symbol::intern(feature)),
+                                &sess.target_features,
                                 &sess.target,
                                 s,
                             )
index 75f384405bb2b5c434940ae89f634d5a6aea57d5..6c172d59f837b4f97690ea8582e11a13a91baee1 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> {
@@ -226,7 +226,6 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> {
                 ExprKind::InlineAsm(ref asm) => {
                     hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
                 }
-                ExprKind::LlvmInlineAsm(ref asm) => self.lower_expr_llvm_asm(asm),
                 ExprKind::Struct(ref se) => {
                     let rest = match &se.rest {
                         StructRest::Base(e) => Some(self.lower_expr(e)),
@@ -393,14 +392,20 @@ fn lower_expr_if(
     // If `cond` kind is `let`, returns `let`. Otherwise, wraps and returns `cond`
     // in a temporary block.
     fn manage_let_cond(&mut self, cond: &'hir hir::Expr<'hir>) -> &'hir hir::Expr<'hir> {
-        match cond.kind {
-            hir::ExprKind::Let(..) => cond,
-            _ => {
-                let span_block =
-                    self.mark_span_with_reason(DesugaringKind::CondTemporary, cond.span, None);
-                self.expr_drop_temps(span_block, cond, AttrVec::new())
+        fn has_let_expr<'hir>(expr: &'hir hir::Expr<'hir>) -> bool {
+            match expr.kind {
+                hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
+                hir::ExprKind::Let(..) => true,
+                _ => false,
             }
         }
+        if has_let_expr(cond) {
+            cond
+        } else {
+            let reason = DesugaringKind::CondTemporary;
+            let span_block = self.mark_span_with_reason(reason, cond.span, None);
+            self.expr_drop_temps(span_block, cond, AttrVec::new())
+        }
     }
 
     // We desugar: `'label: while $cond $body` into:
@@ -1204,11 +1209,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(
@@ -1284,38 +1291,6 @@ fn with_loop_condition_scope<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> T
         result
     }
 
-    fn lower_expr_llvm_asm(&mut self, asm: &LlvmInlineAsm) -> hir::ExprKind<'hir> {
-        let inner = hir::LlvmInlineAsmInner {
-            inputs: asm.inputs.iter().map(|&(c, _)| c).collect(),
-            outputs: asm
-                .outputs
-                .iter()
-                .map(|out| hir::LlvmInlineAsmOutput {
-                    constraint: out.constraint,
-                    is_rw: out.is_rw,
-                    is_indirect: out.is_indirect,
-                    span: self.lower_span(out.expr.span),
-                })
-                .collect(),
-            asm: asm.asm,
-            asm_str_style: asm.asm_str_style,
-            clobbers: asm.clobbers.clone(),
-            volatile: asm.volatile,
-            alignstack: asm.alignstack,
-            dialect: asm.dialect,
-        };
-        let hir_asm = hir::LlvmInlineAsm {
-            inner,
-            inputs_exprs: self.arena.alloc_from_iter(
-                asm.inputs.iter().map(|&(_, ref input)| self.lower_expr_mut(input)),
-            ),
-            outputs_exprs: self
-                .arena
-                .alloc_from_iter(asm.outputs.iter().map(|out| self.lower_expr_mut(&out.expr))),
-        };
-        hir::ExprKind::LlvmInlineAsm(self.arena.alloc(hir_asm))
-    }
-
     fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {
         hir::ExprField {
             hir_id: self.next_id(),
index 8a9dad2cdd7d86635425ed9853b012abe1003f37..62935a2b1f718753aab726119dd05670ba74ee5e 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::definitions;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::*;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_session::Session;
@@ -101,16 +101,10 @@ fn insert_nested(&mut self, item: LocalDefId) {
 }
 
 impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
-    type Map = !;
-
     /// Because we want to track parent items and so forth, enable
     /// deep walking so that we walk nested items in the context of
     /// their outer items.
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        panic!("`visit_nested_xxx` must be manually implemented in this visitor");
-    }
-
     fn visit_nested_item(&mut self, item: ItemId) {
         debug!("visit_nested_item: {:?}", item);
         self.insert_nested(item.def_id);
@@ -335,7 +329,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 35eb716949a13ccf38368ef890119a70e14a3854..47b610670555c9767da887ce5582a3c0b4fc6ded 100644 (file)
@@ -960,7 +960,7 @@ fn lower_token_stream(
     /// returns a `hir::TypeBinding` representing `Item`.
     fn lower_assoc_ty_constraint(
         &mut self,
-        constraint: &AssocTyConstraint,
+        constraint: &AssocConstraint,
         mut itctx: ImplTraitContext<'_, 'hir>,
     ) -> hir::TypeBinding<'hir> {
         debug!("lower_assoc_ty_constraint(constraint={:?}, itctx={:?})", constraint, itctx);
@@ -997,10 +997,14 @@ fn lower_assoc_ty_constraint(
         };
 
         let kind = match constraint.kind {
-            AssocTyConstraintKind::Equality { ref ty } => {
-                hir::TypeBindingKind::Equality { ty: self.lower_ty(ty, itctx) }
+            AssocConstraintKind::Equality { ref term } => {
+                let term = match term {
+                    Term::Ty(ref ty) => self.lower_ty(ty, itctx).into(),
+                    Term::Const(ref c) => self.lower_anon_const(c).into(),
+                };
+                hir::TypeBindingKind::Equality { term }
             }
-            AssocTyConstraintKind::Bound { ref bounds } => {
+            AssocConstraintKind::Bound { ref bounds } => {
                 let mut capturable_lifetimes;
                 let mut parent_def_id = self.current_hir_id_owner;
                 // Piggy-back on the `impl Trait` context to figure out the correct behavior.
@@ -1078,7 +1082,7 @@ fn lower_assoc_ty_constraint(
                             itctx,
                         );
 
-                        hir::TypeBindingKind::Equality { ty }
+                        hir::TypeBindingKind::Equality { term: ty.into() }
                     })
                 } else {
                     // Desugar `AssocTy: Bounds` into a type binding where the
@@ -2436,12 +2440,6 @@ struct ImplTraitLifetimeCollector<'r> {
     }
 
     impl<'r, 'v> intravisit::Visitor<'v> for ImplTraitLifetimeCollector<'r> {
-        type Map = intravisit::ErasedMap<'v>;
-
-        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-            intravisit::NestedVisitorMap::None
-        }
-
         fn visit_generic_args(&mut self, span: Span, parameters: &'v hir::GenericArgs<'v>) {
             // Don't collect elided lifetimes used inside of `Fn()` syntax.
             if parameters.parenthesized {
index 46928a1846540f13859f74c2f6df5ce4023dd67b..79262235cd9f250584e1556c7145a415eb2cf982 100644 (file)
@@ -420,7 +420,7 @@ fn lower_parenthesized_parameter_data(
         ty: &'hir hir::Ty<'hir>,
     ) -> hir::TypeBinding<'hir> {
         let ident = Ident::with_dummy_span(hir::FN_OUTPUT_NAME);
-        let kind = hir::TypeBindingKind::Equality { ty };
+        let kind = hir::TypeBindingKind::Equality { term: ty.into() };
         let args = arena_vec![self;];
         let bindings = arena_vec![self;];
         let gen_args = self.arena.alloc(hir::GenericArgs {
index 6237a01f6943539fa7e1a3cadc725d6447e4af83..eb7c75cac0520ab0018a2acff5f19adee5ce9253 100644 (file)
@@ -138,10 +138,10 @@ fn with_impl_trait(&mut self, outer: Option<Span>, f: impl FnOnce(&mut Self)) {
         self.outer_impl_trait = old;
     }
 
-    fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocTyConstraint) {
+    fn visit_assoc_constraint_from_generic_args(&mut self, constraint: &'a AssocConstraint) {
         match constraint.kind {
-            AssocTyConstraintKind::Equality { .. } => {}
-            AssocTyConstraintKind::Bound { .. } => {
+            AssocConstraintKind::Equality { .. } => {}
+            AssocConstraintKind::Bound { .. } => {
                 if self.is_assoc_ty_bound_banned {
                     self.err_handler().span_err(
                         constraint.span,
@@ -150,7 +150,7 @@ fn visit_assoc_ty_constraint_from_generic_args(&mut self, constraint: &'a AssocT
                 }
             }
         }
-        self.visit_assoc_ty_constraint(constraint);
+        self.visit_assoc_constraint(constraint);
     }
 
     // Mirrors `visit::walk_ty`, but tracks relevant state.
@@ -960,15 +960,6 @@ fn visit_expr(&mut self, expr: &'a Expr) {
                 return;
             }
             ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
-            ExprKind::LlvmInlineAsm(..) if !this.session.target.allow_asm => {
-                struct_span_err!(
-                    this.session,
-                    expr.span,
-                    E0472,
-                    "llvm_asm! is unsupported on this target"
-                )
-                .emit();
-            }
             ExprKind::Match(expr, arms) => {
                 this.visit_expr(expr);
                 for arm in arms {
@@ -1286,7 +1277,7 @@ fn visit_generic_args(&mut self, _: Span, generic_args: &'a GenericArgs) {
                         // are allowed to contain nested `impl Trait`.
                         AngleBracketedArg::Constraint(constraint) => {
                             self.with_impl_trait(None, |this| {
-                                this.visit_assoc_ty_constraint_from_generic_args(constraint);
+                                this.visit_assoc_constraint_from_generic_args(constraint);
                             });
                         }
                     }
@@ -1595,12 +1586,12 @@ fn deny_equality_constraints(
                                     let len = assoc_path.segments.len() - 1;
                                     let gen_args = args.as_ref().map(|p| (**p).clone());
                                     // Build `<Bar = RhsTy>`.
-                                    let arg = AngleBracketedArg::Constraint(AssocTyConstraint {
+                                    let arg = AngleBracketedArg::Constraint(AssocConstraint {
                                         id: rustc_ast::node_id::DUMMY_NODE_ID,
                                         ident: *ident,
                                         gen_args,
-                                        kind: AssocTyConstraintKind::Equality {
-                                            ty: predicate.rhs_ty.clone(),
+                                        kind: AssocConstraintKind::Equality {
+                                            term: predicate.rhs_ty.clone().into(),
                                         },
                                         span: ident.span,
                                     });
index 85e35c942b903119495a6d04d5768d57ef1c0cf7..a6ecfa4520608a42cf1425844db1171b84313733 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_ast as ast;
 use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
-use rustc_ast::{AssocTyConstraint, AssocTyConstraintKind, NodeId};
+use rustc_ast::{AssocConstraint, AssocConstraintKind, NodeId};
 use rustc_ast::{PatKind, RangeEnd, VariantData};
 use rustc_errors::struct_span_err;
 use rustc_feature::{AttributeGate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
@@ -622,8 +622,8 @@ fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
         visit::walk_fn(self, fn_kind, span)
     }
 
-    fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
-        if let AssocTyConstraintKind::Bound { .. } = constraint.kind {
+    fn visit_assoc_constraint(&mut self, constraint: &'a AssocConstraint) {
+        if let AssocConstraintKind::Bound { .. } = constraint.kind {
             gate_feature_post!(
                 &self,
                 associated_type_bounds,
@@ -631,7 +631,7 @@ fn visit_assoc_ty_constraint(&mut self, constraint: &'a AssocTyConstraint) {
                 "associated type bounds are unstable"
             )
         }
-        visit::walk_assoc_ty_constraint(self, constraint)
+        visit::walk_assoc_constraint(self, constraint)
     }
 
     fn visit_assoc_item(&mut self, i: &'a ast::AssocItem, ctxt: AssocCtxt) {
@@ -707,11 +707,7 @@ macro_rules! gate_all {
         "`if let` guards are experimental",
         "you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`"
     );
-    gate_all!(
-        let_chains,
-        "`let` expressions in this position are experimental",
-        "you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`"
-    );
+    gate_all!(let_chains, "`let` expressions in this position are unstable");
     gate_all!(
         async_closure,
         "async closures are unstable",
@@ -724,6 +720,7 @@ macro_rules! gate_all {
     gate_all!(half_open_range_patterns, "half-open range patterns are unstable");
     gate_all!(inline_const, "inline-const is experimental");
     gate_all!(inline_const_pat, "inline-const in pattern position is experimental");
+    gate_all!(associated_const_equality, "associated const equality is incomplete");
 
     // All uses of `gate_all!` below this point were added in #65742,
     // and subsequently disabled (with the non-early gating readded).
index 3980e6da68250497ade236d24a6354c7fb834f5d..a4a48cc8e8a7f1d279cadb2dc2daf4953865134f 100644 (file)
@@ -126,9 +126,9 @@ fn visit_generic_args(&mut self, path_span: Span, generic_args: &GenericArgs) {
         self.count += 1;
         walk_generic_args(self, path_span, generic_args)
     }
-    fn visit_assoc_ty_constraint(&mut self, constraint: &AssocTyConstraint) {
+    fn visit_assoc_constraint(&mut self, constraint: &AssocConstraint) {
         self.count += 1;
-        walk_assoc_ty_constraint(self, constraint)
+        walk_assoc_constraint(self, constraint)
     }
     fn visit_attribute(&mut self, _attr: &Attribute) {
         self.count += 1;
index 29f2be4cf46486d4b46497edf6d0b715bad01d71..5ad8714e9fec999dd71591a64daa47c2652ddae1 100644 (file)
@@ -7,6 +7,5 @@ edition = "2021"
 doctest = false
 
 [dependencies]
-tracing = "0.1"
 rustc_span = { path = "../rustc_span" }
 rustc_ast = { path = "../rustc_ast" }
index ea298d28e72c6a983bc7409067d6273c635fbfca..bdd70148d85a0d483f638aa7184a0a9c1530aaf4 100644 (file)
 //! methods called `Printer::scan_*`, and the 'PRINT' process is the
 //! method called `Printer::print`.
 
+mod ring;
+
+use ring::RingBuffer;
 use std::borrow::Cow;
 use std::collections::VecDeque;
 use std::fmt;
-use tracing::debug;
 
 /// How to break. Described in more detail in the module docs.
 #[derive(Clone, Copy, PartialEq)]
@@ -165,14 +167,9 @@ pub enum Token {
     Break(BreakToken),
     Begin(BeginToken),
     End,
-    Eof,
 }
 
 impl Token {
-    crate fn is_eof(&self) -> bool {
-        matches!(self, Token::Eof)
-    }
-
     pub fn is_hardbreak_tok(&self) -> bool {
         matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY }))
     }
@@ -185,29 +182,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
             Token::Break(_) => f.write_str("BREAK"),
             Token::Begin(_) => f.write_str("BEGIN"),
             Token::End => f.write_str("END"),
-            Token::Eof => f.write_str("EOF"),
         }
     }
 }
 
-fn buf_str(buf: &[BufEntry], left: usize, right: usize, lim: usize) -> String {
-    let n = buf.len();
-    let mut i = left;
-    let mut l = lim;
-    let mut s = String::from("[");
-    while i != right && l != 0 {
-        l -= 1;
-        if i != left {
-            s.push_str(", ");
-        }
-        s.push_str(&format!("{}={}", buf[i].size, &buf[i].token));
-        i += 1;
-        i %= n;
-    }
-    s.push(']');
-    s
-}
-
 #[derive(Copy, Clone)]
 enum PrintStackBreak {
     Fits,
@@ -222,42 +200,14 @@ struct PrintStackElem {
 
 const SIZE_INFINITY: isize = 0xffff;
 
-pub fn mk_printer() -> Printer {
-    let linewidth = 78;
-    // Yes 55, it makes the ring buffers big enough to never fall behind.
-    let n: usize = 55 * linewidth;
-    debug!("mk_printer {}", linewidth);
-    Printer {
-        out: String::new(),
-        buf_max_len: n,
-        margin: linewidth as isize,
-        space: linewidth as isize,
-        left: 0,
-        right: 0,
-        // Initialize a single entry; advance_right() will extend it on demand
-        // up to `buf_max_len` elements.
-        buf: vec![BufEntry::default()],
-        left_total: 0,
-        right_total: 0,
-        scan_stack: VecDeque::new(),
-        print_stack: Vec::new(),
-        pending_indentation: 0,
-    }
-}
-
 pub struct Printer {
     out: String,
-    buf_max_len: usize,
     /// Width of lines we're constrained to
     margin: isize,
     /// Number of spaces left on line
     space: isize,
-    /// Index of left side of input stream
-    left: usize,
-    /// Index of right side of input stream
-    right: usize,
     /// Ring-buffer of tokens and calculated sizes
-    buf: Vec<BufEntry>,
+    buf: RingBuffer<BufEntry>,
     /// Running size of stream "...left"
     left_total: isize,
     /// Running size of stream "...right"
@@ -273,6 +223,9 @@ pub struct Printer {
     print_stack: Vec<PrintStackElem>,
     /// Buffered indentation to avoid writing trailing whitespace
     pending_indentation: isize,
+    /// The token most recently popped from the left boundary of the
+    /// ring-buffer for printing
+    last_printed: Option<Token>,
 }
 
 #[derive(Clone)]
@@ -281,20 +234,34 @@ struct BufEntry {
     size: isize,
 }
 
-impl Default for BufEntry {
-    fn default() -> Self {
-        BufEntry { token: Token::Eof, size: 0 }
+impl Printer {
+    pub fn new() -> Self {
+        let linewidth = 78;
+        Printer {
+            out: String::new(),
+            margin: linewidth as isize,
+            space: linewidth as isize,
+            buf: RingBuffer::new(),
+            left_total: 0,
+            right_total: 0,
+            scan_stack: VecDeque::new(),
+            print_stack: Vec::new(),
+            pending_indentation: 0,
+            last_printed: None,
+        }
     }
-}
 
-impl Printer {
-    pub fn last_token(&self) -> Token {
-        self.buf[self.right].token.clone()
+    pub fn last_token(&self) -> Option<&Token> {
+        self.last_token_still_buffered().or_else(|| self.last_printed.as_ref())
+    }
+
+    pub fn last_token_still_buffered(&self) -> Option<&Token> {
+        self.buf.last().map(|last| &last.token)
     }
 
     /// Be very careful with this!
-    pub fn replace_last_token(&mut self, t: Token) {
-        self.buf[self.right].token = t;
+    pub fn replace_last_token_still_buffered(&mut self, t: Token) {
+        self.buf.last_mut().unwrap().token = t;
     }
 
     fn scan_eof(&mut self) {
@@ -308,23 +275,18 @@ fn scan_begin(&mut self, b: BeginToken) {
         if self.scan_stack.is_empty() {
             self.left_total = 1;
             self.right_total = 1;
-            self.left = 0;
-            self.right = 0;
-        } else {
-            self.advance_right();
+            self.buf.clear();
         }
-        debug!("pp Begin({})/buffer Vec<{},{}>", b.offset, self.left, self.right);
-        self.scan_push(BufEntry { token: Token::Begin(b), size: -self.right_total });
+        let right = self.buf.push(BufEntry { token: Token::Begin(b), size: -self.right_total });
+        self.scan_stack.push_front(right);
     }
 
     fn scan_end(&mut self) {
         if self.scan_stack.is_empty() {
-            debug!("pp End/print Vec<{},{}>", self.left, self.right);
             self.print_end();
         } else {
-            debug!("pp End/buffer Vec<{},{}>", self.left, self.right);
-            self.advance_right();
-            self.scan_push(BufEntry { token: Token::End, size: -1 });
+            let right = self.buf.push(BufEntry { token: Token::End, size: -1 });
+            self.scan_stack.push_front(right);
         }
     }
 
@@ -332,92 +294,44 @@ fn scan_break(&mut self, b: BreakToken) {
         if self.scan_stack.is_empty() {
             self.left_total = 1;
             self.right_total = 1;
-            self.left = 0;
-            self.right = 0;
+            self.buf.clear();
         } else {
-            self.advance_right();
+            self.check_stack(0);
         }
-        debug!("pp Break({})/buffer Vec<{},{}>", b.offset, self.left, self.right);
-        self.check_stack(0);
-        self.scan_push(BufEntry { token: Token::Break(b), size: -self.right_total });
+        let right = self.buf.push(BufEntry { token: Token::Break(b), size: -self.right_total });
+        self.scan_stack.push_front(right);
         self.right_total += b.blank_space;
     }
 
     fn scan_string(&mut self, s: Cow<'static, str>) {
         if self.scan_stack.is_empty() {
-            debug!("pp String('{}')/print Vec<{},{}>", s, self.left, self.right);
-            self.print_string(s);
+            self.print_string(&s);
         } else {
-            debug!("pp String('{}')/buffer Vec<{},{}>", s, self.left, self.right);
-            self.advance_right();
             let len = s.len() as isize;
-            self.buf[self.right] = BufEntry { token: Token::String(s), size: len };
+            self.buf.push(BufEntry { token: Token::String(s), size: len });
             self.right_total += len;
             self.check_stream();
         }
     }
 
     fn check_stream(&mut self) {
-        debug!(
-            "check_stream Vec<{}, {}> with left_total={}, right_total={}",
-            self.left, self.right, self.left_total, self.right_total
-        );
-        if self.right_total - self.left_total > self.space {
-            debug!(
-                "scan window is {}, longer than space on line ({})",
-                self.right_total - self.left_total,
-                self.space
-            );
-            if Some(&self.left) == self.scan_stack.back() {
-                debug!("setting {} to infinity and popping", self.left);
-                let scanned = self.scan_pop_bottom();
-                self.buf[scanned].size = SIZE_INFINITY;
+        while self.right_total - self.left_total > self.space {
+            if *self.scan_stack.back().unwrap() == self.buf.index_of_first() {
+                self.scan_stack.pop_back().unwrap();
+                self.buf.first_mut().unwrap().size = SIZE_INFINITY;
             }
             self.advance_left();
-            if self.left != self.right {
-                self.check_stream();
+            if self.buf.is_empty() {
+                break;
             }
         }
     }
 
-    fn scan_push(&mut self, entry: BufEntry) {
-        debug!("scan_push {}", self.right);
-        self.buf[self.right] = entry;
-        self.scan_stack.push_front(self.right);
-    }
-
-    fn scan_pop(&mut self) -> usize {
-        self.scan_stack.pop_front().unwrap()
-    }
-
-    fn scan_top(&self) -> usize {
-        *self.scan_stack.front().unwrap()
-    }
-
-    fn scan_pop_bottom(&mut self) -> usize {
-        self.scan_stack.pop_back().unwrap()
-    }
-
-    fn advance_right(&mut self) {
-        self.right += 1;
-        self.right %= self.buf_max_len;
-        // Extend the buf if necessary.
-        if self.right == self.buf.len() {
-            self.buf.push(BufEntry::default());
-        }
-        assert_ne!(self.right, self.left);
-    }
-
     fn advance_left(&mut self) {
-        debug!(
-            "advance_left Vec<{},{}>, sizeof({})={}",
-            self.left, self.right, self.left, self.buf[self.left].size
-        );
-
-        let mut left_size = self.buf[self.left].size;
+        let mut left_size = self.buf.first().unwrap().size;
 
         while left_size >= 0 {
-            let left = self.buf[self.left].token.clone();
+            let left = self.buf.first().unwrap().token.clone();
 
             let len = match left {
                 Token::Break(b) => b.blank_space,
@@ -433,39 +347,38 @@ fn advance_left(&mut self) {
 
             self.left_total += len;
 
-            if self.left == self.right {
+            self.buf.advance_left();
+            if self.buf.is_empty() {
                 break;
             }
 
-            self.left += 1;
-            self.left %= self.buf_max_len;
-
-            left_size = self.buf[self.left].size;
+            left_size = self.buf.first().unwrap().size;
         }
     }
 
-    fn check_stack(&mut self, k: usize) {
-        if !self.scan_stack.is_empty() {
-            let x = self.scan_top();
-            match self.buf[x].token {
+    fn check_stack(&mut self, mut k: usize) {
+        while let Some(&x) = self.scan_stack.front() {
+            let mut entry = &mut self.buf[x];
+            match entry.token {
                 Token::Begin(_) => {
-                    if k > 0 {
-                        self.scan_pop();
-                        self.buf[x].size += self.right_total;
-                        self.check_stack(k - 1);
+                    if k == 0 {
+                        break;
                     }
+                    self.scan_stack.pop_front().unwrap();
+                    entry.size += self.right_total;
+                    k -= 1;
                 }
                 Token::End => {
                     // paper says + not =, but that makes no sense.
-                    self.scan_pop();
-                    self.buf[x].size = 1;
-                    self.check_stack(k + 1);
+                    self.scan_stack.pop_front().unwrap();
+                    entry.size = 1;
+                    k += 1;
                 }
                 _ => {
-                    self.scan_pop();
-                    self.buf[x].size += self.right_total;
-                    if k > 0 {
-                        self.check_stack(k);
+                    self.scan_stack.pop_front().unwrap();
+                    entry.size += self.right_total;
+                    if k == 0 {
+                        break;
                     }
                 }
             }
@@ -473,14 +386,12 @@ fn check_stack(&mut self, k: usize) {
     }
 
     fn print_newline(&mut self, amount: isize) {
-        debug!("NEWLINE {}", amount);
         self.out.push('\n');
         self.pending_indentation = 0;
         self.indent(amount);
     }
 
     fn indent(&mut self, amount: isize) {
-        debug!("INDENT {}", amount);
         self.pending_indentation += amount;
     }
 
@@ -493,17 +404,14 @@ fn get_top(&self) -> PrintStackElem {
     fn print_begin(&mut self, b: BeginToken, l: isize) {
         if l > self.space {
             let col = self.margin - self.space + b.offset;
-            debug!("print Begin -> push broken block at col {}", col);
             self.print_stack
                 .push(PrintStackElem { offset: col, pbreak: PrintStackBreak::Broken(b.breaks) });
         } else {
-            debug!("print Begin -> push fitting block");
             self.print_stack.push(PrintStackElem { offset: 0, pbreak: PrintStackBreak::Fits });
         }
     }
 
     fn print_end(&mut self) {
-        debug!("print End -> pop End");
         self.print_stack.pop().unwrap();
     }
 
@@ -511,22 +419,18 @@ fn print_break(&mut self, b: BreakToken, l: isize) {
         let top = self.get_top();
         match top.pbreak {
             PrintStackBreak::Fits => {
-                debug!("print Break({}) in fitting block", b.blank_space);
                 self.space -= b.blank_space;
                 self.indent(b.blank_space);
             }
             PrintStackBreak::Broken(Breaks::Consistent) => {
-                debug!("print Break({}+{}) in consistent block", top.offset, b.offset);
                 self.print_newline(top.offset + b.offset);
                 self.space = self.margin - (top.offset + b.offset);
             }
             PrintStackBreak::Broken(Breaks::Inconsistent) => {
                 if l > self.space {
-                    debug!("print Break({}+{}) w/ newline in inconsistent", top.offset, b.offset);
                     self.print_newline(top.offset + b.offset);
                     self.space = self.margin - (top.offset + b.offset);
                 } else {
-                    debug!("print Break({}) w/o newline in inconsistent", b.blank_space);
                     self.indent(b.blank_space);
                     self.space -= b.blank_space;
                 }
@@ -534,9 +438,8 @@ fn print_break(&mut self, b: BreakToken, l: isize) {
         }
     }
 
-    fn print_string(&mut self, s: Cow<'static, str>) {
+    fn print_string(&mut self, s: &str) {
         let len = s.len() as isize;
-        debug!("print String({})", s);
         // assert!(len <= space);
         self.space -= len;
 
@@ -549,23 +452,21 @@ fn print_string(&mut self, s: Cow<'static, str>) {
         self.out.reserve(self.pending_indentation as usize);
         self.out.extend(std::iter::repeat(' ').take(self.pending_indentation as usize));
         self.pending_indentation = 0;
-        self.out.push_str(&s);
+        self.out.push_str(s);
     }
 
     fn print(&mut self, token: Token, l: isize) {
-        debug!("print {} {} (remaining line space={})", token, l, self.space);
-        debug!("{}", buf_str(&self.buf, self.left, self.right, 6));
-        match token {
-            Token::Begin(b) => self.print_begin(b, l),
+        match &token {
+            Token::Begin(b) => self.print_begin(*b, l),
             Token::End => self.print_end(),
-            Token::Break(b) => self.print_break(b, l),
+            Token::Break(b) => self.print_break(*b, l),
             Token::String(s) => {
                 let len = s.len() as isize;
                 assert_eq!(len, l);
                 self.print_string(s);
             }
-            Token::Eof => panic!(), // Eof should never get here.
         }
+        self.last_printed = Some(token);
     }
 
     // Convenience functions to talk to the printer.
@@ -620,7 +521,10 @@ pub fn hardbreak(&mut self) {
     }
 
     pub fn is_beginning_of_line(&self) -> bool {
-        self.last_token().is_eof() || self.last_token().is_hardbreak_tok()
+        match self.last_token() {
+            Some(last_token) => last_token.is_hardbreak_tok(),
+            None => true,
+        }
     }
 
     pub fn hardbreak_tok_offset(off: isize) -> Token {
diff --git a/compiler/rustc_ast_pretty/src/pp/ring.rs b/compiler/rustc_ast_pretty/src/pp/ring.rs
new file mode 100644 (file)
index 0000000..d20142e
--- /dev/null
@@ -0,0 +1,76 @@
+use std::collections::VecDeque;
+use std::ops::{Index, IndexMut};
+
+/// A view onto a finite range of an infinitely long sequence of T.
+///
+/// The Ts are indexed 0..infinity. A RingBuffer begins as a view of elements
+/// 0..0 (i.e. nothing). The user of the RingBuffer advances its left and right
+/// position independently, although only in the positive direction, and only
+/// with left <= right at all times.
+///
+/// Holding a RingBuffer whose view is elements left..right gives the ability to
+/// use Index and IndexMut to access elements i in the infinitely long queue for
+/// which left <= i < right.
+pub struct RingBuffer<T> {
+    data: VecDeque<T>,
+    // Abstract index of data[0] in the infinitely sized queue.
+    offset: usize,
+}
+
+impl<T> RingBuffer<T> {
+    pub fn new() -> Self {
+        RingBuffer { data: VecDeque::new(), offset: 0 }
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.data.is_empty()
+    }
+
+    pub fn push(&mut self, value: T) -> usize {
+        let index = self.offset + self.data.len();
+        self.data.push_back(value);
+        index
+    }
+
+    pub fn advance_left(&mut self) {
+        self.data.pop_front().unwrap();
+        self.offset += 1;
+    }
+
+    pub fn clear(&mut self) {
+        self.data.clear();
+    }
+
+    pub fn index_of_first(&self) -> usize {
+        self.offset
+    }
+
+    pub fn first(&self) -> Option<&T> {
+        self.data.front()
+    }
+
+    pub fn first_mut(&mut self) -> Option<&mut T> {
+        self.data.front_mut()
+    }
+
+    pub fn last(&self) -> Option<&T> {
+        self.data.back()
+    }
+
+    pub fn last_mut(&mut self) -> Option<&mut T> {
+        self.data.back_mut()
+    }
+}
+
+impl<T> Index<usize> for RingBuffer<T> {
+    type Output = T;
+    fn index(&self, index: usize) -> &Self::Output {
+        &self.data[index.checked_sub(self.offset).unwrap()]
+    }
+}
+
+impl<T> IndexMut<usize> for RingBuffer<T> {
+    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
+        &mut self.data[index.checked_sub(self.offset).unwrap()]
+    }
+}
index fa9a20f2e03584192cd6ac3dfdd55bcbf93bebf1..1cbc3162d432645a8bb9260fd4c280bc2d62222c 100644 (file)
@@ -1,15 +1,18 @@
+mod expr;
+mod item;
+
 use crate::pp::Breaks::{Consistent, Inconsistent};
 use crate::pp::{self, Breaks};
 
-use rustc_ast::attr;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::util::classify;
 use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
-use rustc_ast::util::parser::{self, AssocOp, Fixity};
+use rustc_ast::util::parser;
 use rustc_ast::{self as ast, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
-use rustc_ast::{GenericArg, MacArgs, ModKind};
+use rustc_ast::{attr, Term};
+use rustc_ast::{GenericArg, MacArgs};
 use rustc_ast::{GenericBound, SelfKind, TraitBoundModifier};
 use rustc_ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@@ -103,7 +106,7 @@ pub fn print_crate<'a>(
     edition: Edition,
 ) -> String {
     let mut s =
-        State { s: pp::mk_printer(), comments: Some(Comments::new(sm, filename, input)), ann };
+        State { s: pp::Printer::new(), comments: Some(Comments::new(sm, filename, input)), ann };
 
     if is_expanded && !krate.attrs.iter().any(|attr| attr.has_name(sym::no_core)) {
         // We need to print `#![no_std]` (and its feature gate) so that
@@ -210,10 +213,6 @@ pub fn literal_to_string(lit: token::Lit) -> String {
     out
 }
 
-fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
-    format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
-}
-
 impl std::ops::Deref for State<'_> {
     type Target = pp::Printer;
     fn deref(&self) -> &Self::Target {
@@ -329,9 +328,9 @@ fn print_comment(&mut self, cmnt: &Comment) {
             CommentStyle::BlankLine => {
                 // We need to do at least one, possibly two hardbreaks.
                 let twice = match self.last_token() {
-                    pp::Token::String(s) => ";" == s,
-                    pp::Token::Begin(_) => true,
-                    pp::Token::End => true,
+                    Some(pp::Token::String(s)) => ";" == s,
+                    Some(pp::Token::Begin(_)) => true,
+                    Some(pp::Token::End) => true,
                     _ => false,
                 };
                 if twice {
@@ -687,11 +686,15 @@ fn bclose(&mut self, span: rustc_span::Span, empty: bool) {
     fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
         if !self.is_beginning_of_line() {
             self.break_offset(n, off)
-        } else if off != 0 && self.last_token().is_hardbreak_tok() {
-            // We do something pretty sketchy here: tuck the nonzero
-            // offset-adjustment we were going to deposit along with the
-            // break into the previous hardbreak.
-            self.replace_last_token(pp::Printer::hardbreak_tok_offset(off));
+        } else if off != 0 {
+            if let Some(last_token) = self.last_token_still_buffered() {
+                if last_token.is_hardbreak_tok() {
+                    // We do something pretty sketchy here: tuck the nonzero
+                    // offset-adjustment we were going to deposit along with the
+                    // break into the previous hardbreak.
+                    self.replace_last_token_still_buffered(pp::Printer::hardbreak_tok_offset(off));
+                }
+            }
         }
     }
 
@@ -910,7 +913,7 @@ fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params:
 
 impl<'a> State<'a> {
     pub fn new() -> State<'a> {
-        State { s: pp::mk_printer(), comments: None, ann: &NoAnn }
+        State { s: pp::Printer::new(), comments: None, ann: &NoAnn }
     }
 
     crate fn commasep_cmnt<T, F, G>(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G)
@@ -938,13 +941,6 @@ pub fn new() -> State<'a> {
         self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span)
     }
 
-    crate fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
-        self.print_inner_attributes(attrs);
-        for item in &nmod.items {
-            self.print_foreign_item(item);
-        }
-    }
-
     pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
         if let Some(lt) = *lifetime {
             self.print_lifetime(lt);
@@ -952,18 +948,19 @@ pub fn print_opt_lifetime(&mut self, lifetime: &Option<ast::Lifetime>) {
         }
     }
 
-    pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocTyConstraint) {
+    pub fn print_assoc_constraint(&mut self, constraint: &ast::AssocConstraint) {
         self.print_ident(constraint.ident);
         constraint.gen_args.as_ref().map(|args| self.print_generic_args(args, false));
         self.space();
         match &constraint.kind {
-            ast::AssocTyConstraintKind::Equality { ty } => {
+            ast::AssocConstraintKind::Equality { term } => {
                 self.word_space("=");
-                self.print_type(ty);
-            }
-            ast::AssocTyConstraintKind::Bound { bounds } => {
-                self.print_type_bounds(":", &*bounds);
+                match term {
+                    Term::Ty(ty) => self.print_type(ty),
+                    Term::Const(c) => self.print_expr_anon_const(c),
+                }
             }
+            ast::AssocConstraintKind::Bound { bounds } => self.print_type_bounds(":", &*bounds),
         }
     }
 
@@ -1056,343 +1053,6 @@ pub fn print_type(&mut self, ty: &ast::Ty) {
         self.end();
     }
 
-    crate fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
-        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
-        self.ann.pre(self, AnnNode::SubItem(id));
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(span.lo());
-        self.print_outer_attributes(attrs);
-        match kind {
-            ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
-                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
-            }
-            ast::ForeignItemKind::Static(ty, mutbl, body) => {
-                let def = ast::Defaultness::Final;
-                self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
-            }
-            ast::ForeignItemKind::TyAlias(box ast::TyAlias {
-                defaultness,
-                generics,
-                bounds,
-                ty,
-            }) => {
-                self.print_associated_type(
-                    ident,
-                    generics,
-                    bounds,
-                    ty.as_deref(),
-                    vis,
-                    *defaultness,
-                );
-            }
-            ast::ForeignItemKind::MacCall(m) => {
-                self.print_mac(m);
-                if m.args.need_semicolon() {
-                    self.word(";");
-                }
-            }
-        }
-        self.ann.post(self, AnnNode::SubItem(id))
-    }
-
-    fn print_item_const(
-        &mut self,
-        ident: Ident,
-        mutbl: Option<ast::Mutability>,
-        ty: &ast::Ty,
-        body: Option<&ast::Expr>,
-        vis: &ast::Visibility,
-        defaultness: ast::Defaultness,
-    ) {
-        self.head("");
-        self.print_visibility(vis);
-        self.print_defaultness(defaultness);
-        let leading = match mutbl {
-            None => "const",
-            Some(ast::Mutability::Not) => "static",
-            Some(ast::Mutability::Mut) => "static mut",
-        };
-        self.word_space(leading);
-        self.print_ident(ident);
-        self.word_space(":");
-        self.print_type(ty);
-        if body.is_some() {
-            self.space();
-        }
-        self.end(); // end the head-ibox
-        if let Some(body) = body {
-            self.word_space("=");
-            self.print_expr(body);
-        }
-        self.word(";");
-        self.end(); // end the outer cbox
-    }
-
-    fn print_associated_type(
-        &mut self,
-        ident: Ident,
-        generics: &ast::Generics,
-        bounds: &ast::GenericBounds,
-        ty: Option<&ast::Ty>,
-        vis: &ast::Visibility,
-        defaultness: ast::Defaultness,
-    ) {
-        self.head("");
-        self.print_visibility(vis);
-        self.print_defaultness(defaultness);
-        self.word_space("type");
-        self.print_ident(ident);
-        self.print_generic_params(&generics.params);
-        self.print_type_bounds(":", bounds);
-        self.print_where_clause(&generics.where_clause);
-        if let Some(ty) = ty {
-            self.space();
-            self.word_space("=");
-            self.print_type(ty);
-        }
-        self.word(";");
-        self.end(); // end inner head-block
-        self.end(); // end outer head-block
-    }
-
-    /// Pretty-prints an item.
-    crate fn print_item(&mut self, item: &ast::Item) {
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(item.span.lo());
-        self.print_outer_attributes(&item.attrs);
-        self.ann.pre(self, AnnNode::Item(item));
-        match item.kind {
-            ast::ItemKind::ExternCrate(orig_name) => {
-                self.head(visibility_qualified(&item.vis, "extern crate"));
-                if let Some(orig_name) = orig_name {
-                    self.print_name(orig_name);
-                    self.space();
-                    self.word("as");
-                    self.space();
-                }
-                self.print_ident(item.ident);
-                self.word(";");
-                self.end(); // end inner head-block
-                self.end(); // end outer head-block
-            }
-            ast::ItemKind::Use(ref tree) => {
-                self.head(visibility_qualified(&item.vis, "use"));
-                self.print_use_tree(tree);
-                self.word(";");
-                self.end(); // end inner head-block
-                self.end(); // end outer head-block
-            }
-            ast::ItemKind::Static(ref ty, mutbl, ref body) => {
-                let def = ast::Defaultness::Final;
-                self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def);
-            }
-            ast::ItemKind::Const(def, ref ty, ref body) => {
-                self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
-            }
-            ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => {
-                let body = body.as_deref();
-                self.print_fn_full(
-                    sig,
-                    item.ident,
-                    generics,
-                    &item.vis,
-                    defaultness,
-                    body,
-                    &item.attrs,
-                );
-            }
-            ast::ItemKind::Mod(unsafety, ref mod_kind) => {
-                self.head(Self::to_string(|s| {
-                    s.print_visibility(&item.vis);
-                    s.print_unsafety(unsafety);
-                    s.word("mod");
-                }));
-                self.print_ident(item.ident);
-
-                match mod_kind {
-                    ModKind::Loaded(items, ..) => {
-                        self.nbsp();
-                        self.bopen();
-                        self.print_inner_attributes(&item.attrs);
-                        for item in items {
-                            self.print_item(item);
-                        }
-                        let empty = item.attrs.is_empty() && items.is_empty();
-                        self.bclose(item.span, empty);
-                    }
-                    ModKind::Unloaded => {
-                        self.word(";");
-                        self.end(); // end inner head-block
-                        self.end(); // end outer head-block
-                    }
-                }
-            }
-            ast::ItemKind::ForeignMod(ref nmod) => {
-                self.head(Self::to_string(|s| {
-                    s.print_unsafety(nmod.unsafety);
-                    s.word("extern");
-                }));
-                if let Some(abi) = nmod.abi {
-                    self.print_literal(&abi.as_lit());
-                    self.nbsp();
-                }
-                self.bopen();
-                self.print_foreign_mod(nmod, &item.attrs);
-                let empty = item.attrs.is_empty() && nmod.items.is_empty();
-                self.bclose(item.span, empty);
-            }
-            ast::ItemKind::GlobalAsm(ref asm) => {
-                self.head(visibility_qualified(&item.vis, "global_asm!"));
-                self.print_inline_asm(asm);
-                self.end();
-            }
-            ast::ItemKind::TyAlias(box ast::TyAlias {
-                defaultness,
-                ref generics,
-                ref bounds,
-                ref ty,
-            }) => {
-                let ty = ty.as_deref();
-                self.print_associated_type(
-                    item.ident,
-                    generics,
-                    bounds,
-                    ty,
-                    &item.vis,
-                    defaultness,
-                );
-            }
-            ast::ItemKind::Enum(ref enum_definition, ref params) => {
-                self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
-            }
-            ast::ItemKind::Struct(ref struct_def, ref generics) => {
-                self.head(visibility_qualified(&item.vis, "struct"));
-                self.print_struct(struct_def, generics, item.ident, item.span, true);
-            }
-            ast::ItemKind::Union(ref struct_def, ref generics) => {
-                self.head(visibility_qualified(&item.vis, "union"));
-                self.print_struct(struct_def, generics, item.ident, item.span, true);
-            }
-            ast::ItemKind::Impl(box ast::Impl {
-                unsafety,
-                polarity,
-                defaultness,
-                constness,
-                ref generics,
-                ref of_trait,
-                ref self_ty,
-                ref items,
-            }) => {
-                self.head("");
-                self.print_visibility(&item.vis);
-                self.print_defaultness(defaultness);
-                self.print_unsafety(unsafety);
-                self.word("impl");
-
-                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("!");
-                }
-
-                if let Some(ref t) = *of_trait {
-                    self.print_trait_ref(t);
-                    self.space();
-                    self.word_space("for");
-                }
-
-                self.print_type(self_ty);
-                self.print_where_clause(&generics.where_clause);
-
-                self.space();
-                self.bopen();
-                self.print_inner_attributes(&item.attrs);
-                for impl_item in items {
-                    self.print_assoc_item(impl_item);
-                }
-                let empty = item.attrs.is_empty() && items.is_empty();
-                self.bclose(item.span, empty);
-            }
-            ast::ItemKind::Trait(box ast::Trait {
-                is_auto,
-                unsafety,
-                ref generics,
-                ref bounds,
-                ref items,
-                ..
-            }) => {
-                self.head("");
-                self.print_visibility(&item.vis);
-                self.print_unsafety(unsafety);
-                self.print_is_auto(is_auto);
-                self.word_nbsp("trait");
-                self.print_ident(item.ident);
-                self.print_generic_params(&generics.params);
-                let mut real_bounds = Vec::with_capacity(bounds.len());
-                for b in bounds.iter() {
-                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
-                        self.space();
-                        self.word_space("for ?");
-                        self.print_trait_ref(&ptr.trait_ref);
-                    } else {
-                        real_bounds.push(b.clone());
-                    }
-                }
-                self.print_type_bounds(":", &real_bounds);
-                self.print_where_clause(&generics.where_clause);
-                self.word(" ");
-                self.bopen();
-                self.print_inner_attributes(&item.attrs);
-                for trait_item in items {
-                    self.print_assoc_item(trait_item);
-                }
-                let empty = item.attrs.is_empty() && items.is_empty();
-                self.bclose(item.span, empty);
-            }
-            ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
-                self.head("");
-                self.print_visibility(&item.vis);
-                self.word_nbsp("trait");
-                self.print_ident(item.ident);
-                self.print_generic_params(&generics.params);
-                let mut real_bounds = Vec::with_capacity(bounds.len());
-                // FIXME(durka) this seems to be some quite outdated syntax
-                for b in bounds.iter() {
-                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
-                        self.space();
-                        self.word_space("for ?");
-                        self.print_trait_ref(&ptr.trait_ref);
-                    } else {
-                        real_bounds.push(b.clone());
-                    }
-                }
-                self.nbsp();
-                self.print_type_bounds("=", &real_bounds);
-                self.print_where_clause(&generics.where_clause);
-                self.word(";");
-            }
-            ast::ItemKind::MacCall(ref mac) => {
-                self.print_mac(mac);
-                if mac.args.need_semicolon() {
-                    self.word(";");
-                }
-            }
-            ast::ItemKind::MacroDef(ref macro_def) => {
-                self.print_mac_def(macro_def, &item.ident, &item.span, |state| {
-                    state.print_visibility(&item.vis)
-                });
-            }
-        }
-        self.ann.post(self, AnnNode::Item(item))
-    }
-
     fn print_trait_ref(&mut self, t: &ast::TraitRef) {
         self.print_path(&t.path, false, 0)
     }
@@ -1410,167 +1070,6 @@ fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
         self.print_trait_ref(&t.trait_ref)
     }
 
-    crate fn print_enum_def(
-        &mut self,
-        enum_definition: &ast::EnumDef,
-        generics: &ast::Generics,
-        ident: Ident,
-        span: rustc_span::Span,
-        visibility: &ast::Visibility,
-    ) {
-        self.head(visibility_qualified(visibility, "enum"));
-        self.print_ident(ident);
-        self.print_generic_params(&generics.params);
-        self.print_where_clause(&generics.where_clause);
-        self.space();
-        self.print_variants(&enum_definition.variants, span)
-    }
-
-    crate fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
-        self.bopen();
-        for v in variants {
-            self.space_if_not_bol();
-            self.maybe_print_comment(v.span.lo());
-            self.print_outer_attributes(&v.attrs);
-            self.ibox(INDENT_UNIT);
-            self.print_variant(v);
-            self.word(",");
-            self.end();
-            self.maybe_print_trailing_comment(v.span, None);
-        }
-        let empty = variants.is_empty();
-        self.bclose(span, empty)
-    }
-
-    crate fn print_visibility(&mut self, vis: &ast::Visibility) {
-        match vis.kind {
-            ast::VisibilityKind::Public => self.word_nbsp("pub"),
-            ast::VisibilityKind::Crate(sugar) => match sugar {
-                ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
-                ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
-            },
-            ast::VisibilityKind::Restricted { ref path, .. } => {
-                let path = Self::to_string(|s| s.print_path(path, false, 0));
-                if path == "self" || path == "super" {
-                    self.word_nbsp(format!("pub({})", path))
-                } else {
-                    self.word_nbsp(format!("pub(in {})", path))
-                }
-            }
-            ast::VisibilityKind::Inherited => {}
-        }
-    }
-
-    crate fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
-        if let ast::Defaultness::Default(_) = defaultness {
-            self.word_nbsp("default");
-        }
-    }
-
-    crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
-        self.nbsp();
-        self.bopen();
-
-        let empty = fields.is_empty();
-        if !empty {
-            self.hardbreak_if_not_bol();
-
-            for field in fields {
-                self.hardbreak_if_not_bol();
-                self.maybe_print_comment(field.span.lo());
-                self.print_outer_attributes(&field.attrs);
-                self.print_visibility(&field.vis);
-                self.print_ident(field.ident.unwrap());
-                self.word_nbsp(":");
-                self.print_type(&field.ty);
-                self.word(",");
-            }
-        }
-
-        self.bclose(span, empty);
-    }
-
-    crate fn print_struct(
-        &mut self,
-        struct_def: &ast::VariantData,
-        generics: &ast::Generics,
-        ident: Ident,
-        span: rustc_span::Span,
-        print_finalizer: bool,
-    ) {
-        self.print_ident(ident);
-        self.print_generic_params(&generics.params);
-        match struct_def {
-            ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
-                if let ast::VariantData::Tuple(..) = struct_def {
-                    self.popen();
-                    self.commasep(Inconsistent, struct_def.fields(), |s, field| {
-                        s.maybe_print_comment(field.span.lo());
-                        s.print_outer_attributes(&field.attrs);
-                        s.print_visibility(&field.vis);
-                        s.print_type(&field.ty)
-                    });
-                    self.pclose();
-                }
-                self.print_where_clause(&generics.where_clause);
-                if print_finalizer {
-                    self.word(";");
-                }
-                self.end();
-                self.end(); // Close the outer-box.
-            }
-            ast::VariantData::Struct(ref fields, ..) => {
-                self.print_where_clause(&generics.where_clause);
-                self.print_record_struct_body(fields, span);
-            }
-        }
-    }
-
-    crate fn print_variant(&mut self, v: &ast::Variant) {
-        self.head("");
-        self.print_visibility(&v.vis);
-        let generics = ast::Generics::default();
-        self.print_struct(&v.data, &generics, v.ident, v.span, false);
-        if let Some(ref d) = v.disr_expr {
-            self.space();
-            self.word_space("=");
-            self.print_expr(&d.value)
-        }
-    }
-
-    crate fn print_assoc_item(&mut self, item: &ast::AssocItem) {
-        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
-        self.ann.pre(self, AnnNode::SubItem(id));
-        self.hardbreak_if_not_bol();
-        self.maybe_print_comment(span.lo());
-        self.print_outer_attributes(attrs);
-        match kind {
-            ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
-                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
-            }
-            ast::AssocItemKind::Const(def, ty, body) => {
-                self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
-            }
-            ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
-                self.print_associated_type(
-                    ident,
-                    generics,
-                    bounds,
-                    ty.as_deref(),
-                    vis,
-                    *defaultness,
-                );
-            }
-            ast::AssocItemKind::MacCall(m) => {
-                self.print_mac(m);
-                if m.args.need_semicolon() {
-                    self.word(";");
-                }
-            }
-        }
-        self.ann.post(self, AnnNode::SubItem(id))
-    }
-
     crate fn print_stmt(&mut self, st: &ast::Stmt) {
         self.maybe_print_comment(st.span.lo());
         match st.kind {
@@ -1681,42 +1180,6 @@ fn print_poly_trait_ref(&mut self, t: &ast::PolyTraitRef) {
         self.print_expr_cond_paren(expr, Self::cond_needs_par(expr) || npals())
     }
 
-    fn print_else(&mut self, els: Option<&ast::Expr>) {
-        if let Some(_else) = els {
-            match _else.kind {
-                // Another `else if` block.
-                ast::ExprKind::If(ref i, ref then, ref e) => {
-                    self.cbox(INDENT_UNIT - 1);
-                    self.ibox(0);
-                    self.word(" else if ");
-                    self.print_expr_as_cond(i);
-                    self.space();
-                    self.print_block(then);
-                    self.print_else(e.as_deref())
-                }
-                // Final `else` block.
-                ast::ExprKind::Block(ref b, _) => {
-                    self.cbox(INDENT_UNIT - 1);
-                    self.ibox(0);
-                    self.word(" else ");
-                    self.print_block(b)
-                }
-                // Constraints would be great here!
-                _ => {
-                    panic!("print_if saw if with weird alternative");
-                }
-            }
-        }
-    }
-
-    crate fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
-        self.head("if");
-        self.print_expr_as_cond(test);
-        self.space();
-        self.print_block(blk);
-        self.print_else(elseopt)
-    }
-
     crate fn print_mac(&mut self, m: &ast::MacCall) {
         self.print_mac_common(
             Some(MacHeader::Path(&m.path)),
@@ -1729,533 +1192,6 @@ fn print_else(&mut self, els: Option<&ast::Expr>) {
         );
     }
 
-    fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
-        self.popen();
-        self.commasep_exprs(Inconsistent, args);
-        self.pclose()
-    }
-
-    crate fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
-        self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
-    }
-
-    /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
-    /// `if cond { ... }`.
-    crate fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
-        self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
-    }
-
-    // Does `expr` need parentheses when printed in a condition position?
-    //
-    // These cases need parens due to the parse error observed in #26461: `if return {}`
-    // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
-    fn cond_needs_par(expr: &ast::Expr) -> bool {
-        match expr.kind {
-            ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
-            _ => parser::contains_exterior_struct_lit(expr),
-        }
-    }
-
-    /// Prints `expr` or `(expr)` when `needs_par` holds.
-    fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
-        if needs_par {
-            self.popen();
-        }
-        self.print_expr(expr);
-        if needs_par {
-            self.pclose();
-        }
-    }
-
-    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
-        self.ibox(INDENT_UNIT);
-        self.word("[");
-        self.commasep_exprs(Inconsistent, exprs);
-        self.word("]");
-        self.end();
-    }
-
-    fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
-        self.ibox(INDENT_UNIT);
-        self.word("const");
-        self.print_expr(&expr.value);
-        self.end();
-    }
-
-    fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
-        self.ibox(INDENT_UNIT);
-        self.word("[");
-        self.print_expr(element);
-        self.word_space(";");
-        self.print_expr(&count.value);
-        self.word("]");
-        self.end();
-    }
-
-    fn print_expr_struct(
-        &mut self,
-        qself: &Option<ast::QSelf>,
-        path: &ast::Path,
-        fields: &[ast::ExprField],
-        rest: &ast::StructRest,
-    ) {
-        if let Some(qself) = qself {
-            self.print_qpath(path, qself, true);
-        } else {
-            self.print_path(path, true, 0);
-        }
-        self.word("{");
-        self.commasep_cmnt(
-            Consistent,
-            fields,
-            |s, field| {
-                s.print_outer_attributes(&field.attrs);
-                s.ibox(INDENT_UNIT);
-                if !field.is_shorthand {
-                    s.print_ident(field.ident);
-                    s.word_space(":");
-                }
-                s.print_expr(&field.expr);
-                s.end();
-            },
-            |f| f.span,
-        );
-        match rest {
-            ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
-                self.ibox(INDENT_UNIT);
-                if !fields.is_empty() {
-                    self.word(",");
-                    self.space();
-                }
-                self.word("..");
-                if let ast::StructRest::Base(ref expr) = *rest {
-                    self.print_expr(expr);
-                }
-                self.end();
-            }
-            ast::StructRest::None if !fields.is_empty() => self.word(","),
-            _ => {}
-        }
-        self.word("}");
-    }
-
-    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
-        self.popen();
-        self.commasep_exprs(Inconsistent, exprs);
-        if exprs.len() == 1 {
-            self.word(",");
-        }
-        self.pclose()
-    }
-
-    fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
-        let prec = match func.kind {
-            ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
-            _ => parser::PREC_POSTFIX,
-        };
-
-        self.print_expr_maybe_paren(func, prec);
-        self.print_call_post(args)
-    }
-
-    fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
-        let base_args = &args[1..];
-        self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
-        self.word(".");
-        self.print_ident(segment.ident);
-        if let Some(ref args) = segment.args {
-            self.print_generic_args(args, true);
-        }
-        self.print_call_post(base_args)
-    }
-
-    fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
-        let assoc_op = AssocOp::from_ast_binop(op.node);
-        let prec = assoc_op.precedence() as i8;
-        let fixity = assoc_op.fixity();
-
-        let (left_prec, right_prec) = match fixity {
-            Fixity::Left => (prec, prec + 1),
-            Fixity::Right => (prec + 1, prec),
-            Fixity::None => (prec + 1, prec + 1),
-        };
-
-        let left_prec = match (&lhs.kind, op.node) {
-            // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
-            // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
-            // of `(x as i32) < ...`. We need to convince it _not_ to do that.
-            (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
-                parser::PREC_FORCE_PAREN
-            }
-            // We are given `(let _ = a) OP b`.
-            //
-            // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
-            //   as the parser will interpret this as `(let _ = a) OP b`.
-            //
-            // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
-            //   parens are required since the parser would interpret `let a = b < c` as
-            //   `let a = (b < c)`. To achieve this, we force parens.
-            (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
-                parser::PREC_FORCE_PAREN
-            }
-            _ => left_prec,
-        };
-
-        self.print_expr_maybe_paren(lhs, left_prec);
-        self.space();
-        self.word_space(op.node.to_string());
-        self.print_expr_maybe_paren(rhs, right_prec)
-    }
-
-    fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
-        self.word(ast::UnOp::to_string(op));
-        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
-    }
-
-    fn print_expr_addr_of(
-        &mut self,
-        kind: ast::BorrowKind,
-        mutability: ast::Mutability,
-        expr: &ast::Expr,
-    ) {
-        self.word("&");
-        match kind {
-            ast::BorrowKind::Ref => self.print_mutability(mutability, false),
-            ast::BorrowKind::Raw => {
-                self.word_nbsp("raw");
-                self.print_mutability(mutability, true);
-            }
-        }
-        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
-    }
-
-    pub fn print_expr(&mut self, expr: &ast::Expr) {
-        self.print_expr_outer_attr_style(expr, true)
-    }
-
-    fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
-        self.maybe_print_comment(expr.span.lo());
-
-        let attrs = &expr.attrs;
-        if is_inline {
-            self.print_outer_attributes_inline(attrs);
-        } else {
-            self.print_outer_attributes(attrs);
-        }
-
-        self.ibox(INDENT_UNIT);
-        self.ann.pre(self, AnnNode::Expr(expr));
-        match expr.kind {
-            ast::ExprKind::Box(ref expr) => {
-                self.word_space("box");
-                self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
-            }
-            ast::ExprKind::Array(ref exprs) => {
-                self.print_expr_vec(exprs);
-            }
-            ast::ExprKind::ConstBlock(ref anon_const) => {
-                self.print_expr_anon_const(anon_const);
-            }
-            ast::ExprKind::Repeat(ref element, ref count) => {
-                self.print_expr_repeat(element, count);
-            }
-            ast::ExprKind::Struct(ref se) => {
-                self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest);
-            }
-            ast::ExprKind::Tup(ref exprs) => {
-                self.print_expr_tup(exprs);
-            }
-            ast::ExprKind::Call(ref func, ref args) => {
-                self.print_expr_call(func, &args);
-            }
-            ast::ExprKind::MethodCall(ref segment, ref args, _) => {
-                self.print_expr_method_call(segment, &args);
-            }
-            ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
-                self.print_expr_binary(op, lhs, rhs);
-            }
-            ast::ExprKind::Unary(op, ref expr) => {
-                self.print_expr_unary(op, expr);
-            }
-            ast::ExprKind::AddrOf(k, m, ref expr) => {
-                self.print_expr_addr_of(k, m, expr);
-            }
-            ast::ExprKind::Lit(ref lit) => {
-                self.print_literal(lit);
-            }
-            ast::ExprKind::Cast(ref expr, ref ty) => {
-                let prec = AssocOp::As.precedence() as i8;
-                self.print_expr_maybe_paren(expr, prec);
-                self.space();
-                self.word_space("as");
-                self.print_type(ty);
-            }
-            ast::ExprKind::Type(ref expr, ref ty) => {
-                let prec = AssocOp::Colon.precedence() as i8;
-                self.print_expr_maybe_paren(expr, prec);
-                self.word_space(":");
-                self.print_type(ty);
-            }
-            ast::ExprKind::Let(ref pat, ref scrutinee, _) => {
-                self.print_let(pat, scrutinee);
-            }
-            ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
-                self.print_if(test, blk, elseopt.as_deref())
-            }
-            ast::ExprKind::While(ref test, ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                self.head("while");
-                self.print_expr_as_cond(test);
-                self.space();
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                self.head("for");
-                self.print_pat(pat);
-                self.space();
-                self.word_space("in");
-                self.print_expr_as_cond(iter);
-                self.space();
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Loop(ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                self.head("loop");
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Match(ref expr, ref arms) => {
-                self.cbox(INDENT_UNIT);
-                self.ibox(INDENT_UNIT);
-                self.word_nbsp("match");
-                self.print_expr_as_cond(expr);
-                self.space();
-                self.bopen();
-                self.print_inner_attributes_no_trailing_hardbreak(attrs);
-                for arm in arms {
-                    self.print_arm(arm);
-                }
-                let empty = attrs.is_empty() && arms.is_empty();
-                self.bclose(expr.span, empty);
-            }
-            ast::ExprKind::Closure(
-                capture_clause,
-                asyncness,
-                movability,
-                ref decl,
-                ref body,
-                _,
-            ) => {
-                self.print_movability(movability);
-                self.print_asyncness(asyncness);
-                self.print_capture_clause(capture_clause);
-
-                self.print_fn_params_and_ret(decl, true);
-                self.space();
-                self.print_expr(body);
-                self.end(); // need to close a box
-
-                // a box will be closed by print_expr, but we didn't want an overall
-                // wrapper so we closed the corresponding opening. so create an
-                // empty box to satisfy the close.
-                self.ibox(0);
-            }
-            ast::ExprKind::Block(ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-                // containing cbox, will be closed by print-block at }
-                self.cbox(INDENT_UNIT);
-                // head-box, will be closed by print-block after {
-                self.ibox(0);
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Async(capture_clause, _, ref blk) => {
-                self.word_nbsp("async");
-                self.print_capture_clause(capture_clause);
-                // cbox/ibox in analogy to the `ExprKind::Block` arm above
-                self.cbox(INDENT_UNIT);
-                self.ibox(0);
-                self.print_block_with_attrs(blk, attrs);
-            }
-            ast::ExprKind::Await(ref expr) => {
-                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
-                self.word(".await");
-            }
-            ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
-                let prec = AssocOp::Assign.precedence() as i8;
-                self.print_expr_maybe_paren(lhs, prec + 1);
-                self.space();
-                self.word_space("=");
-                self.print_expr_maybe_paren(rhs, prec);
-            }
-            ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
-                let prec = AssocOp::Assign.precedence() as i8;
-                self.print_expr_maybe_paren(lhs, prec + 1);
-                self.space();
-                self.word(op.node.to_string());
-                self.word_space("=");
-                self.print_expr_maybe_paren(rhs, prec);
-            }
-            ast::ExprKind::Field(ref expr, ident) => {
-                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
-                self.word(".");
-                self.print_ident(ident);
-            }
-            ast::ExprKind::Index(ref expr, ref index) => {
-                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
-                self.word("[");
-                self.print_expr(index);
-                self.word("]");
-            }
-            ast::ExprKind::Range(ref start, ref end, limits) => {
-                // Special case for `Range`.  `AssocOp` claims that `Range` has higher precedence
-                // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
-                // Here we use a fake precedence value so that any child with lower precedence than
-                // a "normal" binop gets parenthesized.  (`LOr` is the lowest-precedence binop.)
-                let fake_prec = AssocOp::LOr.precedence() as i8;
-                if let Some(ref e) = *start {
-                    self.print_expr_maybe_paren(e, fake_prec);
-                }
-                if limits == ast::RangeLimits::HalfOpen {
-                    self.word("..");
-                } else {
-                    self.word("..=");
-                }
-                if let Some(ref e) = *end {
-                    self.print_expr_maybe_paren(e, fake_prec);
-                }
-            }
-            ast::ExprKind::Underscore => self.word("_"),
-            ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
-            ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
-            ast::ExprKind::Break(opt_label, ref opt_expr) => {
-                self.word("break");
-                if let Some(label) = opt_label {
-                    self.space();
-                    self.print_ident(label.ident);
-                }
-                if let Some(ref expr) = *opt_expr {
-                    self.space();
-                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
-                }
-            }
-            ast::ExprKind::Continue(opt_label) => {
-                self.word("continue");
-                if let Some(label) = opt_label {
-                    self.space();
-                    self.print_ident(label.ident);
-                }
-            }
-            ast::ExprKind::Ret(ref result) => {
-                self.word("return");
-                if let Some(ref expr) = *result {
-                    self.word(" ");
-                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
-                }
-            }
-            ast::ExprKind::InlineAsm(ref a) => {
-                self.word("asm!");
-                self.print_inline_asm(a);
-            }
-            ast::ExprKind::LlvmInlineAsm(ref a) => {
-                self.word("llvm_asm!");
-                self.popen();
-                self.print_symbol(a.asm, a.asm_str_style);
-                self.word_space(":");
-
-                self.commasep(Inconsistent, &a.outputs, |s, out| {
-                    let constraint = out.constraint.as_str();
-                    let mut ch = constraint.chars();
-                    match ch.next() {
-                        Some('=') if out.is_rw => {
-                            s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
-                        }
-                        _ => s.print_string(&constraint, ast::StrStyle::Cooked),
-                    }
-                    s.popen();
-                    s.print_expr(&out.expr);
-                    s.pclose();
-                });
-                self.space();
-                self.word_space(":");
-
-                self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
-                    s.print_symbol(co, ast::StrStyle::Cooked);
-                    s.popen();
-                    s.print_expr(o);
-                    s.pclose();
-                });
-                self.space();
-                self.word_space(":");
-
-                self.commasep(Inconsistent, &a.clobbers, |s, &co| {
-                    s.print_symbol(co, ast::StrStyle::Cooked);
-                });
-
-                let mut options = vec![];
-                if a.volatile {
-                    options.push("volatile");
-                }
-                if a.alignstack {
-                    options.push("alignstack");
-                }
-                if a.dialect == ast::LlvmAsmDialect::Intel {
-                    options.push("intel");
-                }
-
-                if !options.is_empty() {
-                    self.space();
-                    self.word_space(":");
-                    self.commasep(Inconsistent, &options, |s, &co| {
-                        s.print_string(co, ast::StrStyle::Cooked);
-                    });
-                }
-
-                self.pclose();
-            }
-            ast::ExprKind::MacCall(ref m) => self.print_mac(m),
-            ast::ExprKind::Paren(ref e) => {
-                self.popen();
-                self.print_expr(e);
-                self.pclose();
-            }
-            ast::ExprKind::Yield(ref e) => {
-                self.word("yield");
-
-                if let Some(ref expr) = *e {
-                    self.space();
-                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
-                }
-            }
-            ast::ExprKind::Try(ref e) => {
-                self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
-                self.word("?")
-            }
-            ast::ExprKind::TryBlock(ref blk) => {
-                self.head("try");
-                self.print_block_with_attrs(blk, attrs)
-            }
-            ast::ExprKind::Err => {
-                self.popen();
-                self.word("/*ERROR*/");
-                self.pclose()
-            }
-        }
-        self.ann.post(self, AnnNode::Expr(expr));
-        self.end();
-    }
-
     fn print_inline_asm(&mut self, asm: &ast::InlineAsm) {
         enum AsmArg<'a> {
             Template(String),
@@ -2551,48 +1487,6 @@ fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, colons_before_pa
         self.ann.post(self, AnnNode::Pat(pat))
     }
 
-    fn print_arm(&mut self, arm: &ast::Arm) {
-        // Note, I have no idea why this check is necessary, but here it is.
-        if arm.attrs.is_empty() {
-            self.space();
-        }
-        self.cbox(INDENT_UNIT);
-        self.ibox(0);
-        self.maybe_print_comment(arm.pat.span.lo());
-        self.print_outer_attributes(&arm.attrs);
-        self.print_pat(&arm.pat);
-        self.space();
-        if let Some(ref e) = arm.guard {
-            self.word_space("if");
-            self.print_expr(e);
-            self.space();
-        }
-        self.word_space("=>");
-
-        match arm.body.kind {
-            ast::ExprKind::Block(ref blk, opt_label) => {
-                if let Some(label) = opt_label {
-                    self.print_ident(label.ident);
-                    self.word_space(":");
-                }
-
-                // The block will close the pattern's ibox.
-                self.print_block_unclosed_indent(blk);
-
-                // If it is a user-provided unsafe block, print a comma after it.
-                if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
-                    self.word(",");
-                }
-            }
-            _ => {
-                self.end(); // Close the ibox for the pattern.
-                self.print_expr(&arm.body);
-                self.word(",");
-            }
-        }
-        self.end(); // Close enclosing cbox.
-    }
-
     fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
         match explicit_self.node {
             SelfKind::Value(m) => {
@@ -2614,75 +1508,12 @@ fn print_explicit_self(&mut self, explicit_self: &ast::ExplicitSelf) {
         }
     }
 
-    fn print_fn_full(
-        &mut self,
-        sig: &ast::FnSig,
-        name: Ident,
-        generics: &ast::Generics,
-        vis: &ast::Visibility,
-        defaultness: ast::Defaultness,
-        body: Option<&ast::Block>,
-        attrs: &[ast::Attribute],
-    ) {
-        if body.is_some() {
-            self.head("");
-        }
-        self.print_visibility(vis);
-        self.print_defaultness(defaultness);
-        self.print_fn(&sig.decl, sig.header, Some(name), generics);
-        if let Some(body) = body {
-            self.nbsp();
-            self.print_block_with_attrs(body, attrs);
-        } else {
-            self.word(";");
-        }
-    }
-
-    crate fn print_fn(
-        &mut self,
-        decl: &ast::FnDecl,
-        header: ast::FnHeader,
-        name: Option<Ident>,
-        generics: &ast::Generics,
-    ) {
-        self.print_fn_header_info(header);
-        if let Some(name) = name {
-            self.nbsp();
-            self.print_ident(name);
-        }
-        self.print_generic_params(&generics.params);
-        self.print_fn_params_and_ret(decl, false);
-        self.print_where_clause(&generics.where_clause)
-    }
-
-    crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
-        let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
-        self.word(open);
-        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
-        self.word(close);
-        self.print_fn_ret_ty(&decl.output)
-    }
-
-    crate fn print_movability(&mut self, movability: ast::Movability) {
-        match movability {
-            ast::Movability::Static => self.word_space("static"),
-            ast::Movability::Movable => {}
-        }
-    }
-
     crate fn print_asyncness(&mut self, asyncness: ast::Async) {
         if asyncness.is_async() {
             self.word_nbsp("async");
         }
     }
 
-    crate fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
-        match capture_clause {
-            ast::CaptureBy::Value => self.word_space("move"),
-            ast::CaptureBy::Ref => {}
-        }
-    }
-
     pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::GenericBound]) {
         if !bounds.is_empty() {
             self.word(prefix);
@@ -2777,83 +1608,6 @@ pub fn print_type_bounds(&mut self, prefix: &'static str, bounds: &[ast::Generic
         self.word(">");
     }
 
-    crate fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
-        if where_clause.predicates.is_empty() && !where_clause.has_where_token {
-            return;
-        }
-
-        self.space();
-        self.word_space("where");
-
-        for (i, predicate) in where_clause.predicates.iter().enumerate() {
-            if i != 0 {
-                self.word_space(",");
-            }
-
-            self.print_where_predicate(predicate);
-        }
-    }
-
-    pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
-        match predicate {
-            ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
-                bound_generic_params,
-                bounded_ty,
-                bounds,
-                ..
-            }) => {
-                self.print_formal_generic_params(bound_generic_params);
-                self.print_type(bounded_ty);
-                self.print_type_bounds(":", bounds);
-            }
-            ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
-                lifetime,
-                bounds,
-                ..
-            }) => {
-                self.print_lifetime_bounds(*lifetime, bounds);
-            }
-            ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
-                self.print_type(lhs_ty);
-                self.space();
-                self.word_space("=");
-                self.print_type(rhs_ty);
-            }
-        }
-    }
-
-    crate fn print_use_tree(&mut self, tree: &ast::UseTree) {
-        match tree.kind {
-            ast::UseTreeKind::Simple(rename, ..) => {
-                self.print_path(&tree.prefix, false, 0);
-                if let Some(rename) = rename {
-                    self.space();
-                    self.word_space("as");
-                    self.print_ident(rename);
-                }
-            }
-            ast::UseTreeKind::Glob => {
-                if !tree.prefix.segments.is_empty() {
-                    self.print_path(&tree.prefix, false, 0);
-                    self.word("::");
-                }
-                self.word("*");
-            }
-            ast::UseTreeKind::Nested(ref items) => {
-                if tree.prefix.segments.is_empty() {
-                    self.word("{");
-                } else {
-                    self.print_path(&tree.prefix, false, 0);
-                    self.word("::{");
-                }
-                self.commasep(Inconsistent, &items, |this, &(ref tree, _)| {
-                    this.print_use_tree(tree)
-                });
-                self.word("}");
-            }
-        }
-    }
-
     pub fn print_mutability(&mut self, mutbl: ast::Mutability, print_const: bool) {
         match mutbl {
             ast::Mutability::Mut => self.word_nbsp("mut"),
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
new file mode 100644 (file)
index 0000000..956200d
--- /dev/null
@@ -0,0 +1,571 @@
+use crate::pp::Breaks::{Consistent, Inconsistent};
+use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+
+use rustc_ast::ptr::P;
+use rustc_ast::util::parser::{self, AssocOp, Fixity};
+use rustc_ast::{self as ast, BlockCheckMode};
+
+impl<'a> State<'a> {
+    fn print_else(&mut self, els: Option<&ast::Expr>) {
+        if let Some(_else) = els {
+            match _else.kind {
+                // Another `else if` block.
+                ast::ExprKind::If(ref i, ref then, ref e) => {
+                    self.cbox(INDENT_UNIT - 1);
+                    self.ibox(0);
+                    self.word(" else if ");
+                    self.print_expr_as_cond(i);
+                    self.space();
+                    self.print_block(then);
+                    self.print_else(e.as_deref())
+                }
+                // Final `else` block.
+                ast::ExprKind::Block(ref b, _) => {
+                    self.cbox(INDENT_UNIT - 1);
+                    self.ibox(0);
+                    self.word(" else ");
+                    self.print_block(b)
+                }
+                // Constraints would be great here!
+                _ => {
+                    panic!("print_if saw if with weird alternative");
+                }
+            }
+        }
+    }
+
+    fn print_if(&mut self, test: &ast::Expr, blk: &ast::Block, elseopt: Option<&ast::Expr>) {
+        self.head("if");
+        self.print_expr_as_cond(test);
+        self.space();
+        self.print_block(blk);
+        self.print_else(elseopt)
+    }
+
+    fn print_call_post(&mut self, args: &[P<ast::Expr>]) {
+        self.popen();
+        self.commasep_exprs(Inconsistent, args);
+        self.pclose()
+    }
+
+    fn print_expr_maybe_paren(&mut self, expr: &ast::Expr, prec: i8) {
+        self.print_expr_cond_paren(expr, expr.precedence().order() < prec)
+    }
+
+    /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in
+    /// `if cond { ... }`.
+    fn print_expr_as_cond(&mut self, expr: &ast::Expr) {
+        self.print_expr_cond_paren(expr, Self::cond_needs_par(expr))
+    }
+
+    // Does `expr` need parentheses when printed in a condition position?
+    //
+    // These cases need parens due to the parse error observed in #26461: `if return {}`
+    // parses as the erroneous construct `if (return {})`, not `if (return) {}`.
+    pub(super) fn cond_needs_par(expr: &ast::Expr) -> bool {
+        match expr.kind {
+            ast::ExprKind::Break(..) | ast::ExprKind::Closure(..) | ast::ExprKind::Ret(..) => true,
+            _ => parser::contains_exterior_struct_lit(expr),
+        }
+    }
+
+    /// Prints `expr` or `(expr)` when `needs_par` holds.
+    pub(super) fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) {
+        if needs_par {
+            self.popen();
+        }
+        self.print_expr(expr);
+        if needs_par {
+            self.pclose();
+        }
+    }
+
+    fn print_expr_vec(&mut self, exprs: &[P<ast::Expr>]) {
+        self.ibox(INDENT_UNIT);
+        self.word("[");
+        self.commasep_exprs(Inconsistent, exprs);
+        self.word("]");
+        self.end();
+    }
+
+    pub(super) fn print_expr_anon_const(&mut self, expr: &ast::AnonConst) {
+        self.ibox(INDENT_UNIT);
+        self.word("const");
+        self.print_expr(&expr.value);
+        self.end();
+    }
+
+    fn print_expr_repeat(&mut self, element: &ast::Expr, count: &ast::AnonConst) {
+        self.ibox(INDENT_UNIT);
+        self.word("[");
+        self.print_expr(element);
+        self.word_space(";");
+        self.print_expr(&count.value);
+        self.word("]");
+        self.end();
+    }
+
+    fn print_expr_struct(
+        &mut self,
+        qself: &Option<ast::QSelf>,
+        path: &ast::Path,
+        fields: &[ast::ExprField],
+        rest: &ast::StructRest,
+    ) {
+        if let Some(qself) = qself {
+            self.print_qpath(path, qself, true);
+        } else {
+            self.print_path(path, true, 0);
+        }
+        self.word("{");
+        self.commasep_cmnt(
+            Consistent,
+            fields,
+            |s, field| {
+                s.print_outer_attributes(&field.attrs);
+                s.ibox(INDENT_UNIT);
+                if !field.is_shorthand {
+                    s.print_ident(field.ident);
+                    s.word_space(":");
+                }
+                s.print_expr(&field.expr);
+                s.end();
+            },
+            |f| f.span,
+        );
+        match rest {
+            ast::StructRest::Base(_) | ast::StructRest::Rest(_) => {
+                self.ibox(INDENT_UNIT);
+                if !fields.is_empty() {
+                    self.word(",");
+                    self.space();
+                }
+                self.word("..");
+                if let ast::StructRest::Base(ref expr) = *rest {
+                    self.print_expr(expr);
+                }
+                self.end();
+            }
+            ast::StructRest::None if !fields.is_empty() => self.word(","),
+            _ => {}
+        }
+        self.word("}");
+    }
+
+    fn print_expr_tup(&mut self, exprs: &[P<ast::Expr>]) {
+        self.popen();
+        self.commasep_exprs(Inconsistent, exprs);
+        if exprs.len() == 1 {
+            self.word(",");
+        }
+        self.pclose()
+    }
+
+    fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>]) {
+        let prec = match func.kind {
+            ast::ExprKind::Field(..) => parser::PREC_FORCE_PAREN,
+            _ => parser::PREC_POSTFIX,
+        };
+
+        self.print_expr_maybe_paren(func, prec);
+        self.print_call_post(args)
+    }
+
+    fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
+        let base_args = &args[1..];
+        self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
+        self.word(".");
+        self.print_ident(segment.ident);
+        if let Some(ref args) = segment.args {
+            self.print_generic_args(args, true);
+        }
+        self.print_call_post(base_args)
+    }
+
+    fn print_expr_binary(&mut self, op: ast::BinOp, lhs: &ast::Expr, rhs: &ast::Expr) {
+        let assoc_op = AssocOp::from_ast_binop(op.node);
+        let prec = assoc_op.precedence() as i8;
+        let fixity = assoc_op.fixity();
+
+        let (left_prec, right_prec) = match fixity {
+            Fixity::Left => (prec, prec + 1),
+            Fixity::Right => (prec + 1, prec),
+            Fixity::None => (prec + 1, prec + 1),
+        };
+
+        let left_prec = match (&lhs.kind, op.node) {
+            // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is
+            // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead
+            // of `(x as i32) < ...`. We need to convince it _not_ to do that.
+            (&ast::ExprKind::Cast { .. }, ast::BinOpKind::Lt | ast::BinOpKind::Shl) => {
+                parser::PREC_FORCE_PAREN
+            }
+            // We are given `(let _ = a) OP b`.
+            //
+            // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid redundant parens
+            //   as the parser will interpret this as `(let _ = a) OP b`.
+            //
+            // - Otherwise, e.g. when we have `(let a = b) < c` in AST,
+            //   parens are required since the parser would interpret `let a = b < c` as
+            //   `let a = (b < c)`. To achieve this, we force parens.
+            (&ast::ExprKind::Let { .. }, _) if !parser::needs_par_as_let_scrutinee(prec) => {
+                parser::PREC_FORCE_PAREN
+            }
+            _ => left_prec,
+        };
+
+        self.print_expr_maybe_paren(lhs, left_prec);
+        self.space();
+        self.word_space(op.node.to_string());
+        self.print_expr_maybe_paren(rhs, right_prec)
+    }
+
+    fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr) {
+        self.word(ast::UnOp::to_string(op));
+        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+    }
+
+    fn print_expr_addr_of(
+        &mut self,
+        kind: ast::BorrowKind,
+        mutability: ast::Mutability,
+        expr: &ast::Expr,
+    ) {
+        self.word("&");
+        match kind {
+            ast::BorrowKind::Ref => self.print_mutability(mutability, false),
+            ast::BorrowKind::Raw => {
+                self.word_nbsp("raw");
+                self.print_mutability(mutability, true);
+            }
+        }
+        self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)
+    }
+
+    pub fn print_expr(&mut self, expr: &ast::Expr) {
+        self.print_expr_outer_attr_style(expr, true)
+    }
+
+    pub(super) fn print_expr_outer_attr_style(&mut self, expr: &ast::Expr, is_inline: bool) {
+        self.maybe_print_comment(expr.span.lo());
+
+        let attrs = &expr.attrs;
+        if is_inline {
+            self.print_outer_attributes_inline(attrs);
+        } else {
+            self.print_outer_attributes(attrs);
+        }
+
+        self.ibox(INDENT_UNIT);
+        self.ann.pre(self, AnnNode::Expr(expr));
+        match expr.kind {
+            ast::ExprKind::Box(ref expr) => {
+                self.word_space("box");
+                self.print_expr_maybe_paren(expr, parser::PREC_PREFIX);
+            }
+            ast::ExprKind::Array(ref exprs) => {
+                self.print_expr_vec(exprs);
+            }
+            ast::ExprKind::ConstBlock(ref anon_const) => {
+                self.print_expr_anon_const(anon_const);
+            }
+            ast::ExprKind::Repeat(ref element, ref count) => {
+                self.print_expr_repeat(element, count);
+            }
+            ast::ExprKind::Struct(ref se) => {
+                self.print_expr_struct(&se.qself, &se.path, &se.fields, &se.rest);
+            }
+            ast::ExprKind::Tup(ref exprs) => {
+                self.print_expr_tup(exprs);
+            }
+            ast::ExprKind::Call(ref func, ref args) => {
+                self.print_expr_call(func, &args);
+            }
+            ast::ExprKind::MethodCall(ref segment, ref args, _) => {
+                self.print_expr_method_call(segment, &args);
+            }
+            ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
+                self.print_expr_binary(op, lhs, rhs);
+            }
+            ast::ExprKind::Unary(op, ref expr) => {
+                self.print_expr_unary(op, expr);
+            }
+            ast::ExprKind::AddrOf(k, m, ref expr) => {
+                self.print_expr_addr_of(k, m, expr);
+            }
+            ast::ExprKind::Lit(ref lit) => {
+                self.print_literal(lit);
+            }
+            ast::ExprKind::Cast(ref expr, ref ty) => {
+                let prec = AssocOp::As.precedence() as i8;
+                self.print_expr_maybe_paren(expr, prec);
+                self.space();
+                self.word_space("as");
+                self.print_type(ty);
+            }
+            ast::ExprKind::Type(ref expr, ref ty) => {
+                let prec = AssocOp::Colon.precedence() as i8;
+                self.print_expr_maybe_paren(expr, prec);
+                self.word_space(":");
+                self.print_type(ty);
+            }
+            ast::ExprKind::Let(ref pat, ref scrutinee, _) => {
+                self.print_let(pat, scrutinee);
+            }
+            ast::ExprKind::If(ref test, ref blk, ref elseopt) => {
+                self.print_if(test, blk, elseopt.as_deref())
+            }
+            ast::ExprKind::While(ref test, ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                self.head("while");
+                self.print_expr_as_cond(test);
+                self.space();
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::ForLoop(ref pat, ref iter, ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                self.head("for");
+                self.print_pat(pat);
+                self.space();
+                self.word_space("in");
+                self.print_expr_as_cond(iter);
+                self.space();
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Loop(ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                self.head("loop");
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Match(ref expr, ref arms) => {
+                self.cbox(INDENT_UNIT);
+                self.ibox(INDENT_UNIT);
+                self.word_nbsp("match");
+                self.print_expr_as_cond(expr);
+                self.space();
+                self.bopen();
+                self.print_inner_attributes_no_trailing_hardbreak(attrs);
+                for arm in arms {
+                    self.print_arm(arm);
+                }
+                let empty = attrs.is_empty() && arms.is_empty();
+                self.bclose(expr.span, empty);
+            }
+            ast::ExprKind::Closure(
+                capture_clause,
+                asyncness,
+                movability,
+                ref decl,
+                ref body,
+                _,
+            ) => {
+                self.print_movability(movability);
+                self.print_asyncness(asyncness);
+                self.print_capture_clause(capture_clause);
+
+                self.print_fn_params_and_ret(decl, true);
+                self.space();
+                self.print_expr(body);
+                self.end(); // need to close a box
+
+                // a box will be closed by print_expr, but we didn't want an overall
+                // wrapper so we closed the corresponding opening. so create an
+                // empty box to satisfy the close.
+                self.ibox(0);
+            }
+            ast::ExprKind::Block(ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+                // containing cbox, will be closed by print-block at }
+                self.cbox(INDENT_UNIT);
+                // head-box, will be closed by print-block after {
+                self.ibox(0);
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Async(capture_clause, _, ref blk) => {
+                self.word_nbsp("async");
+                self.print_capture_clause(capture_clause);
+                // cbox/ibox in analogy to the `ExprKind::Block` arm above
+                self.cbox(INDENT_UNIT);
+                self.ibox(0);
+                self.print_block_with_attrs(blk, attrs);
+            }
+            ast::ExprKind::Await(ref expr) => {
+                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+                self.word(".await");
+            }
+            ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
+                let prec = AssocOp::Assign.precedence() as i8;
+                self.print_expr_maybe_paren(lhs, prec + 1);
+                self.space();
+                self.word_space("=");
+                self.print_expr_maybe_paren(rhs, prec);
+            }
+            ast::ExprKind::AssignOp(op, ref lhs, ref rhs) => {
+                let prec = AssocOp::Assign.precedence() as i8;
+                self.print_expr_maybe_paren(lhs, prec + 1);
+                self.space();
+                self.word(op.node.to_string());
+                self.word_space("=");
+                self.print_expr_maybe_paren(rhs, prec);
+            }
+            ast::ExprKind::Field(ref expr, ident) => {
+                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+                self.word(".");
+                self.print_ident(ident);
+            }
+            ast::ExprKind::Index(ref expr, ref index) => {
+                self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
+                self.word("[");
+                self.print_expr(index);
+                self.word("]");
+            }
+            ast::ExprKind::Range(ref start, ref end, limits) => {
+                // Special case for `Range`.  `AssocOp` claims that `Range` has higher precedence
+                // than `Assign`, but `x .. x = x` gives a parse error instead of `x .. (x = x)`.
+                // Here we use a fake precedence value so that any child with lower precedence than
+                // a "normal" binop gets parenthesized.  (`LOr` is the lowest-precedence binop.)
+                let fake_prec = AssocOp::LOr.precedence() as i8;
+                if let Some(ref e) = *start {
+                    self.print_expr_maybe_paren(e, fake_prec);
+                }
+                if limits == ast::RangeLimits::HalfOpen {
+                    self.word("..");
+                } else {
+                    self.word("..=");
+                }
+                if let Some(ref e) = *end {
+                    self.print_expr_maybe_paren(e, fake_prec);
+                }
+            }
+            ast::ExprKind::Underscore => self.word("_"),
+            ast::ExprKind::Path(None, ref path) => self.print_path(path, true, 0),
+            ast::ExprKind::Path(Some(ref qself), ref path) => self.print_qpath(path, qself, true),
+            ast::ExprKind::Break(opt_label, ref opt_expr) => {
+                self.word("break");
+                if let Some(label) = opt_label {
+                    self.space();
+                    self.print_ident(label.ident);
+                }
+                if let Some(ref expr) = *opt_expr {
+                    self.space();
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+                }
+            }
+            ast::ExprKind::Continue(opt_label) => {
+                self.word("continue");
+                if let Some(label) = opt_label {
+                    self.space();
+                    self.print_ident(label.ident);
+                }
+            }
+            ast::ExprKind::Ret(ref result) => {
+                self.word("return");
+                if let Some(ref expr) = *result {
+                    self.word(" ");
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+                }
+            }
+            ast::ExprKind::InlineAsm(ref a) => {
+                self.word("asm!");
+                self.print_inline_asm(a);
+            }
+            ast::ExprKind::MacCall(ref m) => self.print_mac(m),
+            ast::ExprKind::Paren(ref e) => {
+                self.popen();
+                self.print_expr(e);
+                self.pclose();
+            }
+            ast::ExprKind::Yield(ref e) => {
+                self.word("yield");
+
+                if let Some(ref expr) = *e {
+                    self.space();
+                    self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
+                }
+            }
+            ast::ExprKind::Try(ref e) => {
+                self.print_expr_maybe_paren(e, parser::PREC_POSTFIX);
+                self.word("?")
+            }
+            ast::ExprKind::TryBlock(ref blk) => {
+                self.head("try");
+                self.print_block_with_attrs(blk, attrs)
+            }
+            ast::ExprKind::Err => {
+                self.popen();
+                self.word("/*ERROR*/");
+                self.pclose()
+            }
+        }
+        self.ann.post(self, AnnNode::Expr(expr));
+        self.end();
+    }
+
+    fn print_arm(&mut self, arm: &ast::Arm) {
+        // Note, I have no idea why this check is necessary, but here it is.
+        if arm.attrs.is_empty() {
+            self.space();
+        }
+        self.cbox(INDENT_UNIT);
+        self.ibox(0);
+        self.maybe_print_comment(arm.pat.span.lo());
+        self.print_outer_attributes(&arm.attrs);
+        self.print_pat(&arm.pat);
+        self.space();
+        if let Some(ref e) = arm.guard {
+            self.word_space("if");
+            self.print_expr(e);
+            self.space();
+        }
+        self.word_space("=>");
+
+        match arm.body.kind {
+            ast::ExprKind::Block(ref blk, opt_label) => {
+                if let Some(label) = opt_label {
+                    self.print_ident(label.ident);
+                    self.word_space(":");
+                }
+
+                // The block will close the pattern's ibox.
+                self.print_block_unclosed_indent(blk);
+
+                // If it is a user-provided unsafe block, print a comma after it.
+                if let BlockCheckMode::Unsafe(ast::UserProvided) = blk.rules {
+                    self.word(",");
+                }
+            }
+            _ => {
+                self.end(); // Close the ibox for the pattern.
+                self.print_expr(&arm.body);
+                self.word(",");
+            }
+        }
+        self.end(); // Close enclosing cbox.
+    }
+
+    fn print_movability(&mut self, movability: ast::Movability) {
+        match movability {
+            ast::Movability::Static => self.word_space("static"),
+            ast::Movability::Movable => {}
+        }
+    }
+
+    fn print_capture_clause(&mut self, capture_clause: ast::CaptureBy) {
+        match capture_clause {
+            ast::CaptureBy::Value => self.word_space("move"),
+            ast::CaptureBy::Ref => {}
+        }
+    }
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
new file mode 100644 (file)
index 0000000..c756b94
--- /dev/null
@@ -0,0 +1,644 @@
+use crate::pp::Breaks::Inconsistent;
+use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+
+use rustc_ast as ast;
+use rustc_ast::GenericBound;
+use rustc_ast::ModKind;
+use rustc_span::symbol::Ident;
+
+fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String {
+    format!("{}{}", State::to_string(|s| s.print_visibility(vis)), s)
+}
+
+impl<'a> State<'a> {
+    fn print_foreign_mod(&mut self, nmod: &ast::ForeignMod, attrs: &[ast::Attribute]) {
+        self.print_inner_attributes(attrs);
+        for item in &nmod.items {
+            self.print_foreign_item(item);
+        }
+    }
+
+    fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
+        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
+        self.ann.pre(self, AnnNode::SubItem(id));
+        self.hardbreak_if_not_bol();
+        self.maybe_print_comment(span.lo());
+        self.print_outer_attributes(attrs);
+        match kind {
+            ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
+                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
+            }
+            ast::ForeignItemKind::Static(ty, mutbl, body) => {
+                let def = ast::Defaultness::Final;
+                self.print_item_const(ident, Some(*mutbl), ty, body.as_deref(), vis, def);
+            }
+            ast::ForeignItemKind::TyAlias(box ast::TyAlias {
+                defaultness,
+                generics,
+                bounds,
+                ty,
+            }) => {
+                self.print_associated_type(
+                    ident,
+                    generics,
+                    bounds,
+                    ty.as_deref(),
+                    vis,
+                    *defaultness,
+                );
+            }
+            ast::ForeignItemKind::MacCall(m) => {
+                self.print_mac(m);
+                if m.args.need_semicolon() {
+                    self.word(";");
+                }
+            }
+        }
+        self.ann.post(self, AnnNode::SubItem(id))
+    }
+
+    fn print_item_const(
+        &mut self,
+        ident: Ident,
+        mutbl: Option<ast::Mutability>,
+        ty: &ast::Ty,
+        body: Option<&ast::Expr>,
+        vis: &ast::Visibility,
+        defaultness: ast::Defaultness,
+    ) {
+        self.head("");
+        self.print_visibility(vis);
+        self.print_defaultness(defaultness);
+        let leading = match mutbl {
+            None => "const",
+            Some(ast::Mutability::Not) => "static",
+            Some(ast::Mutability::Mut) => "static mut",
+        };
+        self.word_space(leading);
+        self.print_ident(ident);
+        self.word_space(":");
+        self.print_type(ty);
+        if body.is_some() {
+            self.space();
+        }
+        self.end(); // end the head-ibox
+        if let Some(body) = body {
+            self.word_space("=");
+            self.print_expr(body);
+        }
+        self.word(";");
+        self.end(); // end the outer cbox
+    }
+
+    fn print_associated_type(
+        &mut self,
+        ident: Ident,
+        generics: &ast::Generics,
+        bounds: &ast::GenericBounds,
+        ty: Option<&ast::Ty>,
+        vis: &ast::Visibility,
+        defaultness: ast::Defaultness,
+    ) {
+        self.head("");
+        self.print_visibility(vis);
+        self.print_defaultness(defaultness);
+        self.word_space("type");
+        self.print_ident(ident);
+        self.print_generic_params(&generics.params);
+        self.print_type_bounds(":", bounds);
+        self.print_where_clause(&generics.where_clause);
+        if let Some(ty) = ty {
+            self.space();
+            self.word_space("=");
+            self.print_type(ty);
+        }
+        self.word(";");
+        self.end(); // end inner head-block
+        self.end(); // end outer head-block
+    }
+
+    /// Pretty-prints an item.
+    crate fn print_item(&mut self, item: &ast::Item) {
+        self.hardbreak_if_not_bol();
+        self.maybe_print_comment(item.span.lo());
+        self.print_outer_attributes(&item.attrs);
+        self.ann.pre(self, AnnNode::Item(item));
+        match item.kind {
+            ast::ItemKind::ExternCrate(orig_name) => {
+                self.head(visibility_qualified(&item.vis, "extern crate"));
+                if let Some(orig_name) = orig_name {
+                    self.print_name(orig_name);
+                    self.space();
+                    self.word("as");
+                    self.space();
+                }
+                self.print_ident(item.ident);
+                self.word(";");
+                self.end(); // end inner head-block
+                self.end(); // end outer head-block
+            }
+            ast::ItemKind::Use(ref tree) => {
+                self.head(visibility_qualified(&item.vis, "use"));
+                self.print_use_tree(tree);
+                self.word(";");
+                self.end(); // end inner head-block
+                self.end(); // end outer head-block
+            }
+            ast::ItemKind::Static(ref ty, mutbl, ref body) => {
+                let def = ast::Defaultness::Final;
+                self.print_item_const(item.ident, Some(mutbl), ty, body.as_deref(), &item.vis, def);
+            }
+            ast::ItemKind::Const(def, ref ty, ref body) => {
+                self.print_item_const(item.ident, None, ty, body.as_deref(), &item.vis, def);
+            }
+            ast::ItemKind::Fn(box ast::Fn { defaultness, ref sig, ref generics, ref body }) => {
+                let body = body.as_deref();
+                self.print_fn_full(
+                    sig,
+                    item.ident,
+                    generics,
+                    &item.vis,
+                    defaultness,
+                    body,
+                    &item.attrs,
+                );
+            }
+            ast::ItemKind::Mod(unsafety, ref mod_kind) => {
+                self.head(Self::to_string(|s| {
+                    s.print_visibility(&item.vis);
+                    s.print_unsafety(unsafety);
+                    s.word("mod");
+                }));
+                self.print_ident(item.ident);
+
+                match mod_kind {
+                    ModKind::Loaded(items, ..) => {
+                        self.nbsp();
+                        self.bopen();
+                        self.print_inner_attributes(&item.attrs);
+                        for item in items {
+                            self.print_item(item);
+                        }
+                        let empty = item.attrs.is_empty() && items.is_empty();
+                        self.bclose(item.span, empty);
+                    }
+                    ModKind::Unloaded => {
+                        self.word(";");
+                        self.end(); // end inner head-block
+                        self.end(); // end outer head-block
+                    }
+                }
+            }
+            ast::ItemKind::ForeignMod(ref nmod) => {
+                self.head(Self::to_string(|s| {
+                    s.print_unsafety(nmod.unsafety);
+                    s.word("extern");
+                }));
+                if let Some(abi) = nmod.abi {
+                    self.print_literal(&abi.as_lit());
+                    self.nbsp();
+                }
+                self.bopen();
+                self.print_foreign_mod(nmod, &item.attrs);
+                let empty = item.attrs.is_empty() && nmod.items.is_empty();
+                self.bclose(item.span, empty);
+            }
+            ast::ItemKind::GlobalAsm(ref asm) => {
+                self.head(visibility_qualified(&item.vis, "global_asm!"));
+                self.print_inline_asm(asm);
+                self.end();
+            }
+            ast::ItemKind::TyAlias(box ast::TyAlias {
+                defaultness,
+                ref generics,
+                ref bounds,
+                ref ty,
+            }) => {
+                let ty = ty.as_deref();
+                self.print_associated_type(
+                    item.ident,
+                    generics,
+                    bounds,
+                    ty,
+                    &item.vis,
+                    defaultness,
+                );
+            }
+            ast::ItemKind::Enum(ref enum_definition, ref params) => {
+                self.print_enum_def(enum_definition, params, item.ident, item.span, &item.vis);
+            }
+            ast::ItemKind::Struct(ref struct_def, ref generics) => {
+                self.head(visibility_qualified(&item.vis, "struct"));
+                self.print_struct(struct_def, generics, item.ident, item.span, true);
+            }
+            ast::ItemKind::Union(ref struct_def, ref generics) => {
+                self.head(visibility_qualified(&item.vis, "union"));
+                self.print_struct(struct_def, generics, item.ident, item.span, true);
+            }
+            ast::ItemKind::Impl(box ast::Impl {
+                unsafety,
+                polarity,
+                defaultness,
+                constness,
+                ref generics,
+                ref of_trait,
+                ref self_ty,
+                ref items,
+            }) => {
+                self.head("");
+                self.print_visibility(&item.vis);
+                self.print_defaultness(defaultness);
+                self.print_unsafety(unsafety);
+                self.word("impl");
+
+                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("!");
+                }
+
+                if let Some(ref t) = *of_trait {
+                    self.print_trait_ref(t);
+                    self.space();
+                    self.word_space("for");
+                }
+
+                self.print_type(self_ty);
+                self.print_where_clause(&generics.where_clause);
+
+                self.space();
+                self.bopen();
+                self.print_inner_attributes(&item.attrs);
+                for impl_item in items {
+                    self.print_assoc_item(impl_item);
+                }
+                let empty = item.attrs.is_empty() && items.is_empty();
+                self.bclose(item.span, empty);
+            }
+            ast::ItemKind::Trait(box ast::Trait {
+                is_auto,
+                unsafety,
+                ref generics,
+                ref bounds,
+                ref items,
+                ..
+            }) => {
+                self.head("");
+                self.print_visibility(&item.vis);
+                self.print_unsafety(unsafety);
+                self.print_is_auto(is_auto);
+                self.word_nbsp("trait");
+                self.print_ident(item.ident);
+                self.print_generic_params(&generics.params);
+                let mut real_bounds = Vec::with_capacity(bounds.len());
+                for b in bounds.iter() {
+                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+                        self.space();
+                        self.word_space("for ?");
+                        self.print_trait_ref(&ptr.trait_ref);
+                    } else {
+                        real_bounds.push(b.clone());
+                    }
+                }
+                self.print_type_bounds(":", &real_bounds);
+                self.print_where_clause(&generics.where_clause);
+                self.word(" ");
+                self.bopen();
+                self.print_inner_attributes(&item.attrs);
+                for trait_item in items {
+                    self.print_assoc_item(trait_item);
+                }
+                let empty = item.attrs.is_empty() && items.is_empty();
+                self.bclose(item.span, empty);
+            }
+            ast::ItemKind::TraitAlias(ref generics, ref bounds) => {
+                self.head(visibility_qualified(&item.vis, "trait"));
+                self.print_ident(item.ident);
+                self.print_generic_params(&generics.params);
+                let mut real_bounds = Vec::with_capacity(bounds.len());
+                // FIXME(durka) this seems to be some quite outdated syntax
+                for b in bounds.iter() {
+                    if let GenericBound::Trait(ref ptr, ast::TraitBoundModifier::Maybe) = *b {
+                        self.space();
+                        self.word_space("for ?");
+                        self.print_trait_ref(&ptr.trait_ref);
+                    } else {
+                        real_bounds.push(b.clone());
+                    }
+                }
+                self.nbsp();
+                self.print_type_bounds("=", &real_bounds);
+                self.print_where_clause(&generics.where_clause);
+                self.word(";");
+                self.end(); // end inner head-block
+                self.end(); // end outer head-block
+            }
+            ast::ItemKind::MacCall(ref mac) => {
+                self.print_mac(mac);
+                if mac.args.need_semicolon() {
+                    self.word(";");
+                }
+            }
+            ast::ItemKind::MacroDef(ref macro_def) => {
+                self.print_mac_def(macro_def, &item.ident, &item.span, |state| {
+                    state.print_visibility(&item.vis)
+                });
+            }
+        }
+        self.ann.post(self, AnnNode::Item(item))
+    }
+
+    fn print_enum_def(
+        &mut self,
+        enum_definition: &ast::EnumDef,
+        generics: &ast::Generics,
+        ident: Ident,
+        span: rustc_span::Span,
+        visibility: &ast::Visibility,
+    ) {
+        self.head(visibility_qualified(visibility, "enum"));
+        self.print_ident(ident);
+        self.print_generic_params(&generics.params);
+        self.print_where_clause(&generics.where_clause);
+        self.space();
+        self.print_variants(&enum_definition.variants, span)
+    }
+
+    fn print_variants(&mut self, variants: &[ast::Variant], span: rustc_span::Span) {
+        self.bopen();
+        for v in variants {
+            self.space_if_not_bol();
+            self.maybe_print_comment(v.span.lo());
+            self.print_outer_attributes(&v.attrs);
+            self.ibox(INDENT_UNIT);
+            self.print_variant(v);
+            self.word(",");
+            self.end();
+            self.maybe_print_trailing_comment(v.span, None);
+        }
+        let empty = variants.is_empty();
+        self.bclose(span, empty)
+    }
+
+    crate fn print_visibility(&mut self, vis: &ast::Visibility) {
+        match vis.kind {
+            ast::VisibilityKind::Public => self.word_nbsp("pub"),
+            ast::VisibilityKind::Crate(sugar) => match sugar {
+                ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"),
+                ast::CrateSugar::JustCrate => self.word_nbsp("crate"),
+            },
+            ast::VisibilityKind::Restricted { ref path, .. } => {
+                let path = Self::to_string(|s| s.print_path(path, false, 0));
+                if path == "self" || path == "super" {
+                    self.word_nbsp(format!("pub({})", path))
+                } else {
+                    self.word_nbsp(format!("pub(in {})", path))
+                }
+            }
+            ast::VisibilityKind::Inherited => {}
+        }
+    }
+
+    fn print_defaultness(&mut self, defaultness: ast::Defaultness) {
+        if let ast::Defaultness::Default(_) = defaultness {
+            self.word_nbsp("default");
+        }
+    }
+
+    fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) {
+        self.nbsp();
+        self.bopen();
+
+        let empty = fields.is_empty();
+        if !empty {
+            self.hardbreak_if_not_bol();
+
+            for field in fields {
+                self.hardbreak_if_not_bol();
+                self.maybe_print_comment(field.span.lo());
+                self.print_outer_attributes(&field.attrs);
+                self.print_visibility(&field.vis);
+                self.print_ident(field.ident.unwrap());
+                self.word_nbsp(":");
+                self.print_type(&field.ty);
+                self.word(",");
+            }
+        }
+
+        self.bclose(span, empty);
+    }
+
+    fn print_struct(
+        &mut self,
+        struct_def: &ast::VariantData,
+        generics: &ast::Generics,
+        ident: Ident,
+        span: rustc_span::Span,
+        print_finalizer: bool,
+    ) {
+        self.print_ident(ident);
+        self.print_generic_params(&generics.params);
+        match struct_def {
+            ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
+                if let ast::VariantData::Tuple(..) = struct_def {
+                    self.popen();
+                    self.commasep(Inconsistent, struct_def.fields(), |s, field| {
+                        s.maybe_print_comment(field.span.lo());
+                        s.print_outer_attributes(&field.attrs);
+                        s.print_visibility(&field.vis);
+                        s.print_type(&field.ty)
+                    });
+                    self.pclose();
+                }
+                self.print_where_clause(&generics.where_clause);
+                if print_finalizer {
+                    self.word(";");
+                }
+                self.end();
+                self.end(); // Close the outer-box.
+            }
+            ast::VariantData::Struct(ref fields, ..) => {
+                self.print_where_clause(&generics.where_clause);
+                self.print_record_struct_body(fields, span);
+            }
+        }
+    }
+
+    crate fn print_variant(&mut self, v: &ast::Variant) {
+        self.head("");
+        self.print_visibility(&v.vis);
+        let generics = ast::Generics::default();
+        self.print_struct(&v.data, &generics, v.ident, v.span, false);
+        if let Some(ref d) = v.disr_expr {
+            self.space();
+            self.word_space("=");
+            self.print_expr(&d.value)
+        }
+    }
+
+    fn print_assoc_item(&mut self, item: &ast::AssocItem) {
+        let ast::Item { id, span, ident, ref attrs, ref kind, ref vis, tokens: _ } = *item;
+        self.ann.pre(self, AnnNode::SubItem(id));
+        self.hardbreak_if_not_bol();
+        self.maybe_print_comment(span.lo());
+        self.print_outer_attributes(attrs);
+        match kind {
+            ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
+                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
+            }
+            ast::AssocItemKind::Const(def, ty, body) => {
+                self.print_item_const(ident, None, ty, body.as_deref(), vis, *def);
+            }
+            ast::AssocItemKind::TyAlias(box ast::TyAlias { defaultness, generics, bounds, ty }) => {
+                self.print_associated_type(
+                    ident,
+                    generics,
+                    bounds,
+                    ty.as_deref(),
+                    vis,
+                    *defaultness,
+                );
+            }
+            ast::AssocItemKind::MacCall(m) => {
+                self.print_mac(m);
+                if m.args.need_semicolon() {
+                    self.word(";");
+                }
+            }
+        }
+        self.ann.post(self, AnnNode::SubItem(id))
+    }
+
+    fn print_fn_full(
+        &mut self,
+        sig: &ast::FnSig,
+        name: Ident,
+        generics: &ast::Generics,
+        vis: &ast::Visibility,
+        defaultness: ast::Defaultness,
+        body: Option<&ast::Block>,
+        attrs: &[ast::Attribute],
+    ) {
+        if body.is_some() {
+            self.head("");
+        }
+        self.print_visibility(vis);
+        self.print_defaultness(defaultness);
+        self.print_fn(&sig.decl, sig.header, Some(name), generics);
+        if let Some(body) = body {
+            self.nbsp();
+            self.print_block_with_attrs(body, attrs);
+        } else {
+            self.word(";");
+        }
+    }
+
+    crate fn print_fn(
+        &mut self,
+        decl: &ast::FnDecl,
+        header: ast::FnHeader,
+        name: Option<Ident>,
+        generics: &ast::Generics,
+    ) {
+        self.print_fn_header_info(header);
+        if let Some(name) = name {
+            self.nbsp();
+            self.print_ident(name);
+        }
+        self.print_generic_params(&generics.params);
+        self.print_fn_params_and_ret(decl, false);
+        self.print_where_clause(&generics.where_clause)
+    }
+
+    crate fn print_fn_params_and_ret(&mut self, decl: &ast::FnDecl, is_closure: bool) {
+        let (open, close) = if is_closure { ("|", "|") } else { ("(", ")") };
+        self.word(open);
+        self.commasep(Inconsistent, &decl.inputs, |s, param| s.print_param(param, is_closure));
+        self.word(close);
+        self.print_fn_ret_ty(&decl.output)
+    }
+
+    fn print_where_clause(&mut self, where_clause: &ast::WhereClause) {
+        if where_clause.predicates.is_empty() && !where_clause.has_where_token {
+            return;
+        }
+
+        self.space();
+        self.word_space("where");
+
+        for (i, predicate) in where_clause.predicates.iter().enumerate() {
+            if i != 0 {
+                self.word_space(",");
+            }
+
+            self.print_where_predicate(predicate);
+        }
+    }
+
+    pub fn print_where_predicate(&mut self, predicate: &ast::WherePredicate) {
+        match predicate {
+            ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
+                bound_generic_params,
+                bounded_ty,
+                bounds,
+                ..
+            }) => {
+                self.print_formal_generic_params(bound_generic_params);
+                self.print_type(bounded_ty);
+                self.print_type_bounds(":", bounds);
+            }
+            ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
+                lifetime,
+                bounds,
+                ..
+            }) => {
+                self.print_lifetime_bounds(*lifetime, bounds);
+            }
+            ast::WherePredicate::EqPredicate(ast::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => {
+                self.print_type(lhs_ty);
+                self.space();
+                self.word_space("=");
+                self.print_type(rhs_ty);
+            }
+        }
+    }
+
+    fn print_use_tree(&mut self, tree: &ast::UseTree) {
+        match tree.kind {
+            ast::UseTreeKind::Simple(rename, ..) => {
+                self.print_path(&tree.prefix, false, 0);
+                if let Some(rename) = rename {
+                    self.space();
+                    self.word_space("as");
+                    self.print_ident(rename);
+                }
+            }
+            ast::UseTreeKind::Glob => {
+                if !tree.prefix.segments.is_empty() {
+                    self.print_path(&tree.prefix, false, 0);
+                    self.word("::");
+                }
+                self.word("*");
+            }
+            ast::UseTreeKind::Nested(ref items) => {
+                if tree.prefix.segments.is_empty() {
+                    self.word("{");
+                } else {
+                    self.print_path(&tree.prefix, false, 0);
+                    self.word("::{");
+                }
+                self.commasep(Inconsistent, &items, |this, &(ref tree, _)| {
+                    this.print_use_tree(tree)
+                });
+                self.word("}");
+            }
+        }
+    }
+}
index 15372ec1534fe164fb6d9f162a27e46c7eada66c..f0036f09c3881fccb3af7fccd7025e3b68c70db0 100644 (file)
@@ -8,7 +8,6 @@
 use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
 use rustc_mir_dataflow::{Analysis, Direction, Results};
 use std::fmt;
-use std::iter;
 
 use crate::{
     places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid,
@@ -385,14 +384,6 @@ fn statement_effect(
                 self.kill_borrows_on_place(trans, Place::from(local));
             }
 
-            mir::StatementKind::LlvmInlineAsm(ref asm) => {
-                for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
-                    if !kind.is_indirect && !kind.is_rw {
-                        self.kill_borrows_on_place(trans, *output);
-                    }
-                }
-            }
-
             mir::StatementKind::FakeRead(..)
             | mir::StatementKind::SetDiscriminant { .. }
             | mir::StatementKind::StorageLive(..)
index 70acbc9ee2dbc4024fd77bd4504ca8ef3ea0a1b7..eec994f88b96e3500ab57a9f125e8f243a92ecc5 100644 (file)
@@ -16,9 +16,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
 
         PlaceContext::MutatingUse(MutatingUseContext::Store) |
 
-        // This is potentially both a def and a use...
-        PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput) |
-
         // We let Call define the result in both the success and
         // unwind cases. This is not really correct, however it
         // does not seem to be observable due to the way that we
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..01cc72121c7d4d5cfc9ad03787ee2f363578c12b 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")
@@ -779,7 +779,10 @@ fn get_future_inner_return_ty(&self, hir_ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::
                                     [
                                         hir::TypeBinding {
                                             ident: Ident { name: sym::Output, .. },
-                                            kind: hir::TypeBindingKind::Equality { ty },
+                                            kind:
+                                                hir::TypeBindingKind::Equality {
+                                                    term: hir::Term::Ty(ty),
+                                                },
                                             ..
                                         },
                                     ],
index c03e4d8a448900996b3091e97993b474fc431fef..73ced63e4d75075ce517f7387f5ecaf22249d0eb 100644 (file)
@@ -5,12 +5,11 @@
 use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
 use rustc_middle::mir::{Statement, StatementKind};
 use rustc_middle::ty::TyCtxt;
-use std::iter;
 
 use crate::{
     borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth,
-    Activation, ArtificialField, BorrowIndex, Deep, JustWrite, LocalMutationIsAllowed, MutateMode,
-    Read, ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteAndRead, WriteKind,
+    Activation, ArtificialField, BorrowIndex, Deep, LocalMutationIsAllowed, Read, ReadKind,
+    ReadOrWrite, Reservation, Shallow, Write, WriteKind,
 };
 
 pub(super) fn generate_invalidates<'tcx>(
@@ -59,37 +58,13 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             StatementKind::Assign(box (lhs, rhs)) => {
                 self.consume_rvalue(location, rhs);
 
-                self.mutate_place(location, *lhs, Shallow(None), JustWrite);
+                self.mutate_place(location, *lhs, Shallow(None));
             }
             StatementKind::FakeRead(box (_, _)) => {
                 // Only relevant for initialized/liveness/safety checks.
             }
             StatementKind::SetDiscriminant { place, variant_index: _ } => {
-                self.mutate_place(location, **place, Shallow(None), JustWrite);
-            }
-            StatementKind::LlvmInlineAsm(asm) => {
-                for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
-                    if o.is_indirect {
-                        // FIXME(eddyb) indirect inline asm outputs should
-                        // be encoded through MIR place derefs instead.
-                        self.access_place(
-                            location,
-                            *output,
-                            (Deep, Read(ReadKind::Copy)),
-                            LocalMutationIsAllowed::No,
-                        );
-                    } else {
-                        self.mutate_place(
-                            location,
-                            *output,
-                            if o.is_rw { Deep } else { Shallow(None) },
-                            if o.is_rw { WriteAndRead } else { JustWrite },
-                        );
-                    }
-                }
-                for (_, input) in asm.inputs.iter() {
-                    self.consume_operand(location, input);
-                }
+                self.mutate_place(location, **place, Shallow(None));
             }
             StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
                 ref src,
@@ -142,7 +117,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                 target: _,
                 unwind: _,
             } => {
-                self.mutate_place(location, *drop_place, Deep, JustWrite);
+                self.mutate_place(location, *drop_place, Deep);
                 self.consume_operand(location, new_value);
             }
             TerminatorKind::Call {
@@ -158,7 +133,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     self.consume_operand(location, arg);
                 }
                 if let Some((dest, _ /*bb*/)) = destination {
-                    self.mutate_place(location, *dest, Deep, JustWrite);
+                    self.mutate_place(location, *dest, Deep);
                 }
             }
             TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
@@ -181,7 +156,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     }
                 }
 
-                self.mutate_place(location, *resume_arg, Deep, JustWrite);
+                self.mutate_place(location, *resume_arg, Deep);
             }
             TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
                 // Invalidate all borrows of local places
@@ -208,13 +183,13 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                         }
                         InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
                             if let Some(place) = place {
-                                self.mutate_place(location, place, Shallow(None), JustWrite);
+                                self.mutate_place(location, place, Shallow(None));
                             }
                         }
                         InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
                             self.consume_operand(location, in_value);
                             if let Some(out_place) = out_place {
-                                self.mutate_place(location, out_place, Shallow(None), JustWrite);
+                                self.mutate_place(location, out_place, Shallow(None));
                             }
                         }
                         InlineAsmOperand::Const { value: _ }
@@ -238,13 +213,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
 
 impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
     /// Simulates mutation of a place.
-    fn mutate_place(
-        &mut self,
-        location: Location,
-        place: Place<'tcx>,
-        kind: AccessDepth,
-        _mode: MutateMode,
-    ) {
+    fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) {
         self.access_place(
             location,
             place,
index fe34d6e7ca9dde71dcc2c6c7d50f6a85d4dd614c..1e9acb114b7fc46db6632fdadfdcc7c390b3a34d 100644 (file)
@@ -40,7 +40,6 @@
 use smallvec::SmallVec;
 use std::cell::RefCell;
 use std::collections::BTreeMap;
-use std::iter;
 use std::mem;
 use std::rc::Rc;
 
@@ -55,7 +54,6 @@
 use self::diagnostics::{AccessKind, RegionName};
 use self::location::LocationTable;
 use self::prefixes::PrefixSet;
-use self::MutateMode::{JustWrite, WriteAndRead};
 use facts::AllFacts;
 
 use self::path_utils::*;
@@ -186,7 +184,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 }
@@ -630,7 +628,7 @@ fn visit_statement_before_primary_effect(
             StatementKind::Assign(box (lhs, ref rhs)) => {
                 self.consume_rvalue(location, (rhs, span), flow_state);
 
-                self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state);
+                self.mutate_place(location, (*lhs, span), Shallow(None), flow_state);
             }
             StatementKind::FakeRead(box (_, ref place)) => {
                 // Read for match doesn't access any memory and is used to
@@ -651,41 +649,8 @@ fn visit_statement_before_primary_effect(
                 );
             }
             StatementKind::SetDiscriminant { place, variant_index: _ } => {
-                self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state);
+                self.mutate_place(location, (**place, span), Shallow(None), flow_state);
             }
-            StatementKind::LlvmInlineAsm(ref asm) => {
-                for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
-                    if o.is_indirect {
-                        // FIXME(eddyb) indirect inline asm outputs should
-                        // be encoded through MIR place derefs instead.
-                        self.access_place(
-                            location,
-                            (*output, o.span),
-                            (Deep, Read(ReadKind::Copy)),
-                            LocalMutationIsAllowed::No,
-                            flow_state,
-                        );
-                        self.check_if_path_or_subpath_is_moved(
-                            location,
-                            InitializationRequiringAction::Use,
-                            (output.as_ref(), o.span),
-                            flow_state,
-                        );
-                    } else {
-                        self.mutate_place(
-                            location,
-                            (*output, o.span),
-                            if o.is_rw { Deep } else { Shallow(None) },
-                            if o.is_rw { WriteAndRead } else { JustWrite },
-                            flow_state,
-                        );
-                    }
-                }
-                for (_, input) in asm.inputs.iter() {
-                    self.consume_operand(location, (input, span), flow_state);
-                }
-            }
-
             StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
                 ..
             }) => {
@@ -750,7 +715,7 @@ fn visit_terminator_before_primary_effect(
                 target: _,
                 unwind: _,
             } => {
-                self.mutate_place(loc, (drop_place, span), Deep, JustWrite, flow_state);
+                self.mutate_place(loc, (drop_place, span), Deep, flow_state);
                 self.consume_operand(loc, (new_value, span), flow_state);
             }
             TerminatorKind::Call {
@@ -766,7 +731,7 @@ fn visit_terminator_before_primary_effect(
                     self.consume_operand(loc, (arg, span), flow_state);
                 }
                 if let Some((dest, _ /*bb*/)) = *destination {
-                    self.mutate_place(loc, (dest, span), Deep, JustWrite, flow_state);
+                    self.mutate_place(loc, (dest, span), Deep, flow_state);
                 }
             }
             TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
@@ -780,7 +745,7 @@ fn visit_terminator_before_primary_effect(
 
             TerminatorKind::Yield { ref value, resume: _, resume_arg, drop: _ } => {
                 self.consume_operand(loc, (value, span), flow_state);
-                self.mutate_place(loc, (resume_arg, span), Deep, JustWrite, flow_state);
+                self.mutate_place(loc, (resume_arg, span), Deep, flow_state);
             }
 
             TerminatorKind::InlineAsm {
@@ -798,13 +763,7 @@ fn visit_terminator_before_primary_effect(
                         }
                         InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
                             if let Some(place) = place {
-                                self.mutate_place(
-                                    loc,
-                                    (place, span),
-                                    Shallow(None),
-                                    JustWrite,
-                                    flow_state,
-                                );
+                                self.mutate_place(loc, (place, span), Shallow(None), flow_state);
                             }
                         }
                         InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
@@ -814,7 +773,6 @@ fn visit_terminator_before_primary_effect(
                                     loc,
                                     (out_place, span),
                                     Shallow(None),
-                                    JustWrite,
                                     flow_state,
                                 );
                             }
@@ -886,12 +844,6 @@ fn visit_terminator_after_primary_effect(
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum MutateMode {
-    JustWrite,
-    WriteAndRead,
-}
-
 use self::AccessDepth::{Deep, Shallow};
 use self::ReadOrWrite::{Activation, Read, Reservation, Write};
 
@@ -977,7 +929,6 @@ enum LocalMutationIsAllowed {
 
 #[derive(Copy, Clone, Debug)]
 enum InitializationRequiringAction {
-    Update,
     Borrow,
     MatchOn,
     Use,
@@ -994,7 +945,6 @@ struct RootPlace<'tcx> {
 impl InitializationRequiringAction {
     fn as_noun(self) -> &'static str {
         match self {
-            InitializationRequiringAction::Update => "update",
             InitializationRequiringAction::Borrow => "borrow",
             InitializationRequiringAction::MatchOn => "use", // no good noun
             InitializationRequiringAction::Use => "use",
@@ -1005,7 +955,6 @@ fn as_noun(self) -> &'static str {
 
     fn as_verb_in_past_tense(self) -> &'static str {
         match self {
-            InitializationRequiringAction::Update => "updated",
             InitializationRequiringAction::Borrow => "borrowed",
             InitializationRequiringAction::MatchOn => "matched on",
             InitializationRequiringAction::Use => "used",
@@ -1242,23 +1191,10 @@ fn mutate_place(
         location: Location,
         place_span: (Place<'tcx>, Span),
         kind: AccessDepth,
-        mode: MutateMode,
         flow_state: &Flows<'cx, 'tcx>,
     ) {
-        // Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
-        match mode {
-            MutateMode::WriteAndRead => {
-                self.check_if_path_or_subpath_is_moved(
-                    location,
-                    InitializationRequiringAction::Update,
-                    (place_span.0.as_ref(), place_span.1),
-                    flow_state,
-                );
-            }
-            MutateMode::JustWrite => {
-                self.check_if_assigned_path_is_moved(location, place_span, flow_state);
-            }
-        }
+        // Write of P[i] or *P requires P init'd.
+        self.check_if_assigned_path_is_moved(location, place_span, flow_state);
 
         // Special case: you can assign an immutable local variable
         // (e.g., `x = ...`) so long as it has never been initialized
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..b6f5f4998a643b3600a5b836d2ada79f3603cf71 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!(
@@ -1477,7 +1478,6 @@ fn check_stmt(&mut self, body: &Body<'tcx>, stmt: &Statement<'tcx>, location: Lo
             StatementKind::FakeRead(..)
             | StatementKind::StorageLive(..)
             | StatementKind::StorageDead(..)
-            | StatementKind::LlvmInlineAsm { .. }
             | StatementKind::Retag { .. }
             | StatementKind::Coverage(..)
             | StatementKind::Nop => {}
@@ -1969,7 +1969,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..1a6e56947916f41182136d3d9c96f38cc193c701 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>(
@@ -50,15 +50,6 @@ pub fn parse_asm_args<'a>(
         return Err(diag.struct_span_err(sp, "requires at least a template string argument"));
     }
 
-    // Detect use of the legacy llvm_asm! syntax (which used to be called asm!)
-    if !is_global_asm && p.look_ahead(1, |t| *t == token::Colon || *t == token::ModSep) {
-        let mut err =
-            diag.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported");
-        err.note("consider migrating to the new asm! syntax specified in RFC 2873");
-        err.note("alternatively, switch to llvm_asm! to keep your code working as it is");
-        return Err(err);
-    }
-
     let first_template = p.parse_expr()?;
     let mut args = AsmArgs {
         templates: vec![first_template],
index 8c3ef2864f4859b1fe89adb1eab949de16f9c781..65f785b9097e72f0bd7e1506e2c57cdb40445219 100644 (file)
@@ -33,7 +33,6 @@
 mod format;
 mod format_foreign;
 mod global_allocator;
-mod llvm_asm;
 mod log_syntax;
 mod panic;
 mod source_util;
@@ -78,7 +77,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
         include_str: source_util::expand_include_str,
         include: source_util::expand_include,
         line: source_util::expand_line,
-        llvm_asm: llvm_asm::expand_llvm_asm,
         log_syntax: log_syntax::expand_log_syntax,
         module_path: source_util::expand_mod,
         option_env: env::expand_option_env,
diff --git a/compiler/rustc_builtin_macros/src/llvm_asm.rs b/compiler/rustc_builtin_macros/src/llvm_asm.rs
deleted file mode 100644 (file)
index d72bfa6..0000000
+++ /dev/null
@@ -1,303 +0,0 @@
-// Llvm-style inline assembly support.
-//
-use State::*;
-
-use rustc_ast as ast;
-use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Token};
-use rustc_ast::tokenstream::{self, TokenStream};
-use rustc_ast::LlvmAsmDialect;
-use rustc_errors::{struct_span_err, DiagnosticBuilder, PResult};
-use rustc_expand::base::*;
-use rustc_parse::parser::Parser;
-use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::Span;
-
-enum State {
-    Asm,
-    Outputs,
-    Inputs,
-    Clobbers,
-    Options,
-    StateNone,
-}
-
-impl State {
-    fn next(&self) -> State {
-        match *self {
-            Asm => Outputs,
-            Outputs => Inputs,
-            Inputs => Clobbers,
-            Clobbers => Options,
-            Options => StateNone,
-            StateNone => StateNone,
-        }
-    }
-}
-
-const OPTIONS: &[Symbol] = &[sym::volatile, sym::alignstack, sym::intel];
-
-pub fn expand_llvm_asm<'cx>(
-    cx: &'cx mut ExtCtxt<'_>,
-    sp: Span,
-    tts: TokenStream,
-) -> Box<dyn MacResult + 'cx> {
-    let mut inline_asm = match parse_inline_asm(cx, sp, tts) {
-        Ok(Some(inline_asm)) => inline_asm,
-        Ok(None) => return DummyResult::any(sp),
-        Err(mut err) => {
-            err.emit();
-            return DummyResult::any(sp);
-        }
-    };
-
-    // If there are no outputs, the inline assembly is executed just for its side effects,
-    // so ensure that it is volatile
-    if inline_asm.outputs.is_empty() {
-        inline_asm.volatile = true;
-    }
-
-    MacEager::expr(P(ast::Expr {
-        id: ast::DUMMY_NODE_ID,
-        kind: ast::ExprKind::LlvmInlineAsm(P(inline_asm)),
-        span: cx.with_def_site_ctxt(sp),
-        attrs: ast::AttrVec::new(),
-        tokens: None,
-    }))
-}
-
-fn parse_asm_str<'a>(p: &mut Parser<'a>) -> PResult<'a, Symbol> {
-    match p.parse_str_lit() {
-        Ok(str_lit) => Ok(str_lit.symbol_unescaped),
-        Err(opt_lit) => {
-            let span = opt_lit.map_or(p.token.span, |lit| lit.span);
-            let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
-            err.span_label(span, "not a string literal");
-            Err(err)
-        }
-    }
-}
-
-fn parse_inline_asm<'a>(
-    cx: &mut ExtCtxt<'a>,
-    sp: Span,
-    tts: TokenStream,
-) -> Result<Option<ast::LlvmInlineAsm>, DiagnosticBuilder<'a>> {
-    // Split the tts before the first colon, to avoid `llvm_asm!("x": y)`  being
-    // parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription.
-    let first_colon = tts
-        .trees()
-        .position(|tt| {
-            matches!(
-                tt,
-                tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. })
-            )
-        })
-        .unwrap_or(tts.len());
-    let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect());
-    let mut asm = kw::Empty;
-    let mut asm_str_style = None;
-    let mut outputs = Vec::new();
-    let mut inputs = Vec::new();
-    let mut clobs = Vec::new();
-    let mut volatile = false;
-    let mut alignstack = false;
-    let mut dialect = LlvmAsmDialect::Att;
-
-    let mut state = Asm;
-
-    'statement: loop {
-        match state {
-            Asm => {
-                if asm_str_style.is_some() {
-                    // If we already have a string with instructions,
-                    // ending up in Asm state again is an error.
-                    return Err(struct_span_err!(
-                        cx.sess.parse_sess.span_diagnostic,
-                        sp,
-                        E0660,
-                        "malformed inline assembly"
-                    ));
-                }
-                // Nested parser, stop before the first colon (see above).
-                let mut p2 = cx.new_parser_from_tts(tts.trees().take(first_colon).collect());
-
-                if p2.token == token::Eof {
-                    let mut err =
-                        cx.struct_span_err(sp, "macro requires a string literal as an argument");
-                    err.span_label(sp, "string literal required");
-                    return Err(err);
-                }
-
-                let expr = p2.parse_expr()?;
-                let (s, style) =
-                    match expr_to_string(cx, expr, "inline assembly must be a string literal") {
-                        Some((s, st)) => (s, st),
-                        None => return Ok(None),
-                    };
-
-                // This is most likely malformed.
-                if p2.token != token::Eof {
-                    let mut extra_tts = p2.parse_all_token_trees()?;
-                    extra_tts.extend(tts.trees().skip(first_colon));
-                    p = cx.new_parser_from_tts(extra_tts.into_iter().collect());
-                }
-
-                asm = s;
-                asm_str_style = Some(style);
-            }
-            Outputs => {
-                while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
-                    if !outputs.is_empty() {
-                        p.eat(&token::Comma);
-                    }
-
-                    let constraint = parse_asm_str(&mut p)?;
-
-                    let span = p.prev_token.span;
-
-                    p.expect(&token::OpenDelim(token::Paren))?;
-                    let expr = p.parse_expr()?;
-                    p.expect(&token::CloseDelim(token::Paren))?;
-
-                    // Expands a read+write operand into two operands.
-                    //
-                    // Use '+' modifier when you want the same expression
-                    // to be both an input and an output at the same time.
-                    // It's the opposite of '=&' which means that the memory
-                    // cannot be shared with any other operand (usually when
-                    // a register is clobbered early.)
-                    let constraint_str = constraint.as_str();
-                    let mut ch = constraint_str.chars();
-                    let output = match ch.next() {
-                        Some('=') => None,
-                        Some('+') => Some(Symbol::intern(&format!("={}", ch.as_str()))),
-                        _ => {
-                            struct_span_err!(
-                                cx.sess.parse_sess.span_diagnostic,
-                                span,
-                                E0661,
-                                "output operand constraint lacks '=' or '+'"
-                            )
-                            .emit();
-                            None
-                        }
-                    };
-
-                    let is_rw = output.is_some();
-                    let is_indirect = constraint_str.contains('*');
-                    outputs.push(ast::LlvmInlineAsmOutput {
-                        constraint: output.unwrap_or(constraint),
-                        expr,
-                        is_rw,
-                        is_indirect,
-                    });
-                }
-            }
-            Inputs => {
-                while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
-                    if !inputs.is_empty() {
-                        p.eat(&token::Comma);
-                    }
-
-                    let constraint = parse_asm_str(&mut p)?;
-
-                    if constraint.as_str().starts_with('=') {
-                        struct_span_err!(
-                            cx.sess.parse_sess.span_diagnostic,
-                            p.prev_token.span,
-                            E0662,
-                            "input operand constraint contains '='"
-                        )
-                        .emit();
-                    } else if constraint.as_str().starts_with('+') {
-                        struct_span_err!(
-                            cx.sess.parse_sess.span_diagnostic,
-                            p.prev_token.span,
-                            E0663,
-                            "input operand constraint contains '+'"
-                        )
-                        .emit();
-                    }
-
-                    p.expect(&token::OpenDelim(token::Paren))?;
-                    let input = p.parse_expr()?;
-                    p.expect(&token::CloseDelim(token::Paren))?;
-
-                    inputs.push((constraint, input));
-                }
-            }
-            Clobbers => {
-                while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
-                    if !clobs.is_empty() {
-                        p.eat(&token::Comma);
-                    }
-
-                    let s = parse_asm_str(&mut p)?;
-
-                    if OPTIONS.iter().any(|&opt| s == opt) {
-                        cx.span_warn(p.prev_token.span, "expected a clobber, found an option");
-                    } else if s.as_str().starts_with('{') || s.as_str().ends_with('}') {
-                        struct_span_err!(
-                            cx.sess.parse_sess.span_diagnostic,
-                            p.prev_token.span,
-                            E0664,
-                            "clobber should not be surrounded by braces"
-                        )
-                        .emit();
-                    }
-
-                    clobs.push(s);
-                }
-            }
-            Options => {
-                let option = parse_asm_str(&mut p)?;
-
-                if option == sym::volatile {
-                    // Indicates that the inline assembly has side effects
-                    // and must not be optimized out along with its outputs.
-                    volatile = true;
-                } else if option == sym::alignstack {
-                    alignstack = true;
-                } else if option == sym::intel {
-                    dialect = LlvmAsmDialect::Intel;
-                } else {
-                    cx.span_warn(p.prev_token.span, "unrecognized option");
-                }
-
-                if p.token == token::Comma {
-                    p.eat(&token::Comma);
-                }
-            }
-            StateNone => (),
-        }
-
-        loop {
-            // MOD_SEP is a double colon '::' without space in between.
-            // When encountered, the state must be advanced twice.
-            match (&p.token.kind, state.next(), state.next().next()) {
-                (&token::Colon, StateNone, _) | (&token::ModSep, _, StateNone) => {
-                    p.bump();
-                    break 'statement;
-                }
-                (&token::Colon, st, _) | (&token::ModSep, _, st) => {
-                    p.bump();
-                    state = st;
-                }
-                (&token::Eof, ..) => break 'statement,
-                _ => break,
-            }
-        }
-    }
-
-    Ok(Some(ast::LlvmInlineAsm {
-        asm,
-        asm_str_style: asm_str_style.unwrap(),
-        outputs,
-        inputs,
-        clobbers: clobs,
-        volatile,
-        alignstack,
-        dialect,
-    }))
-}
index b16f5af66f249b5b80588ad452eca32ddd282cbc..5a889734f215b4007efc699b49e876c289ab0647 100644 (file)
@@ -749,18 +749,6 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
         | StatementKind::Retag { .. }
         | StatementKind::AscribeUserType(..) => {}
 
-        StatementKind::LlvmInlineAsm(asm) => {
-            match asm.asm.asm.as_str().trim() {
-                "" => {
-                    // Black box
-                }
-                _ => fx.tcx.sess.span_fatal(
-                    stmt.source_info.span,
-                    "Legacy `llvm_asm!` inline assembly is not supported. \
-                    Try using the new `asm!` instead.",
-                ),
-            }
-        }
         StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
         StatementKind::CopyNonOverlapping(inner) => {
             let dst = codegen_operand(fx, &inner.dst);
index 9a6c45ae98d5f5aeffeb09dd2c16f36fb6ecacef..74571817969d32576a599e56620521f88b0dd952 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) {
@@ -506,7 +508,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
                         {
                             return None;
                         }
-                        StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => {
+                        StatementKind::CopyNonOverlapping(_) => {
                             return None;
                         } // conservative handling
                         StatementKind::Assign(_)
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 93384bc55110167456e5e63ad52617d235456d6a..c242c75ed18ffcf9adb84a9284965fa23e6cb510 100644 (file)
@@ -6,7 +6,7 @@
 
 use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_middle::mir::InlineAsmOperand;
-use rustc_span::Symbol;
+use rustc_span::sym;
 use rustc_target::asm::*;
 
 pub(crate) fn codegen_inline_asm<'tcx>(
@@ -182,11 +182,7 @@ struct InlineAssemblyGenerator<'a, 'tcx> {
 impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
     fn allocate_registers(&mut self) {
         let sess = self.tcx.sess;
-        let map = allocatable_registers(
-            self.arch,
-            |feature| sess.target_features.contains(&Symbol::intern(feature)),
-            &sess.target,
-        );
+        let map = allocatable_registers(self.arch, &sess.target_features, &sess.target);
         let mut allocated = FxHashMap::<_, (bool, bool)>::default();
         let mut regs = vec![None; self.operands.len()];
 
@@ -319,9 +315,9 @@ fn allocate_stack_slots(&mut self) {
         // Allocate stack slots for saving clobbered registers
         let abi_clobber = InlineAsmClobberAbi::parse(
             self.arch,
-            |feature| self.tcx.sess.target_features.contains(&Symbol::intern(feature)),
+            &self.tcx.sess.target_features,
             &self.tcx.sess.target,
-            Symbol::intern("C"),
+            sym::C,
         )
         .unwrap()
         .clobbered_regs();
index f4703b22ecbcf75182fa202b18879204e00f4f98..55c9b4d9ba12d7ded09ce5c00410b529f37aef4f 100644 (file)
@@ -90,7 +90,7 @@
         match $intrinsic {
             $(
                 sym::$name => {
-                    assert!($substs.is_noop());
+                    assert!($substs.is_empty());
                     if let [$(ref $arg),*] = *$args {
                         let ($($arg,)*) = (
                             $(codegen_operand($fx, $arg),)*
index 453bcd601d3fe51b391b5627930c4350190d5bcc..b4213da6e05042b42476746a69024bff9ad8e7ee 100644 (file)
@@ -4,9 +4,8 @@
 use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
 
-use rustc_hir::LlvmInlineAsmInner;
 use rustc_middle::{bug, ty::Instance};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
 use rustc_target::asm::*;
 
 use std::borrow::Cow;
@@ -106,17 +105,6 @@ enum ConstraintOrRegister {
 
 
 impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
-    fn codegen_llvm_inline_asm(&mut self, _ia: &LlvmInlineAsmInner, _outputs: Vec<PlaceRef<'tcx, RValue<'gcc>>>, _inputs: Vec<RValue<'gcc>>, span: Span) -> bool {
-        self.sess().struct_span_err(span, "GCC backend does not support `llvm_asm!`")
-            .help("consider using the `asm!` macro instead")
-            .emit();
-
-        // We return `true` even if we've failed to generate the asm
-        // because we want to suppress the "malformed inline assembly" error
-        // generated by the frontend.
-        true
-    }
-
     fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], _instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) {
         if options.contains(InlineAsmOptions::MAY_UNWIND) {
             self.sess()
@@ -184,7 +172,7 @@ fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_opera
                             let is_target_supported = reg.reg_class().supported_types(asm_arch).iter()
                                 .any(|&(_, feature)| {
                                     if let Some(feature) = feature {
-                                        self.tcx.sess.target_features.contains(&Symbol::intern(feature))
+                                        self.tcx.sess.target_features.contains(&feature)
                                     } else {
                                         true // Register class is unconditionally supported
                                     }
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 caf16c1939df00fc5d94fce08c584ca9ce7df411..8b696dc6fba69a76257ab8b9394e32f5ebd95f7d 100644 (file)
@@ -7,16 +7,13 @@
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
 
-use rustc_ast::LlvmAsmDialect;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_codegen_ssa::mir::operand::OperandValue;
-use rustc_codegen_ssa::mir::place::PlaceRef;
 use rustc_codegen_ssa::traits::*;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::{bug, span_bug, ty::Instance};
-use rustc_span::{Pos, Span, Symbol};
+use rustc_span::{Pos, Span};
 use rustc_target::abi::*;
 use rustc_target::asm::*;
 
 use tracing::debug;
 
 impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
-    fn codegen_llvm_inline_asm(
-        &mut self,
-        ia: &hir::LlvmInlineAsmInner,
-        outputs: Vec<PlaceRef<'tcx, &'ll Value>>,
-        mut inputs: Vec<&'ll Value>,
-        span: Span,
-    ) -> bool {
-        let mut ext_constraints = vec![];
-        let mut output_types = vec![];
-
-        // Prepare the output operands
-        let mut indirect_outputs = vec![];
-        for (i, (out, &place)) in ia.outputs.iter().zip(&outputs).enumerate() {
-            if out.is_rw {
-                let operand = self.load_operand(place);
-                if let OperandValue::Immediate(_) = operand.val {
-                    inputs.push(operand.immediate());
-                }
-                ext_constraints.push(i.to_string());
-            }
-            if out.is_indirect {
-                let operand = self.load_operand(place);
-                if let OperandValue::Immediate(_) = operand.val {
-                    indirect_outputs.push(operand.immediate());
-                }
-            } else {
-                output_types.push(place.layout.llvm_type(self.cx));
-            }
-        }
-        if !indirect_outputs.is_empty() {
-            indirect_outputs.extend_from_slice(&inputs);
-            inputs = indirect_outputs;
-        }
-
-        let clobbers = ia.clobbers.iter().map(|s| format!("~{{{}}}", &s));
-
-        // Default per-arch clobbers
-        // Basically what clang does
-        let arch_clobbers = match &self.sess().target.arch[..] {
-            "x86" | "x86_64" => &["~{dirflag}", "~{fpsr}", "~{flags}"][..],
-            "mips" | "mips64" => &["~{$1}"],
-            _ => &[],
-        };
-
-        let all_constraints = ia
-            .outputs
-            .iter()
-            .map(|out| out.constraint.to_string())
-            .chain(ia.inputs.iter().map(|s| s.to_string()))
-            .chain(ext_constraints)
-            .chain(clobbers)
-            .chain(arch_clobbers.iter().map(|s| (*s).to_string()))
-            .collect::<Vec<String>>()
-            .join(",");
-
-        debug!("Asm Constraints: {}", &all_constraints);
-
-        // Depending on how many outputs we have, the return type is different
-        let num_outputs = output_types.len();
-        let output_type = match num_outputs {
-            0 => self.type_void(),
-            1 => output_types[0],
-            _ => self.type_struct(&output_types, false),
-        };
-
-        let asm = ia.asm.as_str();
-        let r = inline_asm_call(
-            self,
-            &asm,
-            &all_constraints,
-            &inputs,
-            output_type,
-            ia.volatile,
-            ia.alignstack,
-            ia.dialect,
-            &[span],
-            false,
-            None,
-        );
-        if r.is_none() {
-            return false;
-        }
-        let r = r.unwrap();
-
-        // Again, based on how many outputs we have
-        let outputs = ia.outputs.iter().zip(&outputs).filter(|&(o, _)| !o.is_indirect);
-        for (i, (_, &place)) in outputs.enumerate() {
-            let v = if num_outputs == 1 { r } else { self.extract_value(r, i as u64) };
-            OperandValue::Immediate(v).store(self, place);
-        }
-
-        true
-    }
-
     fn codegen_inline_asm(
         &mut self,
         template: &[InlineAsmTemplatePiece],
@@ -142,9 +45,8 @@ fn codegen_inline_asm(
                         for &(_, feature) in reg_class.supported_types(asm_arch) {
                             if let Some(feature) = feature {
                                 let codegen_fn_attrs = self.tcx.codegen_fn_attrs(instance.def_id());
-                                let feature_name = Symbol::intern(feature);
-                                if self.tcx.sess.target_features.contains(&feature_name)
-                                    || codegen_fn_attrs.target_features.contains(&feature_name)
+                                if self.tcx.sess.target_features.contains(&feature)
+                                    || codegen_fn_attrs.target_features.contains(&feature)
                                 {
                                     return true;
                                 }
@@ -349,9 +251,9 @@ fn codegen_inline_asm(
             InlineAsmArch::X86 | InlineAsmArch::X86_64
                 if !options.contains(InlineAsmOptions::ATT_SYNTAX) =>
             {
-                LlvmAsmDialect::Intel
+                llvm::AsmDialect::Intel
             }
-            _ => LlvmAsmDialect::Att,
+            _ => llvm::AsmDialect::Att,
         };
         let result = inline_asm_call(
             self,
@@ -455,7 +357,7 @@ pub(crate) fn inline_asm_call<'ll>(
     output: &'ll llvm::Type,
     volatile: bool,
     alignstack: bool,
-    dia: LlvmAsmDialect,
+    dia: llvm::AsmDialect,
     line_spans: &[Span],
     unwind: bool,
     dest_catch_funclet: Option<(
@@ -498,7 +400,7 @@ pub(crate) fn inline_asm_call<'ll>(
                 cons.len(),
                 volatile,
                 alignstack,
-                llvm::AsmDialect::from_generic(dia),
+                dia,
                 can_throw,
             );
 
@@ -522,7 +424,7 @@ pub(crate) fn inline_asm_call<'ll>(
             // we just encode the start position of each line.
             // FIXME: Figure out a way to pass the entire line spans.
             let mut srcloc = vec![];
-            if dia == LlvmAsmDialect::Intel && line_spans.len() > 1 {
+            if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
                 // LLVM inserts an extra line to add the ".intel_syntax", so add
                 // a dummy srcloc entry for it.
                 //
index 2fb5a0f9faf8269492f5d4b45ed0b949d389ee2a..5703a72c686e5bb3dc09e9d80aba617dbd7cd36f 100644 (file)
@@ -1,6 +1,7 @@
 //! A helper class for dealing with static archives
 
-use std::ffi::{CStr, CString};
+use std::env;
+use std::ffi::{CStr, CString, OsString};
 use std::io;
 use std::mem;
 use std::path::{Path, PathBuf};
@@ -158,54 +159,127 @@ fn inject_dll_import_lib(
             output_path.with_extension("lib")
         };
 
-        // we've checked for \0 characters in the library name already
-        let dll_name_z = CString::new(lib_name).unwrap();
-        // All import names are Rust identifiers and therefore cannot contain \0 characters.
-        // FIXME: when support for #[link_name] implemented, ensure that import.name values don't
-        // have any \0 characters
-        let import_name_and_ordinal_vector: Vec<(CString, Option<u16>)> = dll_imports
+        let mingw_gnu_toolchain = self.config.sess.target.llvm_target.ends_with("pc-windows-gnu");
+
+        let import_name_and_ordinal_vector: Vec<(String, Option<u16>)> = dll_imports
             .iter()
             .map(|import: &DllImport| {
                 if self.config.sess.target.arch == "x86" {
-                    (LlvmArchiveBuilder::i686_decorated_name(import), import.ordinal)
+                    (
+                        LlvmArchiveBuilder::i686_decorated_name(import, mingw_gnu_toolchain),
+                        import.ordinal,
+                    )
                 } else {
-                    (CString::new(import.name.to_string()).unwrap(), import.ordinal)
+                    (import.name.to_string(), import.ordinal)
                 }
             })
             .collect();
 
-        let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
+        if mingw_gnu_toolchain {
+            // The binutils linker used on -windows-gnu targets cannot read the import
+            // libraries generated by LLVM: in our attempts, the linker produced an .EXE
+            // that loaded but crashed with an AV upon calling one of the imported
+            // functions.  Therefore, use binutils to create the import library instead,
+            // by writing a .DEF file to the temp dir and calling binutils's dlltool.
+            let def_file_path =
+                tmpdir.as_ref().join(format!("{}_imports", lib_name)).with_extension("def");
+
+            let def_file_content = format!(
+                "EXPORTS\n{}",
+                import_name_and_ordinal_vector
+                    .into_iter()
+                    .map(|(name, ordinal)| {
+                        match ordinal {
+                            Some(n) => format!("{} @{} NONAME", name, n),
+                            None => name,
+                        }
+                    })
+                    .collect::<Vec<String>>()
+                    .join("\n")
+            );
 
-        tracing::trace!("invoking LLVMRustWriteImportLibrary");
-        tracing::trace!("  dll_name {:#?}", dll_name_z);
-        tracing::trace!("  output_path {}", output_path.display());
-        tracing::trace!(
-            "  import names: {}",
-            dll_imports.iter().map(|import| import.name.to_string()).collect::<Vec<_>>().join(", "),
-        );
+            match std::fs::write(&def_file_path, def_file_content) {
+                Ok(_) => {}
+                Err(e) => {
+                    self.config.sess.fatal(&format!("Error writing .DEF file: {}", e));
+                }
+            };
 
-        let ffi_exports: Vec<LLVMRustCOFFShortExport> = import_name_and_ordinal_vector
-            .iter()
-            .map(|(name_z, ordinal)| LLVMRustCOFFShortExport::new(name_z.as_ptr(), *ordinal))
-            .collect();
-        let result = unsafe {
-            crate::llvm::LLVMRustWriteImportLibrary(
-                dll_name_z.as_ptr(),
-                output_path_z.as_ptr(),
-                ffi_exports.as_ptr(),
-                ffi_exports.len(),
-                llvm_machine_type(&self.config.sess.target.arch) as u16,
-                !self.config.sess.target.is_like_msvc,
-            )
-        };
+            let dlltool = find_binutils_dlltool(self.config.sess);
+            let result = std::process::Command::new(dlltool)
+                .args([
+                    "-d",
+                    def_file_path.to_str().unwrap(),
+                    "-D",
+                    lib_name,
+                    "-l",
+                    output_path.to_str().unwrap(),
+                ])
+                .output();
+
+            match result {
+                Err(e) => {
+                    self.config.sess.fatal(&format!("Error calling dlltool: {}", e.to_string()));
+                }
+                Ok(output) if !output.status.success() => self.config.sess.fatal(&format!(
+                    "Dlltool could not create import library: {}\n{}",
+                    String::from_utf8_lossy(&output.stdout),
+                    String::from_utf8_lossy(&output.stderr)
+                )),
+                _ => {}
+            }
+        } else {
+            // we've checked for \0 characters in the library name already
+            let dll_name_z = CString::new(lib_name).unwrap();
+
+            let output_path_z = rustc_fs_util::path_to_c_string(&output_path);
+
+            tracing::trace!("invoking LLVMRustWriteImportLibrary");
+            tracing::trace!("  dll_name {:#?}", dll_name_z);
+            tracing::trace!("  output_path {}", output_path.display());
+            tracing::trace!(
+                "  import names: {}",
+                dll_imports
+                    .iter()
+                    .map(|import| import.name.to_string())
+                    .collect::<Vec<_>>()
+                    .join(", "),
+            );
 
-        if result == crate::llvm::LLVMRustResult::Failure {
-            self.config.sess.fatal(&format!(
-                "Error creating import library for {}: {}",
-                lib_name,
-                llvm::last_error().unwrap_or("unknown LLVM error".to_string())
-            ));
-        }
+            // All import names are Rust identifiers and therefore cannot contain \0 characters.
+            // FIXME: when support for #[link_name] is implemented, ensure that the import names
+            // still don't contain any \0 characters.  Also need to check that the names don't
+            // contain substrings like " @" or "NONAME" that are keywords or otherwise reserved
+            // in definition files.
+            let cstring_import_name_and_ordinal_vector: Vec<(CString, Option<u16>)> =
+                import_name_and_ordinal_vector
+                    .into_iter()
+                    .map(|(name, ordinal)| (CString::new(name).unwrap(), ordinal))
+                    .collect();
+
+            let ffi_exports: Vec<LLVMRustCOFFShortExport> = cstring_import_name_and_ordinal_vector
+                .iter()
+                .map(|(name_z, ordinal)| LLVMRustCOFFShortExport::new(name_z.as_ptr(), *ordinal))
+                .collect();
+            let result = unsafe {
+                crate::llvm::LLVMRustWriteImportLibrary(
+                    dll_name_z.as_ptr(),
+                    output_path_z.as_ptr(),
+                    ffi_exports.as_ptr(),
+                    ffi_exports.len(),
+                    llvm_machine_type(&self.config.sess.target.arch) as u16,
+                    !self.config.sess.target.is_like_msvc,
+                )
+            };
+
+            if result == crate::llvm::LLVMRustResult::Failure {
+                self.config.sess.fatal(&format!(
+                    "Error creating import library for {}: {}",
+                    lib_name,
+                    llvm::last_error().unwrap_or("unknown LLVM error".to_string())
+                ));
+            }
+        };
 
         self.add_archive(&output_path, |_| false).unwrap_or_else(|e| {
             self.config.sess.fatal(&format!(
@@ -332,22 +406,61 @@ fn build_with_llvm(&mut self, kind: ArchiveKind) -> io::Result<()> {
         }
     }
 
-    fn i686_decorated_name(import: &DllImport) -> CString {
+    fn i686_decorated_name(import: &DllImport, mingw: bool) -> String {
         let name = import.name;
-        // We verified during construction that `name` does not contain any NULL characters, so the
-        // conversion to CString is guaranteed to succeed.
-        CString::new(match import.calling_convention {
-            DllCallingConvention::C => format!("_{}", name),
-            DllCallingConvention::Stdcall(arg_list_size) => format!("_{}@{}", name, arg_list_size),
+        let prefix = if mingw { "" } else { "_" };
+
+        match import.calling_convention {
+            DllCallingConvention::C => format!("{}{}", prefix, name),
+            DllCallingConvention::Stdcall(arg_list_size) => {
+                format!("{}{}@{}", prefix, name, arg_list_size)
+            }
             DllCallingConvention::Fastcall(arg_list_size) => format!("@{}@{}", name, arg_list_size),
             DllCallingConvention::Vectorcall(arg_list_size) => {
                 format!("{}@@{}", name, arg_list_size)
             }
-        })
-        .unwrap()
+        }
     }
 }
 
 fn string_to_io_error(s: String) -> io::Error {
     io::Error::new(io::ErrorKind::Other, format!("bad archive: {}", s))
 }
+
+fn find_binutils_dlltool(sess: &Session) -> OsString {
+    assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
+    if let Some(dlltool_path) = &sess.opts.debugging_opts.dlltool {
+        return dlltool_path.clone().into_os_string();
+    }
+
+    let mut tool_name: OsString = if sess.host.arch != sess.target.arch {
+        // We are cross-compiling, so we need the tool with the prefix matching our target
+        if sess.target.arch == "x86" {
+            "i686-w64-mingw32-dlltool"
+        } else {
+            "x86_64-w64-mingw32-dlltool"
+        }
+    } else {
+        // We are not cross-compiling, so we just want `dlltool`
+        "dlltool"
+    }
+    .into();
+
+    if sess.host.options.is_like_windows {
+        // If we're compiling on Windows, add the .exe suffix
+        tool_name.push(".exe");
+    }
+
+    // NOTE: it's not clear how useful it is to explicitly search PATH.
+    for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) {
+        let full_path = dir.join(&tool_name);
+        if full_path.is_file() {
+            return full_path.into_os_string();
+        }
+    }
+
+    // The user didn't specify the location of the dlltool binary, and we weren't able
+    // to find the appropriate one on the PATH.  Just return the name of the tool
+    // and let the invocation fail with a hopefully useful error message.
+    tool_name
+}
index ddba43cd1f16e67b2655dddee4436f3f7dab6943..6afa649b6de325a19b40e8df10619b1002f371fd 100644 (file)
@@ -349,13 +349,6 @@ fn fat_lto(
             );
             save_temp_bitcode(cgcx, &module, "lto.after-restriction");
         }
-
-        if cgcx.no_landing_pads {
-            unsafe {
-                llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
-            }
-            save_temp_bitcode(cgcx, &module, "lto.after-nounwind");
-        }
     }
 
     Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode })
@@ -770,16 +763,6 @@ pub unsafe fn optimize_thin_module(
             return Err(write::llvm_err(&diag_handler, msg));
         }
 
-        // Like with "fat" LTO, get some better optimizations if landing pads
-        // are disabled by removing all landing pads.
-        if cgcx.no_landing_pads {
-            let _timer = cgcx
-                .prof
-                .generic_activity_with_arg("LLVM_thin_lto_remove_landing_pads", thin_module.name());
-            llvm::LLVMRustMarkAllFunctionsNounwind(llmod);
-            save_temp_bitcode(cgcx, &module, "thin-lto-after-nounwind");
-        }
-
         // Up next comes the per-module local analyses that we do for Thin LTO.
         // Each of these functions is basically copied from the LLVM
         // implementation and then tailored to suit this implementation. Ideally
index 5217fa2758f79c7f4f559c76fb91698d61b184b7..8a9450c20dda4c1727bfa1af201ff190d11344b6 100644 (file)
@@ -731,27 +731,11 @@ fn sext(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
     }
 
     fn fptoui_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
-        if !self.fptoint_sat_broken_in_llvm() {
-            let src_ty = self.cx.val_ty(val);
-            let float_width = self.cx.float_width(src_ty);
-            let int_width = self.cx.int_width(dest_ty);
-            let name = format!("llvm.fptoui.sat.i{}.f{}", int_width, float_width);
-            return Some(self.call_intrinsic(&name, &[val]));
-        }
-
-        None
+        self.fptoint_sat(false, val, dest_ty)
     }
 
     fn fptosi_sat(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> Option<&'ll Value> {
-        if !self.fptoint_sat_broken_in_llvm() {
-            let src_ty = self.cx.val_ty(val);
-            let float_width = self.cx.float_width(src_ty);
-            let int_width = self.cx.int_width(dest_ty);
-            let name = format!("llvm.fptosi.sat.i{}.f{}", int_width, float_width);
-            return Some(self.call_intrinsic(&name, &[val]));
-        }
-
-        None
+        self.fptoint_sat(true, val, dest_ty)
     }
 
     fn fptoui(&mut self, val: &'ll Value, dest_ty: &'ll Type) -> &'ll Value {
@@ -1455,4 +1439,43 @@ fn fptoint_sat_broken_in_llvm(&self) -> bool {
             _ => false,
         }
     }
+
+    fn fptoint_sat(
+        &mut self,
+        signed: bool,
+        val: &'ll Value,
+        dest_ty: &'ll Type,
+    ) -> Option<&'ll Value> {
+        if !self.fptoint_sat_broken_in_llvm() {
+            let src_ty = self.cx.val_ty(val);
+            let (float_ty, int_ty, vector_length) = if self.cx.type_kind(src_ty) == TypeKind::Vector
+            {
+                assert_eq!(self.cx.vector_length(src_ty), self.cx.vector_length(dest_ty));
+                (
+                    self.cx.element_type(src_ty),
+                    self.cx.element_type(dest_ty),
+                    Some(self.cx.vector_length(src_ty)),
+                )
+            } else {
+                (src_ty, dest_ty, None)
+            };
+            let float_width = self.cx.float_width(float_ty);
+            let int_width = self.cx.int_width(int_ty);
+
+            let instr = if signed { "fptosi" } else { "fptoui" };
+            let name = if let Some(vector_length) = vector_length {
+                format!(
+                    "llvm.{}.sat.v{}i{}.v{}f{}",
+                    instr, vector_length, int_width, vector_length, float_width
+                )
+            } else {
+                format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width)
+            };
+            let f =
+                self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
+            Some(self.call(self.type_func(&[src_ty], dest_ty), f, &[val], None))
+        } else {
+            None
+        }
+    }
 }
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 60ff18af0a97e8f1e34bc225d7d09e5294874356..3d5fd2f354e55980a11a2b6f11d6ebbf4941df40 100644 (file)
 use rustc_hir::def::CtorKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_index::vec::{Idx, IndexVec};
+use rustc_middle::bug;
 use rustc_middle::mir::{self, GeneratorLayout};
 use rustc_middle::ty::layout::{self, IntegerExt, LayoutOf, PrimitiveExt, TyAndLayout};
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{
     self, AdtKind, GeneratorSubsts, Instance, ParamEnv, Ty, TyCtxt, COMMON_VTABLE_ENTRIES,
 };
-use rustc_middle::{bug, span_bug};
 use rustc_query_system::ich::NodeIdHashingMode;
 use rustc_session::config::{self, DebugInfo};
 use rustc_span::symbol::Symbol;
 use rustc_span::FileNameDisplayPreference;
-use rustc_span::{self, SourceFile, SourceFileHash, Span};
+use rustc_span::{self, SourceFile, SourceFileHash};
 use rustc_target::abi::{Abi, Align, HasDataLayout, Integer, TagEncoding};
 use rustc_target::abi::{Int, Pointer, F32, F64};
 use rustc_target::abi::{Primitive, Size, VariantIdx, Variants};
@@ -381,9 +381,8 @@ fn fixed_vec_metadata<'ll, 'tcx>(
     unique_type_id: UniqueTypeId,
     array_or_slice_type: Ty<'tcx>,
     element_type: Ty<'tcx>,
-    span: Span,
 ) -> MetadataCreationResult<'ll> {
-    let element_type_metadata = type_metadata(cx, element_type, span);
+    let element_type_metadata = type_metadata(cx, element_type);
 
     return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
@@ -416,11 +415,10 @@ fn vec_slice_metadata<'ll, 'tcx>(
     slice_ptr_type: Ty<'tcx>,
     element_type: Ty<'tcx>,
     unique_type_id: UniqueTypeId,
-    span: Span,
 ) -> MetadataCreationResult<'ll> {
     let data_ptr_type = cx.tcx.mk_imm_ptr(element_type);
 
-    let data_ptr_metadata = type_metadata(cx, data_ptr_type, span);
+    let data_ptr_metadata = type_metadata(cx, data_ptr_type);
 
     return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
@@ -442,7 +440,7 @@ fn vec_slice_metadata<'ll, 'tcx>(
         },
         MemberDescription {
             name: "length".to_owned(),
-            type_metadata: type_metadata(cx, cx.tcx.types.usize, span),
+            type_metadata: type_metadata(cx, cx.tcx.types.usize),
             offset: pointer_size,
             size: usize_size,
             align: usize_align,
@@ -452,8 +450,6 @@ fn vec_slice_metadata<'ll, 'tcx>(
         },
     ];
 
-    let file_metadata = unknown_file_metadata(cx);
-
     let metadata = composite_type_metadata(
         cx,
         slice_ptr_type,
@@ -461,8 +457,6 @@ fn vec_slice_metadata<'ll, 'tcx>(
         unique_type_id,
         member_descriptions,
         NO_SCOPE_METADATA,
-        file_metadata,
-        span,
     );
     MetadataCreationResult::new(metadata, false)
 }
@@ -471,7 +465,6 @@ fn subroutine_type_metadata<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     unique_type_id: UniqueTypeId,
     signature: ty::PolyFnSig<'tcx>,
-    span: Span,
 ) -> MetadataCreationResult<'ll> {
     let signature =
         cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), signature);
@@ -480,12 +473,12 @@ fn subroutine_type_metadata<'ll, 'tcx>(
         // return type
         match signature.output().kind() {
             ty::Tuple(tys) if tys.is_empty() => None,
-            _ => Some(type_metadata(cx, signature.output(), span)),
+            _ => Some(type_metadata(cx, signature.output())),
         },
     )
     .chain(
         // regular arguments
-        signature.inputs().iter().map(|argument_type| Some(type_metadata(cx, argument_type, span))),
+        signature.inputs().iter().map(|argument_type| Some(type_metadata(cx, argument_type))),
     )
     .collect();
 
@@ -541,8 +534,6 @@ fn trait_pointer_metadata<'ll, 'tcx>(
         None => (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_type, true)),
     };
 
-    let file_metadata = unknown_file_metadata(cx);
-
     let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type));
 
     assert_eq!(abi::FAT_PTR_ADDR, 0);
@@ -553,11 +544,7 @@ fn trait_pointer_metadata<'ll, 'tcx>(
     let member_descriptions = vec![
         MemberDescription {
             name: "pointer".to_owned(),
-            type_metadata: type_metadata(
-                cx,
-                cx.tcx.mk_mut_ptr(cx.tcx.types.u8),
-                rustc_span::DUMMY_SP,
-            ),
+            type_metadata: type_metadata(cx, cx.tcx.mk_mut_ptr(cx.tcx.types.u8)),
             offset: layout.fields.offset(0),
             size: data_ptr_field.size,
             align: data_ptr_field.align.abi,
@@ -567,7 +554,7 @@ fn trait_pointer_metadata<'ll, 'tcx>(
         },
         MemberDescription {
             name: "vtable".to_owned(),
-            type_metadata: type_metadata(cx, vtable_field.ty, rustc_span::DUMMY_SP),
+            type_metadata: type_metadata(cx, vtable_field.ty),
             offset: layout.fields.offset(1),
             size: vtable_field.size,
             align: vtable_field.align.abi,
@@ -584,16 +571,10 @@ fn trait_pointer_metadata<'ll, 'tcx>(
         unique_type_id,
         member_descriptions,
         containing_scope,
-        file_metadata,
-        rustc_span::DUMMY_SP,
     )
 }
 
-pub fn type_metadata<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
-    t: Ty<'tcx>,
-    usage_site_span: Span,
-) -> &'ll DIType {
+pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
     // Get the unique type ID of this type.
     let unique_type_id = {
         let mut type_map = debug_context(cx).type_map.borrow_mut();
@@ -630,14 +611,14 @@ pub fn type_metadata<'ll, 'tcx>(
     debug!("type_metadata: {:?}", t);
 
     let ptr_metadata = |ty: Ty<'tcx>| match *ty.kind() {
-        ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)),
-        ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id, usage_site_span)),
+        ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id)),
+        ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id)),
         ty::Dynamic(..) => Ok(MetadataCreationResult::new(
             trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
             false,
         )),
         _ => {
-            let pointee_metadata = type_metadata(cx, ty, usage_site_span);
+            let pointee_metadata = type_metadata(cx, ty);
 
             if let Some(metadata) =
                 debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
@@ -656,10 +637,8 @@ pub fn type_metadata<'ll, 'tcx>(
         ty::Tuple(elements) if elements.is_empty() => {
             MetadataCreationResult::new(basic_type_metadata(cx, t), false)
         }
-        ty::Array(typ, _) | ty::Slice(typ) => {
-            fixed_vec_metadata(cx, unique_type_id, t, typ, usage_site_span)
-        }
-        ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8, usage_site_span),
+        ty::Array(typ, _) | ty::Slice(typ) => fixed_vec_metadata(cx, unique_type_id, t, typ),
+        ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8),
         ty::Dynamic(..) => {
             MetadataCreationResult::new(trait_pointer_metadata(cx, t, None, unique_type_id), false)
         }
@@ -710,8 +689,7 @@ pub fn type_metadata<'ll, 'tcx>(
             type_map.borrow_mut().register_type_with_metadata(t, temp_type);
 
             let fn_metadata =
-                subroutine_type_metadata(cx, unique_type_id, t.fn_sig(cx.tcx), usage_site_span)
-                    .metadata;
+                subroutine_type_metadata(cx, unique_type_id, t.fn_sig(cx.tcx)).metadata;
 
             type_map.borrow_mut().remove_type(t);
 
@@ -721,15 +699,8 @@ pub fn type_metadata<'ll, 'tcx>(
         ty::Closure(def_id, substs) => {
             let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect();
             let containing_scope = get_namespace_for_item(cx, def_id);
-            prepare_tuple_metadata(
-                cx,
-                t,
-                &upvar_tys,
-                unique_type_id,
-                usage_site_span,
-                Some(containing_scope),
-            )
-            .finalize(cx)
+            prepare_tuple_metadata(cx, t, &upvar_tys, unique_type_id, Some(containing_scope))
+                .finalize(cx)
         }
         ty::Generator(def_id, substs, _) => {
             let upvar_tys: Vec<_> = substs
@@ -737,25 +708,18 @@ pub fn type_metadata<'ll, 'tcx>(
                 .prefix_tys()
                 .map(|t| cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t))
                 .collect();
-            prepare_enum_metadata(cx, t, def_id, unique_type_id, usage_site_span, upvar_tys)
-                .finalize(cx)
+            prepare_enum_metadata(cx, t, def_id, unique_type_id, upvar_tys).finalize(cx)
         }
         ty::Adt(def, ..) => match def.adt_kind() {
-            AdtKind::Struct => {
-                prepare_struct_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx)
-            }
-            AdtKind::Union => {
-                prepare_union_metadata(cx, t, unique_type_id, usage_site_span).finalize(cx)
-            }
+            AdtKind::Struct => prepare_struct_metadata(cx, t, unique_type_id).finalize(cx),
+            AdtKind::Union => prepare_union_metadata(cx, t, unique_type_id).finalize(cx),
             AdtKind::Enum => {
-                prepare_enum_metadata(cx, t, def.did, unique_type_id, usage_site_span, vec![])
-                    .finalize(cx)
+                prepare_enum_metadata(cx, t, def.did, unique_type_id, vec![]).finalize(cx)
             }
         },
         ty::Tuple(elements) => {
             let tys: Vec<_> = elements.iter().map(|k| k.expect_ty()).collect();
-            prepare_tuple_metadata(cx, t, &tys, unique_type_id, usage_site_span, NO_SCOPE_METADATA)
-                .finalize(cx)
+            prepare_tuple_metadata(cx, t, &tys, unique_type_id, NO_SCOPE_METADATA).finalize(cx)
         }
         // Type parameters from polymorphized functions.
         ty::Param(_) => MetadataCreationResult::new(param_type_metadata(cx, t), false),
@@ -770,8 +734,7 @@ pub fn type_metadata<'ll, 'tcx>(
             let metadata_for_uid = match type_map.find_metadata_for_unique_id(unique_type_id) {
                 Some(metadata) => metadata,
                 None => {
-                    span_bug!(
-                        usage_site_span,
+                    bug!(
                         "expected type metadata for unique \
                                type ID '{}' to already be in \
                                the `debuginfo::TypeMap` but it \
@@ -785,8 +748,7 @@ pub fn type_metadata<'ll, 'tcx>(
             match type_map.find_metadata_for_type(t) {
                 Some(metadata) => {
                     if metadata != metadata_for_uid {
-                        span_bug!(
-                            usage_site_span,
+                        bug!(
                             "mismatch between `Ty` and \
                                    `UniqueTypeId` maps in \
                                    `debuginfo::TypeMap`. \
@@ -1283,7 +1245,6 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
 struct StructMemberDescriptionFactory<'tcx> {
     ty: Ty<'tcx>,
     variant: &'tcx ty::VariantDef,
-    span: Span,
 }
 
 impl<'tcx> StructMemberDescriptionFactory<'tcx> {
@@ -1300,12 +1261,12 @@ 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 {
                     name,
-                    type_metadata: type_metadata(cx, field.ty, self.span),
+                    type_metadata: type_metadata(cx, field.ty),
                     offset: layout.fields.offset(i),
                     size: field.size,
                     align: field.align.abi,
@@ -1322,7 +1283,6 @@ fn prepare_struct_metadata<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     struct_type: Ty<'tcx>,
     unique_type_id: UniqueTypeId,
-    span: Span,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false);
 
@@ -1348,7 +1308,7 @@ fn prepare_struct_metadata<'ll, 'tcx>(
         unique_type_id,
         struct_metadata_stub,
         struct_metadata_stub,
-        StructMDF(StructMemberDescriptionFactory { ty: struct_type, variant, span }),
+        StructMDF(StructMemberDescriptionFactory { ty: struct_type, variant }),
     )
 }
 
@@ -1385,7 +1345,6 @@ fn closure_saved_names_of_captured_variables(tcx: TyCtxt<'_>, def_id: DefId) ->
 struct TupleMemberDescriptionFactory<'tcx> {
     ty: Ty<'tcx>,
     component_types: Vec<Ty<'tcx>>,
-    span: Span,
 }
 
 impl<'tcx> TupleMemberDescriptionFactory<'tcx> {
@@ -1412,7 +1371,7 @@ fn create_member_descriptions<'ll>(
                 };
                 MemberDescription {
                     name,
-                    type_metadata: type_metadata(cx, component_type, self.span),
+                    type_metadata: type_metadata(cx, component_type),
                     offset: layout.fields.offset(i),
                     size,
                     align,
@@ -1430,7 +1389,6 @@ fn prepare_tuple_metadata<'ll, 'tcx>(
     tuple_type: Ty<'tcx>,
     component_types: &[Ty<'tcx>],
     unique_type_id: UniqueTypeId,
-    span: Span,
     containing_scope: Option<&'ll DIScope>,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let tuple_name = compute_debuginfo_type_name(cx.tcx, tuple_type, false);
@@ -1453,7 +1411,6 @@ fn prepare_tuple_metadata<'ll, 'tcx>(
         TupleMDF(TupleMemberDescriptionFactory {
             ty: tuple_type,
             component_types: component_types.to_vec(),
-            span,
         }),
     )
 }
@@ -1465,7 +1422,6 @@ fn prepare_tuple_metadata<'ll, 'tcx>(
 struct UnionMemberDescriptionFactory<'tcx> {
     layout: TyAndLayout<'tcx>,
     variant: &'tcx ty::VariantDef,
-    span: Span,
 }
 
 impl<'tcx> UnionMemberDescriptionFactory<'tcx> {
@@ -1480,8 +1436,8 @@ fn create_member_descriptions<'ll>(
             .map(|(i, f)| {
                 let field = self.layout.field(cx, i);
                 MemberDescription {
-                    name: f.ident.to_string(),
-                    type_metadata: type_metadata(cx, field.ty, self.span),
+                    name: f.name.to_string(),
+                    type_metadata: type_metadata(cx, field.ty),
                     offset: Size::ZERO,
                     size: field.size,
                     align: field.align.abi,
@@ -1498,7 +1454,6 @@ fn prepare_union_metadata<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     union_type: Ty<'tcx>,
     unique_type_id: UniqueTypeId,
-    span: Span,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false);
 
@@ -1518,7 +1473,7 @@ fn prepare_union_metadata<'ll, 'tcx>(
         unique_type_id,
         union_metadata_stub,
         union_metadata_stub,
-        UnionMDF(UnionMemberDescriptionFactory { layout: cx.layout_of(union_type), variant, span }),
+        UnionMDF(UnionMemberDescriptionFactory { layout: cx.layout_of(union_type), variant }),
     )
 }
 
@@ -1573,7 +1528,6 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> {
     layout: TyAndLayout<'tcx>,
     tag_type_metadata: Option<&'ll DIType>,
     common_members: Vec<Option<&'ll DIType>>,
-    span: Span,
 }
 
 impl<'ll, 'tcx> EnumMemberDescriptionFactory<'ll, 'tcx> {
@@ -1605,7 +1559,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
         // 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);
+        let self_metadata = type_metadata(cx, self.enum_type);
 
         match self.layout.variants {
             Variants::Single { index } => {
@@ -1617,7 +1571,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
 
                 let variant_info = variant_info_for(index);
                 let (variant_type_metadata, member_description_factory) =
-                    describe_enum_variant(cx, self.layout, variant_info, self_metadata, self.span);
+                    describe_enum_variant(cx, self.layout, variant_info, self_metadata);
 
                 let member_descriptions = member_description_factory.create_member_descriptions(cx);
 
@@ -1682,13 +1636,8 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                     .map(|(i, _)| {
                         let variant = self.layout.for_variant(cx, i);
                         let variant_info = variant_info_for(i);
-                        let (variant_type_metadata, member_desc_factory) = describe_enum_variant(
-                            cx,
-                            variant,
-                            variant_info,
-                            self_metadata,
-                            self.span,
-                        );
+                        let (variant_type_metadata, member_desc_factory) =
+                            describe_enum_variant(cx, variant, variant_info, self_metadata);
 
                         let member_descriptions =
                             member_desc_factory.create_member_descriptions(cx);
@@ -1807,7 +1756,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                             tag.value.size(cx).bits(),
                             tag.value.align(cx).abi.bits() as u32,
                             create_DIArray(DIB(cx), &tags),
-                            type_metadata(cx, discr_enum_ty, self.span),
+                            type_metadata(cx, discr_enum_ty),
                             true,
                         )
                     };
@@ -1818,7 +1767,6 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                         dataful_variant_layout,
                         variant_info,
                         self_metadata,
-                        self.span,
                     );
 
                     let member_descriptions = member_desc_factory.create_member_descriptions(cx);
@@ -1864,13 +1812,7 @@ fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec<MemberDes
                             let variant = self.layout.for_variant(cx, i);
                             let variant_info = variant_info_for(i);
                             let (variant_type_metadata, member_desc_factory) =
-                                describe_enum_variant(
-                                    cx,
-                                    variant,
-                                    variant_info,
-                                    self_metadata,
-                                    self.span,
-                                );
+                                describe_enum_variant(cx, variant, variant_info, self_metadata);
 
                             let member_descriptions =
                                 member_desc_factory.create_member_descriptions(cx);
@@ -1908,7 +1850,6 @@ struct VariantMemberDescriptionFactory<'tcx> {
     /// Cloned from the `layout::Struct` describing the variant.
     offsets: Vec<Size>,
     args: Vec<(String, Ty<'tcx>)>,
-    span: Span,
 }
 
 impl<'tcx> VariantMemberDescriptionFactory<'tcx> {
@@ -1923,7 +1864,7 @@ fn create_member_descriptions<'ll>(
                 let (size, align) = cx.size_and_align_of(ty);
                 MemberDescription {
                     name: name.to_string(),
-                    type_metadata: type_metadata(cx, ty, self.span),
+                    type_metadata: type_metadata(cx, ty),
                     offset: self.offsets[i],
                     size,
                     align,
@@ -1950,7 +1891,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))
             }
@@ -1959,7 +1900,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
@@ -1973,7 +1914,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,
@@ -2011,7 +1952,6 @@ fn describe_enum_variant<'ll, 'tcx>(
     layout: layout::TyAndLayout<'tcx>,
     variant: VariantInfo<'_, 'tcx>,
     containing_scope: &'ll DIScope,
-    span: Span,
 ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) {
     let metadata_stub = variant.map_struct_name(|variant_name| {
         let unique_type_id = debug_context(cx)
@@ -2033,8 +1973,7 @@ fn describe_enum_variant<'ll, 'tcx>(
         .map(|i| (variant.field_name(i), layout.field(cx, i).ty))
         .collect();
 
-    let member_description_factory =
-        VariantMDF(VariantMemberDescriptionFactory { offsets, args, span });
+    let member_description_factory = VariantMDF(VariantMemberDescriptionFactory { offsets, args });
 
     (metadata_stub, member_description_factory)
 }
@@ -2044,7 +1983,6 @@ fn prepare_enum_metadata<'ll, 'tcx>(
     enum_type: Ty<'tcx>,
     enum_def_id: DefId,
     unique_type_id: UniqueTypeId,
-    span: Span,
     outer_field_tys: Vec<Ty<'tcx>>,
 ) -> RecursiveTypeDescription<'ll, 'tcx> {
     let tcx = cx.tcx;
@@ -2063,7 +2001,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,
@@ -2109,8 +2047,7 @@ fn prepare_enum_metadata<'ll, 'tcx>(
             Some(discriminant_type_metadata) => discriminant_type_metadata,
             None => {
                 let (discriminant_size, discriminant_align) = (discr.size(cx), discr.align(cx));
-                let discriminant_base_type_metadata =
-                    type_metadata(cx, discr.to_ty(tcx), rustc_span::DUMMY_SP);
+                let discriminant_base_type_metadata = type_metadata(cx, discr.to_ty(tcx));
 
                 let item_name;
                 let discriminant_name = match enum_type.kind() {
@@ -2202,7 +2139,6 @@ fn prepare_enum_metadata<'ll, 'tcx>(
                 layout,
                 tag_type_metadata: discriminant_type_metadata,
                 common_members: vec![],
-                span,
             }),
         );
     }
@@ -2272,11 +2208,8 @@ fn prepare_enum_metadata<'ll, 'tcx>(
     let outer_fields = match layout.variants {
         Variants::Single { .. } => vec![],
         Variants::Multiple { .. } => {
-            let tuple_mdf = TupleMemberDescriptionFactory {
-                ty: enum_type,
-                component_types: outer_field_tys,
-                span,
-            };
+            let tuple_mdf =
+                TupleMemberDescriptionFactory { ty: enum_type, component_types: outer_field_tys };
             tuple_mdf
                 .create_member_descriptions(cx)
                 .into_iter()
@@ -2352,7 +2285,6 @@ fn prepare_enum_metadata<'ll, 'tcx>(
             layout,
             tag_type_metadata: None,
             common_members: outer_fields,
-            span,
         }),
     )
 }
@@ -2368,11 +2300,6 @@ fn composite_type_metadata<'ll, 'tcx>(
     composite_type_unique_id: UniqueTypeId,
     member_descriptions: Vec<MemberDescription<'ll>>,
     containing_scope: Option<&'ll DIScope>,
-
-    // Ignore source location information as long as it
-    // can't be reconstructed for non-local crates.
-    _file_metadata: &'ll DIFile,
-    _definition_span: Span,
 ) -> &'ll DICompositeType {
     // Create the (empty) struct metadata node ...
     let composite_type_metadata = create_struct_stub(
@@ -2450,8 +2377,7 @@ fn compute_type_parameters<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -
                     if let GenericArgKind::Type(ty) = kind.unpack() {
                         let actual_type =
                             cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
-                        let actual_type_metadata =
-                            type_metadata(cx, actual_type, rustc_span::DUMMY_SP);
+                        let actual_type_metadata = type_metadata(cx, actual_type);
                         let name = name.as_str();
                         Some(unsafe {
                             Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
@@ -2593,7 +2519,7 @@ pub fn create_global_var_metadata<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, g
 
     let is_local_to_unit = is_node_local_to_unit(cx, def_id);
     let variable_type = Instance::mono(cx.tcx, def_id).ty(cx.tcx, ty::ParamEnv::reveal_all());
-    let type_metadata = type_metadata(cx, variable_type, span);
+    let type_metadata = type_metadata(cx, variable_type);
     let var_name = tcx.item_name(def_id);
     let var_name = var_name.as_str();
     let linkage_name = mangled_name_of_instance(cx, Instance::mono(tcx, def_id)).name;
@@ -2648,7 +2574,7 @@ fn vtable_type_metadata<'ll, 'tcx>(
     //        things simple instead of adding some ad-hoc disambiguation scheme.
     let vtable_type = tcx.mk_array(tcx.mk_imm_ptr(tcx.types.unit), vtable_entries.len() as u64);
 
-    type_metadata(cx, vtable_type, rustc_span::DUMMY_SP)
+    type_metadata(cx, vtable_type)
 }
 
 /// Creates debug information for the given vtable, which is for the
index 01f7868df3492ee52fe3d14b053600984eee7983..61e49fab6ff8876e7cf9b3c058c8e871b7a2f962 100644 (file)
@@ -390,7 +390,7 @@ fn get_function_signature<'ll, 'tcx>(
             signature.push(if fn_abi.ret.is_ignore() {
                 None
             } else {
-                Some(type_metadata(cx, fn_abi.ret.layout.ty, rustc_span::DUMMY_SP))
+                Some(type_metadata(cx, fn_abi.ret.layout.ty))
             });
 
             // Arguments types
@@ -415,15 +415,11 @@ fn get_function_signature<'ll, 'tcx>(
                         }
                         _ => t,
                     };
-                    Some(type_metadata(cx, t, rustc_span::DUMMY_SP))
+                    Some(type_metadata(cx, t))
                 }));
             } else {
-                signature.extend(
-                    fn_abi
-                        .args
-                        .iter()
-                        .map(|arg| Some(type_metadata(cx, arg.layout.ty, rustc_span::DUMMY_SP))),
-                );
+                signature
+                    .extend(fn_abi.args.iter().map(|arg| Some(type_metadata(cx, arg.layout.ty))));
             }
 
             create_DIArray(DIB(cx), &signature[..])
@@ -453,8 +449,7 @@ fn get_template_parameters<'ll, 'tcx>(
                         if let GenericArgKind::Type(ty) = kind.unpack() {
                             let actual_type =
                                 cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
-                            let actual_type_metadata =
-                                type_metadata(cx, actual_type, rustc_span::DUMMY_SP);
+                            let actual_type_metadata = type_metadata(cx, actual_type);
                             let name = name.as_str();
                             Some(unsafe {
                                 Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
@@ -507,9 +502,9 @@ 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))
+                                Some(type_metadata(cx, impl_self_ty))
                             } else {
                                 Some(namespace::item_namespace(cx, def.did))
                             }
@@ -584,7 +579,7 @@ fn create_dbg_var(
         let loc = self.lookup_debug_loc(span.lo());
         let file_metadata = file_metadata(self, &loc.file);
 
-        let type_metadata = type_metadata(self, variable_type, span);
+        let type_metadata = type_metadata(self, variable_type);
 
         let (argument_index, dwarf_tag) = match variable_kind {
             ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
index 07d49b6e72996d47f126f89e9fda1f1602e98c57..5adfa18035a0e2efbd53c159723c9fb52327a39d 100644 (file)
@@ -7,7 +7,6 @@
 use crate::va_arg::emit_va_arg;
 use crate::value::Value;
 
-use rustc_ast as ast;
 use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
 use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
@@ -351,7 +350,7 @@ fn codegen_intrinsic_call(
                     self.type_void(),
                     true,
                     false,
-                    ast::LlvmAsmDialect::Att,
+                    llvm::AsmDialect::Att,
                     &[span],
                     false,
                     None,
@@ -791,7 +790,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,
@@ -1689,7 +1688,7 @@ macro_rules! bitwise_red {
     bitwise_red!(simd_reduce_all: vector_reduce_and, true);
     bitwise_red!(simd_reduce_any: vector_reduce_or, true);
 
-    if name == sym::simd_cast {
+    if name == sym::simd_cast || name == sym::simd_as {
         require_simd!(ret_ty, "return");
         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
         require!(
@@ -1715,14 +1714,26 @@ enum Style {
         let (in_style, in_width) = match in_elem.kind() {
             // vectors of pointer-sized integers should've been
             // disallowed before here, so this unwrap is safe.
-            ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()),
-            ty::Uint(u) => (Style::Int(false), u.bit_width().unwrap()),
+            ty::Int(i) => (
+                Style::Int(true),
+                i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
+            ty::Uint(u) => (
+                Style::Int(false),
+                u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
             ty::Float(f) => (Style::Float, f.bit_width()),
             _ => (Style::Unsupported, 0),
         };
         let (out_style, out_width) = match out_elem.kind() {
-            ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()),
-            ty::Uint(u) => (Style::Int(false), u.bit_width().unwrap()),
+            ty::Int(i) => (
+                Style::Int(true),
+                i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
+            ty::Uint(u) => (
+                Style::Int(false),
+                u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
+            ),
             ty::Float(f) => (Style::Float, f.bit_width()),
             _ => (Style::Unsupported, 0),
         };
@@ -1749,10 +1760,10 @@ enum Style {
                 });
             }
             (Style::Float, Style::Int(out_is_signed)) => {
-                return Ok(if out_is_signed {
-                    bx.fptosi(args[0].immediate(), llret_ty)
-                } else {
-                    bx.fptoui(args[0].immediate(), llret_ty)
+                return Ok(match (out_is_signed, name == sym::simd_as) {
+                    (false, false) => bx.fptoui(args[0].immediate(), llret_ty),
+                    (true, false) => bx.fptosi(args[0].immediate(), llret_ty),
+                    (_, true) => bx.cast_float_to_int(out_is_signed, args[0].immediate(), llret_ty),
                 });
             }
             (Style::Float, Style::Float) => {
index f2782f84f557bde27a416bc6bb1b19d3716109b3..a1c7d2b4f6156d9bdb3f76f07d1e20905cd57e0a 100644 (file)
@@ -423,22 +423,13 @@ pub enum MetadataType {
 }
 
 /// LLVMRustAsmDialect
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, PartialEq)]
 #[repr(C)]
 pub enum AsmDialect {
     Att,
     Intel,
 }
 
-impl AsmDialect {
-    pub fn from_generic(asm: rustc_ast::LlvmAsmDialect) -> Self {
-        match asm {
-            rustc_ast::LlvmAsmDialect::Att => AsmDialect::Att,
-            rustc_ast::LlvmAsmDialect::Intel => AsmDialect::Intel,
-        }
-    }
-}
-
 /// LLVMRustCodeGenOptLevel
 #[derive(Copy, Clone, PartialEq)]
 #[repr(C)]
@@ -2329,7 +2320,6 @@ pub fn LLVMRustPrintModule(
     pub fn LLVMRustSetNormalizedTarget(M: &Module, triple: *const c_char);
     pub fn LLVMRustAddAlwaysInlinePass(P: &PassManagerBuilder, AddLifetimes: bool);
     pub fn LLVMRustRunRestrictionPass(M: &Module, syms: *const *const c_char, len: size_t);
-    pub fn LLVMRustMarkAllFunctionsNounwind(M: &Module);
 
     pub fn LLVMRustOpenArchive(path: *const c_char) -> Option<&'static mut Archive>;
     pub fn LLVMRustArchiveIteratorNew(AR: &Archive) -> &mut ArchiveIterator<'_>;
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 5c13dfdc1b50537e8811c2bca03d1f2608495b4d..6c6ee363ea310c1480c3208d2c3596793a4167cd 100644 (file)
@@ -41,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 f7fe194d207d31faf611f23d877195b93bd83ba6..acf65259f61cf03a07ec42dc0fa5f7f66583e390 100644 (file)
@@ -667,7 +667,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
         cmd.env_remove(k);
     }
 
-    if sess.opts.debugging_opts.print_link_args {
+    if sess.opts.prints.contains(&PrintRequest::LinkArgs) {
         println!("{:?}", &cmd);
     }
 
index 79c24f0f17280ac73821d47a532f467fa5cf5656..6849533abc049e7098e8ee154b08bb23d1ed3f9d 100644 (file)
@@ -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") => {
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 bea454458c4c028170767eac17cd63b29acb43a9..540979ce02d8fde47e148478b5cfb5d34c7ff466 100644 (file)
@@ -32,7 +32,7 @@
 use rustc_span::source_map::SourceMap;
 use rustc_span::symbol::sym;
 use rustc_span::{BytePos, FileName, InnerSpan, Pos, Span};
-use rustc_target::spec::{MergeFunctions, PanicStrategy, SanitizerSet};
+use rustc_target::spec::{MergeFunctions, SanitizerSet};
 
 use std::any::Any;
 use std::fs;
@@ -313,7 +313,6 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     pub backend: B,
     pub prof: SelfProfilerRef,
     pub lto: Lto,
-    pub no_landing_pads: bool,
     pub save_temps: bool,
     pub fewer_names: bool,
     pub time_trace: bool,
@@ -1039,7 +1038,6 @@ fn start_executing_work<B: ExtraBackendMethods>(
         crate_types: sess.crate_types().to_vec(),
         each_linked_rlib_for_lto,
         lto: sess.lto(),
-        no_landing_pads: sess.panic_strategy() == PanicStrategy::Abort,
         fewer_names: sess.fewer_names(),
         save_temps: sess.opts.cg.save_temps,
         time_trace: sess.opts.debugging_opts.llvm_time_trace,
index 93bb1aee25f7d25d9aca664a58275d30fa9c3f17..9687fd09a53bc091bf86ef6c6de488a7304f463d 100644 (file)
@@ -203,8 +203,9 @@ fn push_debuginfo_type_name<'tcx>(
                 let projection_bounds: SmallVec<[_; 4]> = trait_data
                     .projection_bounds()
                     .map(|bound| {
-                        let ExistentialProjection { item_def_id, ty, .. } = bound.skip_binder();
-                        (item_def_id, ty)
+                        let ExistentialProjection { item_def_id, term, .. } = bound.skip_binder();
+                        // FIXME(associated_const_equality): allow for consts here
+                        (item_def_id, term.ty().unwrap())
                     })
                     .collect();
 
@@ -409,14 +410,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));
             }
@@ -519,12 +520,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_debuginfo(tcx) {
-                write!(output, "generator${}", disambiguated_data.disambiguator).unwrap();
+                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() {
index b1b3f1d6d81b97d3689da5da1ea21f03ed848af8..d768d4920c5b45009da0e30a3a042d2cf82b3625 100644 (file)
@@ -211,7 +211,6 @@ fn visit_local(&mut self, &local: &mir::Local, context: PlaceContext, location:
 
             PlaceContext::MutatingUse(
                 MutatingUseContext::Store
-                | MutatingUseContext::LlvmAsmOutput
                 | MutatingUseContext::AsmOutput
                 | MutatingUseContext::Borrow
                 | MutatingUseContext::AddressOf
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 4b07ed1a1e6c2b2bf884db3b94d42b206c58b9d4..c21d19a62279ff4aa35435c1ac392d63378b905c 100644 (file)
@@ -429,87 +429,78 @@ pub fn codegen_place(
         let cx = self.cx;
         let tcx = self.cx.tcx();
 
-        let result = match place_ref {
-            mir::PlaceRef { local, projection: [] } => match self.locals[local] {
-                LocalRef::Place(place) => {
-                    return place;
-                }
-                LocalRef::UnsizedPlace(place) => {
-                    return bx.load_operand(place).deref(cx);
-                }
-                LocalRef::Operand(..) => {
+        let mut base = 0;
+        let mut cg_base = match self.locals[place_ref.local] {
+            LocalRef::Place(place) => place,
+            LocalRef::UnsizedPlace(place) => bx.load_operand(place).deref(cx),
+            LocalRef::Operand(..) => {
+                if let Some(elem) = place_ref
+                    .projection
+                    .iter()
+                    .enumerate()
+                    .find(|elem| matches!(elem.1, mir::ProjectionElem::Deref))
+                {
+                    base = elem.0 + 1;
+                    self.codegen_consume(
+                        bx,
+                        mir::PlaceRef { projection: &place_ref.projection[..elem.0], ..place_ref },
+                    )
+                    .deref(bx.cx())
+                } else {
                     bug!("using operand local {:?} as place", place_ref);
                 }
-            },
-            mir::PlaceRef { local, projection: [proj_base @ .., mir::ProjectionElem::Deref] } => {
-                // Load the pointer from its location.
-                self.codegen_consume(bx, mir::PlaceRef { local, projection: proj_base })
-                    .deref(bx.cx())
             }
-            mir::PlaceRef { local, projection: &[ref proj_base @ .., elem] } => {
-                // FIXME turn this recursion into iteration
-                let cg_base =
-                    self.codegen_place(bx, mir::PlaceRef { local, projection: proj_base });
-
-                match elem {
-                    mir::ProjectionElem::Deref => bug!(),
-                    mir::ProjectionElem::Field(ref field, _) => {
-                        cg_base.project_field(bx, field.index())
-                    }
-                    mir::ProjectionElem::Index(index) => {
-                        let index = &mir::Operand::Copy(mir::Place::from(index));
-                        let index = self.codegen_operand(bx, index);
-                        let llindex = index.immediate();
-                        cg_base.project_index(bx, llindex)
-                    }
-                    mir::ProjectionElem::ConstantIndex {
-                        offset,
-                        from_end: false,
-                        min_length: _,
-                    } => {
-                        let lloffset = bx.cx().const_usize(offset as u64);
-                        cg_base.project_index(bx, lloffset)
-                    }
-                    mir::ProjectionElem::ConstantIndex {
-                        offset,
-                        from_end: true,
-                        min_length: _,
-                    } => {
-                        let lloffset = bx.cx().const_usize(offset as u64);
-                        let lllen = cg_base.len(bx.cx());
-                        let llindex = bx.sub(lllen, lloffset);
-                        cg_base.project_index(bx, llindex)
-                    }
-                    mir::ProjectionElem::Subslice { from, to, from_end } => {
-                        let mut subslice =
-                            cg_base.project_index(bx, bx.cx().const_usize(from as u64));
-                        let projected_ty =
-                            PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem).ty;
-                        subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty));
-
-                        if subslice.layout.is_unsized() {
-                            assert!(from_end, "slice subslices should be `from_end`");
-                            subslice.llextra = Some(bx.sub(
-                                cg_base.llextra.unwrap(),
-                                bx.cx().const_usize((from as u64) + (to as u64)),
-                            ));
-                        }
-
-                        // Cast the place pointer type to the new
-                        // array or slice type (`*[%_; new_len]`).
-                        subslice.llval = bx.pointercast(
-                            subslice.llval,
-                            bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout)),
-                        );
-
-                        subslice
+        };
+        for elem in place_ref.projection[base..].iter() {
+            cg_base = match elem.clone() {
+                mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()),
+                mir::ProjectionElem::Field(ref field, _) => {
+                    cg_base.project_field(bx, field.index())
+                }
+                mir::ProjectionElem::Index(index) => {
+                    let index = &mir::Operand::Copy(mir::Place::from(index));
+                    let index = self.codegen_operand(bx, index);
+                    let llindex = index.immediate();
+                    cg_base.project_index(bx, llindex)
+                }
+                mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => {
+                    let lloffset = bx.cx().const_usize(offset as u64);
+                    cg_base.project_index(bx, lloffset)
+                }
+                mir::ProjectionElem::ConstantIndex { offset, from_end: true, min_length: _ } => {
+                    let lloffset = bx.cx().const_usize(offset as u64);
+                    let lllen = cg_base.len(bx.cx());
+                    let llindex = bx.sub(lllen, lloffset);
+                    cg_base.project_index(bx, llindex)
+                }
+                mir::ProjectionElem::Subslice { from, to, from_end } => {
+                    let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from as u64));
+                    let projected_ty =
+                        PlaceTy::from_ty(cg_base.layout.ty).projection_ty(tcx, elem.clone()).ty;
+                    subslice.layout = bx.cx().layout_of(self.monomorphize(projected_ty));
+
+                    if subslice.layout.is_unsized() {
+                        assert!(from_end, "slice subslices should be `from_end`");
+                        subslice.llextra = Some(bx.sub(
+                            cg_base.llextra.unwrap(),
+                            bx.cx().const_usize((from as u64) + (to as u64)),
+                        ));
                     }
-                    mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
+
+                    // Cast the place pointer type to the new
+                    // array or slice type (`*[%_; new_len]`).
+                    subslice.llval = bx.pointercast(
+                        subslice.llval,
+                        bx.cx().type_ptr_to(bx.cx().backend_type(subslice.layout)),
+                    );
+
+                    subslice
                 }
-            }
-        };
-        debug!("codegen_place(place={:?}) => {:?}", place_ref, result);
-        result
+                mir::ProjectionElem::Downcast(_, v) => cg_base.project_downcast(bx, v),
+            };
+        }
+        debug!("codegen_place(place={:?}) => {:?}", place_ref, cg_base);
+        cg_base
     }
 
     pub fn monomorphized_place_ty(&self, place_ref: mir::PlaceRef<'tcx>) -> Ty<'tcx> {
index 679c45767018d2810025de4ff761e964b98c3225..68decce82ab52a44bdd6aa83235e4ce040c54ced 100644 (file)
@@ -3,11 +3,10 @@
 use super::{FunctionCx, LocalRef};
 
 use crate::base;
-use crate::common::{self, IntPredicate, RealPredicate};
+use crate::common::{self, IntPredicate};
 use crate::traits::*;
 use crate::MemFlags;
 
-use rustc_apfloat::{ieee, Float, Round, Status};
 use rustc_middle::mir;
 use rustc_middle::ty::cast::{CastTy, IntTy};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
@@ -368,10 +367,10 @@ pub fn codegen_rvalue_operand(
                                 bx.inttoptr(usize_llval, ll_t_out)
                             }
                             (CastTy::Float, CastTy::Int(IntTy::I)) => {
-                                cast_float_to_int(&mut bx, true, llval, ll_t_in, ll_t_out)
+                                bx.cast_float_to_int(true, llval, ll_t_out)
                             }
                             (CastTy::Float, CastTy::Int(_)) => {
-                                cast_float_to_int(&mut bx, false, llval, ll_t_in, ll_t_out)
+                                bx.cast_float_to_int(false, llval, ll_t_out)
                             }
                             _ => bug!("unsupported cast: {:?} to {:?}", operand.layout.ty, cast.ty),
                         };
@@ -768,146 +767,3 @@ pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) ->
         // (*) this is only true if the type is suitable
     }
 }
-
-fn cast_float_to_int<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
-    bx: &mut Bx,
-    signed: bool,
-    x: Bx::Value,
-    float_ty: Bx::Type,
-    int_ty: Bx::Type,
-) -> Bx::Value {
-    if let Some(false) = bx.cx().sess().opts.debugging_opts.saturating_float_casts {
-        return if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) };
-    }
-
-    let try_sat_result = if signed { bx.fptosi_sat(x, int_ty) } else { bx.fptoui_sat(x, int_ty) };
-    if let Some(try_sat_result) = try_sat_result {
-        return try_sat_result;
-    }
-
-    let int_width = bx.cx().int_width(int_ty);
-    let float_width = bx.cx().float_width(float_ty);
-    // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the
-    // destination integer type after rounding towards zero. This `undef` value can cause UB in
-    // safe code (see issue #10184), so we implement a saturating conversion on top of it:
-    // Semantically, the mathematical value of the input is rounded towards zero to the next
-    // mathematical integer, and then the result is clamped into the range of the destination
-    // integer type. Positive and negative infinity are mapped to the maximum and minimum value of
-    // the destination integer type. NaN is mapped to 0.
-    //
-    // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to
-    // a value representable in int_ty.
-    // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits.
-    // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two.
-    // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly
-    // representable. Note that this only works if float_ty's exponent range is sufficiently large.
-    // f16 or 256 bit integers would break this property. Right now the smallest float type is f32
-    // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127.
-    // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
-    // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
-    // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
-    let int_max = |signed: bool, int_width: u64| -> u128 {
-        let shift_amount = 128 - int_width;
-        if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
-    };
-    let int_min = |signed: bool, int_width: u64| -> i128 {
-        if signed { i128::MIN >> (128 - int_width) } else { 0 }
-    };
-
-    let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
-        let rounded_min = ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
-        assert_eq!(rounded_min.status, Status::OK);
-        let rounded_max = ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero);
-        assert!(rounded_max.value.is_finite());
-        (rounded_min.value.to_bits(), rounded_max.value.to_bits())
-    };
-    let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
-        let rounded_min = ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
-        assert_eq!(rounded_min.status, Status::OK);
-        let rounded_max = ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
-        assert!(rounded_max.value.is_finite());
-        (rounded_min.value.to_bits(), rounded_max.value.to_bits())
-    };
-
-    let mut float_bits_to_llval = |bits| {
-        let bits_llval = match float_width {
-            32 => bx.cx().const_u32(bits as u32),
-            64 => bx.cx().const_u64(bits as u64),
-            n => bug!("unsupported float width {}", n),
-        };
-        bx.bitcast(bits_llval, float_ty)
-    };
-    let (f_min, f_max) = match float_width {
-        32 => compute_clamp_bounds_single(signed, int_width),
-        64 => compute_clamp_bounds_double(signed, int_width),
-        n => bug!("unsupported float width {}", n),
-    };
-    let f_min = float_bits_to_llval(f_min);
-    let f_max = float_bits_to_llval(f_max);
-    // To implement saturation, we perform the following steps:
-    //
-    // 1. Cast x to an integer with fpto[su]i. This may result in undef.
-    // 2. Compare x to f_min and f_max, and use the comparison results to select:
-    //  a) int_ty::MIN if x < f_min or x is NaN
-    //  b) int_ty::MAX if x > f_max
-    //  c) the result of fpto[su]i otherwise
-    // 3. If x is NaN, return 0.0, otherwise return the result of step 2.
-    //
-    // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the
-    // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of
-    // undef does not introduce any non-determinism either.
-    // More importantly, the above procedure correctly implements saturating conversion.
-    // Proof (sketch):
-    // If x is NaN, 0 is returned by definition.
-    // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max.
-    // This yields three cases to consider:
-    // (1) if x in [f_min, f_max], the result of fpto[su]i is returned, which agrees with
-    //     saturating conversion for inputs in that range.
-    // (2) if x > f_max, then x is larger than int_ty::MAX. This holds even if f_max is rounded
-    //     (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger
-    //     than int_ty::MAX. Because x is larger than int_ty::MAX, the return value of int_ty::MAX
-    //     is correct.
-    // (3) if x < f_min, then x is smaller than int_ty::MIN. As shown earlier, f_min exactly equals
-    //     int_ty::MIN and therefore the return value of int_ty::MIN is correct.
-    // QED.
-
-    let int_max = bx.cx().const_uint_big(int_ty, int_max(signed, int_width));
-    let int_min = bx.cx().const_uint_big(int_ty, int_min(signed, int_width) as u128);
-    let zero = bx.cx().const_uint(int_ty, 0);
-
-    // Step 1 ...
-    let fptosui_result = if signed { bx.fptosi(x, int_ty) } else { bx.fptoui(x, int_ty) };
-    let less_or_nan = bx.fcmp(RealPredicate::RealULT, x, f_min);
-    let greater = bx.fcmp(RealPredicate::RealOGT, x, f_max);
-
-    // Step 2: We use two comparisons and two selects, with %s1 being the
-    // result:
-    //     %less_or_nan = fcmp ult %x, %f_min
-    //     %greater = fcmp olt %x, %f_max
-    //     %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
-    //     %s1 = select %greater, int_ty::MAX, %s0
-    // Note that %less_or_nan uses an *unordered* comparison. This
-    // comparison is true if the operands are not comparable (i.e., if x is
-    // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
-    // x is NaN.
-    //
-    // Performance note: Unordered comparison can be lowered to a "flipped"
-    // comparison and a negation, and the negation can be merged into the
-    // select. Therefore, it not necessarily any more expensive than an
-    // ordered ("normal") comparison. Whether these optimizations will be
-    // performed is ultimately up to the backend, but at least x86 does
-    // perform them.
-    let s0 = bx.select(less_or_nan, int_min, fptosui_result);
-    let s1 = bx.select(greater, int_max, s0);
-
-    // Step 3: NaN replacement.
-    // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN.
-    // Therefore we only need to execute this step for signed integer types.
-    if signed {
-        // LLVM has no isNaN predicate, so we use (x == x) instead
-        let cmp = bx.fcmp(RealPredicate::RealOEQ, x, x);
-        bx.select(cmp, s1, zero)
-    } else {
-        s1
-    }
-}
index 2c96987d3399eb63f25d0a32ca0db16f3d5c4492..773dc2adcfa0c93705c544bffa4c8a517cd7440e 100644 (file)
@@ -1,9 +1,7 @@
-use rustc_errors::struct_span_err;
 use rustc_middle::mir;
 
 use super::FunctionCx;
 use super::LocalRef;
-use super::OperandValue;
 use crate::traits::BuilderMethods;
 use crate::traits::*;
 
@@ -66,51 +64,6 @@ pub fn codegen_statement(&mut self, mut bx: Bx, statement: &mir::Statement<'tcx>
                 }
                 bx
             }
-            mir::StatementKind::LlvmInlineAsm(ref asm) => {
-                let outputs = asm
-                    .outputs
-                    .iter()
-                    .map(|output| self.codegen_place(&mut bx, output.as_ref()))
-                    .collect();
-
-                let input_vals = asm.inputs.iter().fold(
-                    Vec::with_capacity(asm.inputs.len()),
-                    |mut acc, (span, input)| {
-                        let op = self.codegen_operand(&mut bx, input);
-                        if let OperandValue::Immediate(_) = op.val {
-                            acc.push(op.immediate());
-                        } else {
-                            struct_span_err!(
-                                bx.sess(),
-                                span.to_owned(),
-                                E0669,
-                                "invalid value for constraint in inline assembly"
-                            )
-                            .emit();
-                        }
-                        acc
-                    },
-                );
-
-                if input_vals.len() == asm.inputs.len() {
-                    let res = bx.codegen_llvm_inline_asm(
-                        &asm.asm,
-                        outputs,
-                        input_vals,
-                        statement.source_info.span,
-                    );
-                    if !res {
-                        struct_span_err!(
-                            bx.sess(),
-                            statement.source_info.span,
-                            E0668,
-                            "malformed inline assembly"
-                        )
-                        .emit();
-                    }
-                }
-                bx
-            }
             mir::StatementKind::Coverage(box ref coverage) => {
                 self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
                 bx
index 65f3c754d2dccf408f5d84bee432c260f4bb58bf..11111a7974410f1d9ab2ebe377bf7a6ade571c1d 100644 (file)
@@ -3,7 +3,6 @@
 use crate::mir::place::PlaceRef;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_hir::def_id::DefId;
-use rustc_hir::LlvmInlineAsmInner;
 use rustc_middle::ty::Instance;
 use rustc_span::Span;
 use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -42,15 +41,6 @@ pub enum GlobalAsmOperandRef {
 }
 
 pub trait AsmBuilderMethods<'tcx>: BackendTypes {
-    /// Take an inline assembly expression and splat it out via LLVM
-    fn codegen_llvm_inline_asm(
-        &mut self,
-        ia: &LlvmInlineAsmInner,
-        outputs: Vec<PlaceRef<'tcx, Self::Value>>,
-        inputs: Vec<Self::Value>,
-        span: Span,
-    ) -> bool;
-
     /// Take an inline assembly expression and splat it out via LLVM
     fn codegen_inline_asm(
         &mut self,
index 48d88095855d11300667659b63d76e3fdc5f4963..5a06fb4610587963b923e46be227a4e85fc61499 100644 (file)
@@ -1,18 +1,21 @@
 use super::abi::AbiBuilderMethods;
 use super::asm::AsmBuilderMethods;
+use super::consts::ConstMethods;
 use super::coverageinfo::CoverageInfoBuilderMethods;
 use super::debuginfo::DebugInfoBuilderMethods;
 use super::intrinsic::IntrinsicCallMethods;
-use super::type_::ArgAbiMethods;
+use super::misc::MiscMethods;
+use super::type_::{ArgAbiMethods, BaseTypeMethods};
 use super::{HasCodegen, StaticBuilderMethods};
 
 use crate::common::{
-    AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope,
+    AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope, TypeKind,
 };
 use crate::mir::operand::OperandRef;
 use crate::mir::place::PlaceRef;
 use crate::MemFlags;
 
+use rustc_apfloat::{ieee, Float, Round, Status};
 use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
 use rustc_middle::ty::Ty;
 use rustc_span::Span;
@@ -202,6 +205,179 @@ fn inbounds_gep(
     fn intcast(&mut self, val: Self::Value, dest_ty: Self::Type, is_signed: bool) -> Self::Value;
     fn pointercast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value;
 
+    fn cast_float_to_int(
+        &mut self,
+        signed: bool,
+        x: Self::Value,
+        dest_ty: Self::Type,
+    ) -> Self::Value {
+        let in_ty = self.cx().val_ty(x);
+        let (float_ty, int_ty) = if self.cx().type_kind(dest_ty) == TypeKind::Vector
+            && self.cx().type_kind(in_ty) == TypeKind::Vector
+        {
+            (self.cx().element_type(in_ty), self.cx().element_type(dest_ty))
+        } else {
+            (in_ty, dest_ty)
+        };
+        assert!(matches!(self.cx().type_kind(float_ty), TypeKind::Float | TypeKind::Double));
+        assert_eq!(self.cx().type_kind(int_ty), TypeKind::Integer);
+
+        if let Some(false) = self.cx().sess().opts.debugging_opts.saturating_float_casts {
+            return if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) };
+        }
+
+        let try_sat_result =
+            if signed { self.fptosi_sat(x, dest_ty) } else { self.fptoui_sat(x, dest_ty) };
+        if let Some(try_sat_result) = try_sat_result {
+            return try_sat_result;
+        }
+
+        let int_width = self.cx().int_width(int_ty);
+        let float_width = self.cx().float_width(float_ty);
+        // LLVM's fpto[su]i returns undef when the input x is infinite, NaN, or does not fit into the
+        // destination integer type after rounding towards zero. This `undef` value can cause UB in
+        // safe code (see issue #10184), so we implement a saturating conversion on top of it:
+        // Semantically, the mathematical value of the input is rounded towards zero to the next
+        // mathematical integer, and then the result is clamped into the range of the destination
+        // integer type. Positive and negative infinity are mapped to the maximum and minimum value of
+        // the destination integer type. NaN is mapped to 0.
+        //
+        // Define f_min and f_max as the largest and smallest (finite) floats that are exactly equal to
+        // a value representable in int_ty.
+        // They are exactly equal to int_ty::{MIN,MAX} if float_ty has enough significand bits.
+        // Otherwise, int_ty::MAX must be rounded towards zero, as it is one less than a power of two.
+        // int_ty::MIN, however, is either zero or a negative power of two and is thus exactly
+        // representable. Note that this only works if float_ty's exponent range is sufficiently large.
+        // f16 or 256 bit integers would break this property. Right now the smallest float type is f32
+        // with exponents ranging up to 127, which is barely enough for i128::MIN = -2^127.
+        // On the other hand, f_max works even if int_ty::MAX is greater than float_ty::MAX. Because
+        // we're rounding towards zero, we just get float_ty::MAX (which is always an integer).
+        // This already happens today with u128::MAX = 2^128 - 1 > f32::MAX.
+        let int_max = |signed: bool, int_width: u64| -> u128 {
+            let shift_amount = 128 - int_width;
+            if signed { i128::MAX as u128 >> shift_amount } else { u128::MAX >> shift_amount }
+        };
+        let int_min = |signed: bool, int_width: u64| -> i128 {
+            if signed { i128::MIN >> (128 - int_width) } else { 0 }
+        };
+
+        let compute_clamp_bounds_single = |signed: bool, int_width: u64| -> (u128, u128) {
+            let rounded_min =
+                ieee::Single::from_i128_r(int_min(signed, int_width), Round::TowardZero);
+            assert_eq!(rounded_min.status, Status::OK);
+            let rounded_max =
+                ieee::Single::from_u128_r(int_max(signed, int_width), Round::TowardZero);
+            assert!(rounded_max.value.is_finite());
+            (rounded_min.value.to_bits(), rounded_max.value.to_bits())
+        };
+        let compute_clamp_bounds_double = |signed: bool, int_width: u64| -> (u128, u128) {
+            let rounded_min =
+                ieee::Double::from_i128_r(int_min(signed, int_width), Round::TowardZero);
+            assert_eq!(rounded_min.status, Status::OK);
+            let rounded_max =
+                ieee::Double::from_u128_r(int_max(signed, int_width), Round::TowardZero);
+            assert!(rounded_max.value.is_finite());
+            (rounded_min.value.to_bits(), rounded_max.value.to_bits())
+        };
+        // To implement saturation, we perform the following steps:
+        //
+        // 1. Cast x to an integer with fpto[su]i. This may result in undef.
+        // 2. Compare x to f_min and f_max, and use the comparison results to select:
+        //  a) int_ty::MIN if x < f_min or x is NaN
+        //  b) int_ty::MAX if x > f_max
+        //  c) the result of fpto[su]i otherwise
+        // 3. If x is NaN, return 0.0, otherwise return the result of step 2.
+        //
+        // This avoids resulting undef because values in range [f_min, f_max] by definition fit into the
+        // destination type. It creates an undef temporary, but *producing* undef is not UB. Our use of
+        // undef does not introduce any non-determinism either.
+        // More importantly, the above procedure correctly implements saturating conversion.
+        // Proof (sketch):
+        // If x is NaN, 0 is returned by definition.
+        // Otherwise, x is finite or infinite and thus can be compared with f_min and f_max.
+        // This yields three cases to consider:
+        // (1) if x in [f_min, f_max], the result of fpto[su]i is returned, which agrees with
+        //     saturating conversion for inputs in that range.
+        // (2) if x > f_max, then x is larger than int_ty::MAX. This holds even if f_max is rounded
+        //     (i.e., if f_max < int_ty::MAX) because in those cases, nextUp(f_max) is already larger
+        //     than int_ty::MAX. Because x is larger than int_ty::MAX, the return value of int_ty::MAX
+        //     is correct.
+        // (3) if x < f_min, then x is smaller than int_ty::MIN. As shown earlier, f_min exactly equals
+        //     int_ty::MIN and therefore the return value of int_ty::MIN is correct.
+        // QED.
+
+        let float_bits_to_llval = |bx: &mut Self, bits| {
+            let bits_llval = match float_width {
+                32 => bx.cx().const_u32(bits as u32),
+                64 => bx.cx().const_u64(bits as u64),
+                n => bug!("unsupported float width {}", n),
+            };
+            bx.bitcast(bits_llval, float_ty)
+        };
+        let (f_min, f_max) = match float_width {
+            32 => compute_clamp_bounds_single(signed, int_width),
+            64 => compute_clamp_bounds_double(signed, int_width),
+            n => bug!("unsupported float width {}", n),
+        };
+        let f_min = float_bits_to_llval(self, f_min);
+        let f_max = float_bits_to_llval(self, f_max);
+        let int_max = self.cx().const_uint_big(int_ty, int_max(signed, int_width));
+        let int_min = self.cx().const_uint_big(int_ty, int_min(signed, int_width) as u128);
+        let zero = self.cx().const_uint(int_ty, 0);
+
+        // If we're working with vectors, constants must be "splatted": the constant is duplicated
+        // into each lane of the vector.  The algorithm stays the same, we are just using the
+        // same constant across all lanes.
+        let maybe_splat = |bx: &mut Self, val| {
+            if bx.cx().type_kind(dest_ty) == TypeKind::Vector {
+                bx.vector_splat(bx.vector_length(dest_ty), val)
+            } else {
+                val
+            }
+        };
+        let f_min = maybe_splat(self, f_min);
+        let f_max = maybe_splat(self, f_max);
+        let int_max = maybe_splat(self, int_max);
+        let int_min = maybe_splat(self, int_min);
+        let zero = maybe_splat(self, zero);
+
+        // Step 1 ...
+        let fptosui_result = if signed { self.fptosi(x, dest_ty) } else { self.fptoui(x, dest_ty) };
+        let less_or_nan = self.fcmp(RealPredicate::RealULT, x, f_min);
+        let greater = self.fcmp(RealPredicate::RealOGT, x, f_max);
+
+        // Step 2: We use two comparisons and two selects, with %s1 being the
+        // result:
+        //     %less_or_nan = fcmp ult %x, %f_min
+        //     %greater = fcmp olt %x, %f_max
+        //     %s0 = select %less_or_nan, int_ty::MIN, %fptosi_result
+        //     %s1 = select %greater, int_ty::MAX, %s0
+        // Note that %less_or_nan uses an *unordered* comparison. This
+        // comparison is true if the operands are not comparable (i.e., if x is
+        // NaN). The unordered comparison ensures that s1 becomes int_ty::MIN if
+        // x is NaN.
+        //
+        // Performance note: Unordered comparison can be lowered to a "flipped"
+        // comparison and a negation, and the negation can be merged into the
+        // select. Therefore, it not necessarily any more expensive than an
+        // ordered ("normal") comparison. Whether these optimizations will be
+        // performed is ultimately up to the backend, but at least x86 does
+        // perform them.
+        let s0 = self.select(less_or_nan, int_min, fptosui_result);
+        let s1 = self.select(greater, int_max, s0);
+
+        // Step 3: NaN replacement.
+        // For unsigned types, the above step already yielded int_ty::MIN == 0 if x is NaN.
+        // Therefore we only need to execute this step for signed integer types.
+        if signed {
+            // LLVM has no isNaN predicate, so we use (x == x) instead
+            let cmp = self.fcmp(RealPredicate::RealOEQ, x, x);
+            self.select(cmp, s1, zero)
+        } else {
+            s1
+        }
+    }
+
     fn icmp(&mut self, op: IntPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
     fn fcmp(&mut self, op: RealPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value;
 
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 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 3daa1d3c2b3e87ce3985f2f2ee234f5874feee5b..57ba9b4099232f0c7719b9781748e0c23c179c14 100644 (file)
@@ -140,8 +140,6 @@ pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
             // Defined to do nothing. These are added by optimization passes, to avoid changing the
             // size of MIR constantly.
             Nop => {}
-
-            LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
         }
 
         self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1;
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 dd749c0393473b06b42e3f49a4f541b73b9fa61c..6799514a4490db098206e2958dff72304158fb10 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,
 
@@ -752,10 +751,6 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         self.super_statement(statement, location);
 
         match statement.kind {
-            StatementKind::LlvmInlineAsm { .. } => {
-                self.check_op(ops::InlineAsm);
-            }
-
             StatementKind::Assign(..)
             | StatementKind::SetDiscriminant { .. }
             | StatementKind::FakeRead(..)
@@ -810,7 +805,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,
                         }),
                     );
@@ -829,6 +824,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 55fba5d7ddf69b6f4afacb52086d3ade40081b96..ac282a5ecc82c281454dcc0c83a31a4662bd7f3d 100644 (file)
@@ -843,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),
                             }),
                         })
@@ -969,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 c3f81a3ab838f5ffb2136e1d5f981e4d7a83fd84..22ef0b2dda50688197872161a8e26f27fe062f31 100644 (file)
@@ -352,7 +352,6 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
             StatementKind::SetDiscriminant { .. }
             | StatementKind::StorageLive(..)
             | StatementKind::StorageDead(..)
-            | StatementKind::LlvmInlineAsm(..)
             | StatementKind::Retag(_, _)
             | StatementKind::Coverage(_)
             | StatementKind::Nop => {}
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 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 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 694c679c1586efb40404f450ebd15ef9bfc7b0ca..19fa6812b45d9ff3c957ca0d021f22712daad686 100644 (file)
@@ -645,9 +645,9 @@ fn print_crate_info(
         temps_dir: &Option<PathBuf>,
     ) -> Compilation {
         use rustc_session::config::PrintRequest::*;
-        // PrintRequest::NativeStaticLibs is special - printed during linking
+        // NativeStaticLibs and LinkArgs are special - printed during linking
         // (empty iterator returns true)
-        if sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) {
+        if sess.opts.prints.iter().all(|&p| p == NativeStaticLibs || p == LinkArgs) {
             return Compilation::Continue;
         }
 
@@ -738,7 +738,8 @@ fn print_crate_info(
                     codegen_backend.print(*req, sess);
                 }
                 // Any output here interferes with Cargo's parsing of other printed output
-                PrintRequest::NativeStaticLibs => {}
+                NativeStaticLibs => {}
+                LinkArgs => {}
             }
         }
         Compilation::Stop
index ca2eaa54057fabb1f561ebd9631fb9c3f7cccbf1..584b78554ef88f1ac9d42a93df6af10d47bcbeb7 100644 (file)
@@ -15,7 +15,7 @@ Two general aspects of trait object types give rise to the restrictions:
      these types can only be accessed through pointers, such as `&dyn Trait` or
      `Box<dyn Trait>`. The size of such a pointer is known, but the size of the
      `dyn Trait` object pointed-to by the pointer is _opaque_ to code working
-     with it, and different tait objects with the same trait object type may
+     with it, and different trait objects with the same trait object type may
      have different sizes.
 
   2. The pointer used to access a trait object is paired with an extra pointer
@@ -167,7 +167,7 @@ implementation on-demand. If you call `foo()` with a `bool` parameter, the
 compiler will only generate code for `foo::<bool>()`. When we have additional
 type parameters, the number of monomorphized implementations the compiler
 generates does not grow drastically, since the compiler will only generate an
-implementation if the function is called with unparametrized substitutions
+implementation if the function is called with unparameterized substitutions
 (i.e., substitutions where none of the substituted types are themselves
 parameterized).
 
index 7e1d08daae1f2160eca47c5f3224de20b18d6d97..92fa4c7c21e72d84eece06829af306f34b77fe98 100644 (file)
@@ -1,4 +1,4 @@
-Manual implemetation of a `Fn*` trait.
+Manual implementation of a `Fn*` trait.
 
 Erroneous code example:
 
@@ -33,7 +33,7 @@ impl FnOnce<()> for MyClosure {  // ok!
 }
 ```
 
-The argumements must be a tuple representing the argument list.
+The arguments must be a tuple representing the argument list.
 For more info, see the [tracking issue][iss29625]:
 
 [iss29625]: https://github.com/rust-lang/rust/issues/29625
index 65dcac983acd5feac6fc1b3b151098c1480a9ef3..fedf6365fb5590d10489e4a04dd7081fa26d4a2b 100644 (file)
@@ -10,7 +10,7 @@ let _add = |el: &str| {
 };
 ```
 
-A type anotation of a closure parameter implies a new lifetime declaration.
+A type annotation of a closure parameter implies a new lifetime declaration.
 Consider to drop it, the compiler is reliably able to infer them.
 
 ```
index 89f6e3269ec36856a83a5cd23a72d39e0950ce33..02468dd946646eb25e0d31001076fe138118836a 100644 (file)
@@ -10,7 +10,7 @@ fn main() {
 }
 ```
 
-The problem here is that the lifetime isn't contrained by any of the arguments,
+The problem here is that the lifetime isn't constrained by any of the arguments,
 making it impossible to determine how long it's supposed to live.
 
 To fix this issue, either use the lifetime in the arguments, or use the
index 26d35f2620cb26ca249182672c6d0442bfe280ab..abf90275915e0344d007bf1283fc8af7e2c195fd 100644 (file)
@@ -1,12 +1,9 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 The argument to the `llvm_asm` macro is not well-formed.
 
 Erroneous code example:
 
-```compile_fail,E0660
+```ignore (no longer emitted)
 llvm_asm!("nop" "nop");
 ```
-
-Considering that this would be a long explanation, we instead recommend you
-take a look at the [`llvm_asm`] chapter of the Unstable book:
-
-[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
index 0b8ba7fbbedac76d1caf2fa17347e1eae0c07800..245f755cddd0d649fa0cc64e4b8ebe1571c2778b 100644 (file)
@@ -1,13 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 An invalid syntax was passed to the second argument of an `llvm_asm` macro line.
 
 Erroneous code example:
 
-```compile_fail,E0661
+```ignore (no longer emitted)
 let a;
 llvm_asm!("nop" : "r"(a));
 ```
-
-Considering that this would be a long explanation, we instead recommend you
-take a look at the [`llvm_asm`] chapter of the Unstable book:
-
-[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
index 8c1bab8d0410da5e0fcaef32ac3161488879cd65..ffb716f9957a00dc055fbb4f5f4db9381e48405f 100644 (file)
@@ -1,16 +1,13 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 An invalid input operand constraint was passed to the `llvm_asm` macro
 (third line).
 
 Erroneous code example:
 
-```compile_fail,E0662
+```ignore (no longer emitted)
 llvm_asm!("xor %eax, %eax"
           :
           : "=test"("a")
          );
 ```
-
-Considering that this would be a long explanation, we instead recommend you
-take a look at the [`llvm_asm`] chapter of the Unstable book:
-
-[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
index 53ffd3373a51c30cd43988ac59c2ae232523f637..351cfaca29c1901e7404afe38b18023b7b1c7e31 100644 (file)
@@ -1,16 +1,13 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 An invalid input operand constraint was passed to the `llvm_asm` macro
 (third line).
 
 Erroneous code example:
 
-```compile_fail,E0663
+```ignore (no longer emitted)
 llvm_asm!("xor %eax, %eax"
           :
           : "+test"("a")
          );
 ```
-
-Considering that this would be a long explanation, we instead recommend you
-take a look at the [`llvm_asm`] chapter of the Unstable book:
-
-[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
index f8e72cd330a31d91b2fcfc6816d304a02f2b159c..34135d5db33388f82e3ac4d69c9f33560fd032a2 100644 (file)
@@ -1,16 +1,13 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 A clobber was surrounded by braces in the `llvm_asm` macro.
 
 Erroneous code example:
 
-```compile_fail,E0664
+```ignore (no longer emitted)
 llvm_asm!("mov $$0x200, %eax"
           :
           :
           : "{eax}"
          );
 ```
-
-Considering that this would be a long explanation, we instead recommend you
-take a look at the [`llvm_asm`] chapter of the Unstable book:
-
-[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
index b6fedfe53fce8ad44656ea4027f0168ae7eca780..393aabe2894c78ef2f8964a748d5913bfe342aba 100644 (file)
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 Malformed inline assembly rejected by LLVM.
 
 Erroneous code example:
 
-```compile_fail,E0668
+```ignore (no longer emitted)
 #![feature(llvm_asm)]
 
 fn main() {
index f078c441b342190c61b9dd4ab042a746718a8029..2be8f04eda0b65ae4b6fb912b795165b8d300f58 100644 (file)
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 Cannot convert inline assembly operand to a single LLVM value.
 
 Erroneous code example:
 
-```compile_fail,E0669
+```ignore (no longer emitted)
 #![feature(llvm_asm)]
 
 fn main() {
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 e0bdeb30dc84bcfe70436b7bf9007fb4242db1e0..5fa7ffd554ef12b4edaa39ebb966e705cd38bb75 100644 (file)
@@ -328,6 +328,10 @@ fn process_cfg_attrs<T: AstLike>(&self, node: &mut T) {
         });
     }
 
+    fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> {
+        if attr.has_name(sym::cfg_attr) { self.expand_cfg_attr(attr, true) } else { vec![attr] }
+    }
+
     /// Parse and expand a single `cfg_attr` attribute into a list of attributes
     /// when the configuration predicate is true, or otherwise expand into an
     /// empty list of attributes.
@@ -335,11 +339,7 @@ fn process_cfg_attrs<T: AstLike>(&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(&self, attr: Attribute) -> Vec<Attribute> {
-        if !attr.has_name(sym::cfg_attr) {
-            return vec![attr];
-        }
-
+    crate fn expand_cfg_attr(&self, attr: Attribute, recursive: bool) -> Vec<Attribute> {
         let (cfg_predicate, expanded_attrs) =
             match rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) {
                 None => return vec![],
@@ -348,95 +348,109 @@ fn process_cfg_attr(&self, attr: Attribute) -> Vec<Attribute> {
 
         // Lint on zero attributes in source.
         if expanded_attrs.is_empty() {
-            return vec![attr];
+            self.sess.parse_sess.buffer_lint(
+                rustc_lint_defs::builtin::UNUSED_ATTRIBUTES,
+                attr.span,
+                ast::CRATE_NODE_ID,
+                "`#[cfg_attr]` does not expand to any attributes",
+            );
         }
 
         if !attr::cfg_matches(&cfg_predicate, &self.sess.parse_sess, self.features) {
             return vec![];
         }
 
-        // We call `process_cfg_attr` recursively in case there's a
-        // `cfg_attr` inside of another `cfg_attr`. E.g.
-        //  `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
-        expanded_attrs
-            .into_iter()
-            .flat_map(|(item, span)| {
-                let orig_tokens = attr.tokens().to_tokenstream();
-
-                // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
-                // and producing an attribute of the form `#[attr]`. We
-                // have captured tokens for `attr` itself, but we need to
-                // synthesize tokens for the wrapper `#` and `[]`, which
-                // we do below.
-
-                // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
-                // for `attr` when we expand it to `#[attr]`
-                let mut orig_trees = orig_tokens.trees();
-                let pound_token = match orig_trees.next().unwrap() {
-                    TokenTree::Token(token @ Token { kind: TokenKind::Pound, .. }) => token,
-                    _ => panic!("Bad tokens for attribute {:?}", attr),
-                };
-                let pound_span = pound_token.span;
-
-                let mut trees = vec![(AttrAnnotatedTokenTree::Token(pound_token), Spacing::Alone)];
-                if attr.style == AttrStyle::Inner {
-                    // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
-                    let bang_token = match orig_trees.next().unwrap() {
-                        TokenTree::Token(token @ Token { kind: TokenKind::Not, .. }) => token,
-                        _ => panic!("Bad tokens for attribute {:?}", attr),
-                    };
-                    trees.push((AttrAnnotatedTokenTree::Token(bang_token), Spacing::Alone));
-                }
-                // We don't really have a good span to use for the syntheized `[]`
-                // in `#[attr]`, so just use the span of the `#` token.
-                let bracket_group = AttrAnnotatedTokenTree::Delimited(
-                    DelimSpan::from_single(pound_span),
-                    DelimToken::Bracket,
-                    item.tokens
-                        .as_ref()
-                        .unwrap_or_else(|| panic!("Missing tokens for {:?}", item))
-                        .create_token_stream(),
-                );
-                trees.push((bracket_group, Spacing::Alone));
-                let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees)));
-                let attr = attr::mk_attr_from_item(item, tokens, attr.style, span);
-                if attr.has_name(sym::crate_type) {
-                    self.sess.parse_sess.buffer_lint(
-                        rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
-                        attr.span,
-                        ast::CRATE_NODE_ID,
-                        "`crate_type` within an `#![cfg_attr] attribute is deprecated`",
-                    );
-                }
-                if attr.has_name(sym::crate_name) {
-                    self.sess.parse_sess.buffer_lint(
-                        rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
-                        attr.span,
-                        ast::CRATE_NODE_ID,
-                        "`crate_name` within an `#![cfg_attr] attribute is deprecated`",
-                    );
-                }
-                self.process_cfg_attr(attr)
-            })
-            .collect()
+        if recursive {
+            // We call `process_cfg_attr` recursively in case there's a
+            // `cfg_attr` inside of another `cfg_attr`. E.g.
+            //  `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
+            expanded_attrs
+                .into_iter()
+                .flat_map(|item| self.process_cfg_attr(self.expand_cfg_attr_item(&attr, item)))
+                .collect()
+        } else {
+            expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(&attr, item)).collect()
+        }
+    }
+
+    fn expand_cfg_attr_item(
+        &self,
+        attr: &Attribute,
+        (item, item_span): (ast::AttrItem, Span),
+    ) -> Attribute {
+        let orig_tokens = attr.tokens().to_tokenstream();
+
+        // We are taking an attribute of the form `#[cfg_attr(pred, attr)]`
+        // and producing an attribute of the form `#[attr]`. We
+        // have captured tokens for `attr` itself, but we need to
+        // synthesize tokens for the wrapper `#` and `[]`, which
+        // we do below.
+
+        // Use the `#` in `#[cfg_attr(pred, attr)]` as the `#` token
+        // for `attr` when we expand it to `#[attr]`
+        let mut orig_trees = orig_tokens.trees();
+        let pound_token = match orig_trees.next().unwrap() {
+            TokenTree::Token(token @ Token { kind: TokenKind::Pound, .. }) => token,
+            _ => panic!("Bad tokens for attribute {:?}", attr),
+        };
+        let pound_span = pound_token.span;
+
+        let mut trees = vec![(AttrAnnotatedTokenTree::Token(pound_token), Spacing::Alone)];
+        if attr.style == AttrStyle::Inner {
+            // For inner attributes, we do the same thing for the `!` in `#![some_attr]`
+            let bang_token = match orig_trees.next().unwrap() {
+                TokenTree::Token(token @ Token { kind: TokenKind::Not, .. }) => token,
+                _ => panic!("Bad tokens for attribute {:?}", attr),
+            };
+            trees.push((AttrAnnotatedTokenTree::Token(bang_token), Spacing::Alone));
+        }
+        // We don't really have a good span to use for the syntheized `[]`
+        // in `#[attr]`, so just use the span of the `#` token.
+        let bracket_group = AttrAnnotatedTokenTree::Delimited(
+            DelimSpan::from_single(pound_span),
+            DelimToken::Bracket,
+            item.tokens
+                .as_ref()
+                .unwrap_or_else(|| panic!("Missing tokens for {:?}", item))
+                .create_token_stream(),
+        );
+        trees.push((bracket_group, Spacing::Alone));
+        let tokens = Some(LazyTokenStream::new(AttrAnnotatedTokenStream::new(trees)));
+        let attr = attr::mk_attr_from_item(item, tokens, attr.style, item_span);
+        if attr.has_name(sym::crate_type) {
+            self.sess.parse_sess.buffer_lint(
+                rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
+                attr.span,
+                ast::CRATE_NODE_ID,
+                "`crate_type` within an `#![cfg_attr] attribute is deprecated`",
+            );
+        }
+        if attr.has_name(sym::crate_name) {
+            self.sess.parse_sess.buffer_lint(
+                rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
+                attr.span,
+                ast::CRATE_NODE_ID,
+                "`crate_name` within an `#![cfg_attr] attribute is deprecated`",
+            );
+        }
+        attr
     }
 
     /// Determines if a node with the given attributes should be included in this configuration.
     fn in_cfg(&self, attrs: &[Attribute]) -> bool {
-        attrs.iter().all(|attr| {
-            if !is_cfg(attr) {
+        attrs.iter().all(|attr| !is_cfg(attr) || self.cfg_true(attr))
+    }
+
+    crate fn cfg_true(&self, attr: &Attribute) -> bool {
+        let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
+            Ok(meta_item) => meta_item,
+            Err(mut err) => {
+                err.emit();
                 return true;
             }
-            let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
-                Ok(meta_item) => meta_item,
-                Err(mut err) => {
-                    err.emit();
-                    return true;
-                }
-            };
-            parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
-                attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features)
-            })
+        };
+        parse_cfg(&meta_item, &self.sess).map_or(true, |meta_item| {
+            attr::cfg_matches(&meta_item, &self.sess.parse_sess, self.features)
         })
     }
 
index 07ce901fb417aa2b1c1fe47da35c4d9123c14622..7604a464be2ffd51affdc8623035bde56c2f145b 100644 (file)
@@ -15,7 +15,6 @@
 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::sync::Lrc;
 use rustc_errors::{Applicability, PResult};
@@ -1014,6 +1013,9 @@ trait InvocationCollectorNode: AstLike {
     fn to_annotatable(self) -> Annotatable;
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;
     fn id(&mut self) -> &mut NodeId;
+    fn descr() -> &'static str {
+        unreachable!()
+    }
     fn noop_flat_map<V: MutVisitor>(self, _visitor: &mut V) -> Self::OutputTy {
         unreachable!()
     }
@@ -1477,6 +1479,9 @@ fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
     fn id(&mut self) -> &mut NodeId {
         &mut self.id
     }
+    fn descr() -> &'static str {
+        "an expression"
+    }
     fn noop_visit<V: MutVisitor>(&mut self, visitor: &mut V) {
         noop_visit_expr(self, visitor)
     }
@@ -1576,13 +1581,28 @@ fn take_first_attr(
     ) -> Option<(ast::Attribute, usize, Vec<ast::Path>)> {
         let mut attr = None;
 
+        let mut cfg_pos = None;
+        let mut attr_pos = None;
+        for (pos, attr) in item.attrs().iter().enumerate() {
+            if !attr.is_doc_comment() && !self.cx.expanded_inert_attrs.is_marked(attr) {
+                let name = attr.ident().map(|ident| ident.name);
+                if name == Some(sym::cfg) || name == Some(sym::cfg_attr) {
+                    cfg_pos = Some(pos); // a cfg attr found, no need to search anymore
+                    break;
+                } else if attr_pos.is_none()
+                    && !name.map_or(false, rustc_feature::is_builtin_attr_name)
+                {
+                    attr_pos = Some(pos); // a non-cfg attr found, still may find a cfg attr
+                }
+            }
+        }
+
         item.visit_attrs(|attrs| {
-            attr = attrs
-                .iter()
-                .position(|a| !self.cx.expanded_inert_attrs.is_marked(a) && !is_builtin_attr(a))
-                .map(|attr_pos| {
-                    let attr = attrs.remove(attr_pos);
-                    let following_derives = attrs[attr_pos..]
+            attr = Some(match (cfg_pos, attr_pos) {
+                (Some(pos), _) => (attrs.remove(pos), pos, Vec::new()),
+                (_, Some(pos)) => {
+                    let attr = attrs.remove(pos);
+                    let following_derives = attrs[pos..]
                         .iter()
                         .filter(|a| a.has_name(sym::derive))
                         .flat_map(|a| a.meta_item_list().unwrap_or_default())
@@ -1596,17 +1616,15 @@ fn take_first_attr(
                         })
                         .collect();
 
-                    (attr, attr_pos, following_derives)
-                })
+                    (attr, pos, following_derives)
+                }
+                _ => return,
+            });
         });
 
         attr
     }
 
-    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: &ast::MacCall) {
@@ -1653,28 +1671,71 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
         }
     }
 
+    fn expand_cfg_true(
+        &mut self,
+        node: &mut impl AstLike,
+        attr: ast::Attribute,
+        pos: usize,
+    ) -> bool {
+        let res = self.cfg.cfg_true(&attr);
+        if res {
+            // FIXME: `cfg(TRUE)` attributes do not currently remove themselves during expansion,
+            // and some tools like rustdoc and clippy rely on that. Find a way to remove them
+            // while keeping the tools working.
+            self.cx.expanded_inert_attrs.mark(&attr);
+            node.visit_attrs(|attrs| attrs.insert(pos, attr));
+        }
+        res
+    }
+
+    fn expand_cfg_attr(&self, node: &mut impl AstLike, attr: ast::Attribute, pos: usize) {
+        node.visit_attrs(|attrs| {
+            attrs.splice(pos..pos, self.cfg.expand_cfg_attr(attr, false));
+        });
+    }
+
     fn flat_map_node<Node: InvocationCollectorNode<OutputTy: Default>>(
         &mut self,
-        node: Node,
+        mut 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),
-            }
+        loop {
+            return match self.take_first_attr(&mut node) {
+                Some((attr, pos, derives)) => match attr.name_or_empty() {
+                    sym::cfg => {
+                        if self.expand_cfg_true(&mut node, attr, pos) {
+                            continue;
+                        }
+                        Default::default()
+                    }
+                    sym::cfg_attr => {
+                        self.expand_cfg_attr(&mut node, attr, pos);
+                        continue;
+                    }
+                    _ => {
+                        Node::pre_flat_map_node_collect_attr(&self.cfg, &attr);
+                        self.collect_attr((attr, pos, derives), node.to_annotatable(), Node::KIND)
+                            .make_ast::<Node>()
+                    }
+                },
+                None 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
+                }
+                None => {
+                    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(returned_node) => {
+                            node = returned_node;
+                            continue;
+                        }
+                    }
+                }
+            };
         }
     }
 
@@ -1682,19 +1743,40 @@ 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))
+        loop {
+            return match self.take_first_attr(node) {
+                Some((attr, pos, derives)) => match attr.name_or_empty() {
+                    sym::cfg => {
+                        let span = attr.span;
+                        if self.expand_cfg_true(node, attr, pos) {
+                            continue;
+                        }
+                        let msg =
+                            format!("removing {} is not supported in this position", Node::descr());
+                        self.cx.span_err(span, &msg);
+                        continue;
+                    }
+                    sym::cfg_attr => {
+                        self.expand_cfg_attr(node, attr, pos);
+                        continue;
+                    }
+                    _ => visit_clobber(node, |node| {
+                        self.collect_attr((attr, pos, derives), node.to_annotatable(), Node::KIND)
+                            .make_ast::<Node>()
+                    }),
+                },
+                None 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>()
+                    })
+                }
+                None => {
+                    assign_id!(self, node.id(), || node.noop_visit(self))
+                }
+            };
         }
     }
 }
@@ -1750,7 +1832,7 @@ fn flat_map_generic_param(
         self.flat_map_node(node)
     }
 
-    fn flat_map_stmt(&mut self, node: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
+    fn flat_map_stmt(&mut self, mut node: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> {
         // FIXME: invocations in semicolon-less expressions positions are expanded as expressions,
         // changing that requires some compatibility measures.
         if node.is_expr() {
@@ -1761,7 +1843,6 @@ fn flat_map_generic_param(
             // `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(..), .. }) =>
@@ -1793,7 +1874,10 @@ fn visit_pat(&mut self, node: &mut P<ast::Pat>) {
     }
 
     fn visit_expr(&mut self, node: &mut P<ast::Expr>) {
-        self.cfg.configure_expr(node);
+        // FIXME: Feature gating is performed inconsistently between `Expr` and `OptExpr`.
+        if let Some(attr) = node.attrs.first() {
+            self.cfg.maybe_emit_expr_attr_err(attr);
+        }
         self.visit_node(node)
     }
 
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 ebd12d6ab4e2d1ed9e6076c96cbbf02a7ae61c6b..0b65a5ff3ecc3b28df5607f105d7248e733ed1d6 100644 (file)
@@ -288,6 +288,8 @@ pub fn set(&self, features: &mut Features, span: Span) {
     (active, asm_sym, "1.58.0", Some(72016), None),
     /// Allows the `may_unwind` option in inline assembly.
     (active, asm_unwind, "1.58.0", Some(72016), None),
+    /// Allows users to enforce equality of associated constants `TraitImpl<AssocConst=3>`.
+    (active, associated_const_equality, "1.58.0", Some(92827), None),
     /// Allows the user of associated type bounds.
     (active, associated_type_bounds, "1.34.0", Some(52662), None),
     /// Allows associated type defaults.
@@ -413,7 +415,7 @@ pub fn set(&self, features: &mut Features, span: Span) {
     // Allows setting the threshold for the `large_assignments` lint.
     (active, large_assignments, "1.52.0", Some(83518), None),
     /// Allows `if/while p && let q = r && ...` chains.
-    (incomplete, let_chains, "1.37.0", Some(53667), None),
+    (active, let_chains, "1.37.0", Some(53667), None),
     /// Allows `let...else` statements.
     (active, let_else, "1.56.0", Some(87335), None),
     /// Allows `#[link(..., cfg(..))]`.
index f25b2d8f566c08eede2513d580e8bcbb32b4e7d7..723cc06864a90fb4f8a210b7036b9694c92d29bb 100644 (file)
@@ -352,7 +352,7 @@ pub struct BuiltinAttribute {
 
     // Runtime
     ungated!(
-        windows_subsystem, Normal,
+        windows_subsystem, CrateLevel,
         template!(NameValueStr: "windows|console"), FutureWarnFollowing
     ),
     ungated!(panic_handler, Normal, template!(Word), WarnFollowing), // RFC 2070
@@ -360,7 +360,7 @@ pub struct BuiltinAttribute {
     // Code generation:
     ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing),
     ungated!(cold, Normal, template!(Word), WarnFollowing),
-    ungated!(no_builtins, Normal, template!(Word), WarnFollowing),
+    ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing),
     ungated!(target_feature, Normal, template!(List: r#"enable = "name""#), DuplicatesOk),
     ungated!(track_caller, Normal, template!(Word), WarnFollowing),
     gated!(
@@ -623,6 +623,11 @@ pub struct BuiltinAttribute {
         lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, lang_items,
         "language items are subject to change",
     ),
+    rustc_attr!(
+        rustc_pass_by_value, Normal,
+        template!(Word), WarnFollowing,
+        "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
+    ),
     BuiltinAttribute {
         name: sym::rustc_diagnostic_item,
         type_: Normal,
@@ -677,6 +682,12 @@ pub struct BuiltinAttribute {
         "the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
         from method dispatch when the receiver is an array, for compatibility in editions < 2021."
     ),
+    rustc_attr!(
+        rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."), ErrorFollowing,
+        "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
+        definition of a trait, it's currently in experimental form and should be changed before \
+        being exposed outside of the std"
+    ),
 
     // ==========================================================================
     // Internal attributes, Testing:
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 edad00ed6a2fe0ce03de074dc48a0d3473d3c547..27ec461906419ea93328a5de07aa98cbb9f804a2 100644 (file)
@@ -30,7 +30,6 @@ macro_rules! arena_types {
             [] impl_item_ref: rustc_hir::ImplItemRef,
             [] item: rustc_hir::Item<'tcx>,
             [] inline_asm: rustc_hir::InlineAsm<'tcx>,
-            [] llvm_inline_asm: rustc_hir::LlvmInlineAsm<'tcx>,
             [] local: rustc_hir::Local<'tcx>,
             [] mod_: rustc_hir::Mod<'tcx>,
             [] owner_info: rustc_hir::OwnerInfo<'tcx>,
index f03d8eea40bb3ba292ca5469ab809436db20f8df..a9dbdd483fe6f7c3bd2f6bf61b09eb57febcde2e 100644 (file)
@@ -5,8 +5,8 @@
 use crate::LangItem;
 
 use rustc_ast::util::parser::ExprPrecedence;
-use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect};
-use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, TraitObjectSyntax, UintTy};
+use rustc_ast::{self as ast, CrateSugar};
+use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy};
 pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
 pub use rustc_ast::{CaptureBy, Movability, Mutability};
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@@ -293,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())
     }
@@ -318,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)]
@@ -374,7 +377,7 @@ pub fn has_err(&self) -> bool {
             GenericArg::Type(ty) => matches!(ty.kind, TyKind::Err),
             _ => false,
         }) || self.bindings.iter().any(|arg| match arg.kind {
-            TypeBindingKind::Equality { ty } => matches!(ty.kind, TyKind::Err),
+            TypeBindingKind::Equality { term: Term::Ty(ty) } => matches!(ty.kind, TyKind::Err),
             _ => false,
         })
     }
@@ -1471,7 +1474,6 @@ pub fn precedence(&self) -> ExprPrecedence {
             ExprKind::Continue(..) => ExprPrecedence::Continue,
             ExprKind::Ret(..) => ExprPrecedence::Ret,
             ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
-            ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
             ExprKind::Struct(..) => ExprPrecedence::Struct,
             ExprKind::Repeat(..) => ExprPrecedence::Repeat,
             ExprKind::Yield(..) => ExprPrecedence::Yield,
@@ -1531,7 +1533,6 @@ pub fn is_place_expr(&self, mut allow_projections_from: impl FnMut(&Self) -> boo
             | ExprKind::Loop(..)
             | ExprKind::Assign(..)
             | ExprKind::InlineAsm(..)
-            | ExprKind::LlvmInlineAsm(..)
             | ExprKind::AssignOp(..)
             | ExprKind::Lit(_)
             | ExprKind::ConstBlock(..)
@@ -1614,7 +1615,6 @@ pub fn can_have_side_effects(&self) -> bool {
             | ExprKind::Loop(..)
             | ExprKind::Assign(..)
             | ExprKind::InlineAsm(..)
-            | ExprKind::LlvmInlineAsm(..)
             | ExprKind::AssignOp(..)
             | ExprKind::ConstBlock(..)
             | ExprKind::Box(..)
@@ -1755,8 +1755,6 @@ pub enum ExprKind<'hir> {
 
     /// Inline assembly (from `asm!`), with its outputs and inputs.
     InlineAsm(&'hir InlineAsm<'hir>),
-    /// Inline assembly (from `llvm_asm!`), with its outputs and inputs.
-    LlvmInlineAsm(&'hir LlvmInlineAsm<'hir>),
 
     /// A struct or struct-like variant literal expression.
     ///
@@ -2131,19 +2129,37 @@ pub struct TypeBinding<'hir> {
     pub span: Span,
 }
 
+#[derive(Debug, HashStable_Generic)]
+pub enum Term<'hir> {
+    Ty(&'hir Ty<'hir>),
+    Const(AnonConst),
+}
+
+impl<'hir> From<&'hir Ty<'hir>> for Term<'hir> {
+    fn from(ty: &'hir Ty<'hir>) -> Self {
+        Term::Ty(ty)
+    }
+}
+
+impl<'hir> From<AnonConst> for Term<'hir> {
+    fn from(c: AnonConst) -> Self {
+        Term::Const(c)
+    }
+}
+
 // Represents the two kinds of type bindings.
 #[derive(Debug, HashStable_Generic)]
 pub enum TypeBindingKind<'hir> {
     /// E.g., `Foo<Bar: Send>`.
     Constraint { bounds: &'hir [GenericBound<'hir>] },
-    /// E.g., `Foo<Bar = ()>`.
-    Equality { ty: &'hir Ty<'hir> },
+    /// E.g., `Foo<Bar = ()>`, `Foo<Bar = ()>`
+    Equality { term: Term<'hir> },
 }
 
 impl TypeBinding<'_> {
     pub fn ty(&self) -> &Ty<'_> {
         match self.kind {
-            TypeBindingKind::Equality { ref ty } => ty,
+            TypeBindingKind::Equality { term: Term::Ty(ref ty) } => ty,
             _ => panic!("expected equality type binding for parenthesized generic args"),
         }
     }
@@ -2368,36 +2384,6 @@ pub struct InlineAsm<'hir> {
     pub line_spans: &'hir [Span],
 }
 
-#[derive(Copy, Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)]
-pub struct LlvmInlineAsmOutput {
-    pub constraint: Symbol,
-    pub is_rw: bool,
-    pub is_indirect: bool,
-    pub span: Span,
-}
-
-// NOTE(eddyb) This is used within MIR as well, so unlike the rest of the HIR,
-// it needs to be `Clone` and `Decodable` and use plain `Vec<T>` instead of
-// arena-allocated slice.
-#[derive(Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)]
-pub struct LlvmInlineAsmInner {
-    pub asm: Symbol,
-    pub asm_str_style: StrStyle,
-    pub outputs: Vec<LlvmInlineAsmOutput>,
-    pub inputs: Vec<Symbol>,
-    pub clobbers: Vec<Symbol>,
-    pub volatile: bool,
-    pub alignstack: bool,
-    pub dialect: LlvmAsmDialect,
-}
-
-#[derive(Debug, HashStable_Generic)]
-pub struct LlvmInlineAsm<'hir> {
-    pub inner: LlvmInlineAsmInner,
-    pub outputs_exprs: &'hir [Expr<'hir>],
-    pub inputs_exprs: &'hir [Expr<'hir>],
-}
-
 /// Represents a parameter in a function header.
 #[derive(Debug, HashStable_Generic)]
 pub struct Param<'hir> {
@@ -2740,6 +2726,10 @@ pub struct FnHeader {
 }
 
 impl FnHeader {
+    pub fn is_async(&self) -> bool {
+        matches!(&self.asyncness, IsAsync::Async)
+    }
+
     pub fn is_const(&self) -> bool {
         matches!(&self.constness, Constness::Const)
     }
@@ -2878,6 +2868,8 @@ pub struct ImplItemRef {
     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)]
@@ -3181,7 +3173,7 @@ pub fn ident(&self) -> Option<Ident> {
         }
     }
 
-    pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> {
+    pub fn fn_decl(&self) -> Option<&'hir FnDecl<'hir>> {
         match self {
             Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
             | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
@@ -3193,6 +3185,15 @@ pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> {
         }
     }
 
+    pub fn fn_sig(&self) -> Option<&'hir FnSig<'hir>> {
+        match self {
+            Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
+            | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
+            | Node::Item(Item { kind: ItemKind::Fn(fn_sig, _, _), .. }) => Some(fn_sig),
+            _ => None,
+        }
+    }
+
     pub fn body_id(&self) -> Option<BodyId> {
         match self {
             Node::TraitItem(TraitItem {
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 d0eee422202afff8a23a2e114c42c013f0859749..cfdcd1618ba426a05285fe4327c36c06a024314a 100644 (file)
@@ -160,39 +160,27 @@ fn foreign_item(&self, _: ForeignItemId) -> &'hir ForeignItem<'hir> {
     }
 }
 
-/// An erased version of `Map<'hir>`, using dynamic dispatch.
-/// NOTE: This type is effectively only usable with `NestedVisitorMap::None`.
-pub struct ErasedMap<'hir>(&'hir dyn Map<'hir>);
+pub mod nested_filter {
+    use super::Map;
 
-impl<'hir> Map<'hir> for ErasedMap<'hir> {
-    fn find(&self, _: HirId) -> Option<Node<'hir>> {
-        None
-    }
-    fn body(&self, id: BodyId) -> &'hir Body<'hir> {
-        self.0.body(id)
-    }
-    fn item(&self, id: ItemId) -> &'hir Item<'hir> {
-        self.0.item(id)
-    }
-    fn trait_item(&self, id: TraitItemId) -> &'hir TraitItem<'hir> {
-        self.0.trait_item(id)
-    }
-    fn impl_item(&self, id: ImplItemId) -> &'hir ImplItem<'hir> {
-        self.0.impl_item(id)
-    }
-    fn foreign_item(&self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
-        self.0.foreign_item(id)
+    /// Specifies what nested things a visitor wants to visit. The most
+    /// common choice is `OnlyBodies`, which will cause the visitor to
+    /// visit fn bodies for fns that it encounters, but skip over nested
+    /// item-like things.
+    ///
+    /// See the comments on `ItemLikeVisitor` for more details on the overall
+    /// visit strategy.
+    pub trait NestedFilter<'hir> {
+        type Map: Map<'hir>;
+
+        /// Whether the visitor visits nested "item-like" things.
+        /// E.g., item, impl-item.
+        const INTER: bool;
+        /// Whether the visitor visits "intra item-like" things.
+        /// E.g., function body, closure, `AnonConst`
+        const INTRA: bool;
     }
-}
 
-/// Specifies what nested things a visitor wants to visit. The most
-/// common choice is `OnlyBodies`, which will cause the visitor to
-/// visit fn bodies for fns that it encounters, but skip over nested
-/// item-like things.
-///
-/// See the comments on `ItemLikeVisitor` for more details on the overall
-/// visit strategy.
-pub enum NestedVisitorMap<M> {
     /// Do not visit any nested things. When you add a new
     /// "non-nested" thing, you will want to audit such uses to see if
     /// they remain valid.
@@ -200,47 +188,16 @@ pub enum NestedVisitorMap<M> {
     /// Use this if you are only walking some particular kind of tree
     /// (i.e., a type, or fn signature) and you don't want to thread a
     /// HIR map around.
-    None,
-
-    /// Do not visit nested item-like things, but visit nested things
-    /// that are inside of an item-like.
-    ///
-    /// **This is the most common choice.** A very common pattern is
-    /// to use `visit_all_item_likes()` as an outer loop,
-    /// and to have the visitor that visits the contents of each item
-    /// using this setting.
-    OnlyBodies(M),
-
-    /// Visits all nested things, including item-likes.
-    ///
-    /// **This is an unusual choice.** It is used when you want to
-    /// process everything within their lexical context. Typically you
-    /// kick off the visit by doing `walk_krate()`.
-    All(M),
-}
-
-impl<M> NestedVisitorMap<M> {
-    /// Returns the map to use for an "intra item-like" thing (if any).
-    /// E.g., function body.
-    fn intra(self) -> Option<M> {
-        match self {
-            NestedVisitorMap::None => None,
-            NestedVisitorMap::OnlyBodies(map) => Some(map),
-            NestedVisitorMap::All(map) => Some(map),
-        }
-    }
-
-    /// Returns the map to use for an "item-like" thing (if any).
-    /// E.g., item, impl-item.
-    fn inter(self) -> Option<M> {
-        match self {
-            NestedVisitorMap::None => None,
-            NestedVisitorMap::OnlyBodies(_) => None,
-            NestedVisitorMap::All(map) => Some(map),
-        }
+    pub struct None(());
+    impl NestedFilter<'_> for None {
+        type Map = !;
+        const INTER: bool = false;
+        const INTRA: bool = false;
     }
 }
 
+use nested_filter::NestedFilter;
+
 /// Each method of the Visitor trait is a hook to be potentially
 /// overridden. Each method's default implementation recursively visits
 /// the substructure of the input via the corresponding `walk` method;
@@ -258,7 +215,9 @@ fn inter(self) -> Option<M> {
 /// to monitor future changes to `Visitor` in case a new method with a
 /// new default implementation gets introduced.)
 pub trait Visitor<'v>: Sized {
-    type Map: Map<'v>;
+    // this type should not be overridden, it exists for convenient usage as `Self::Map`
+    type Map: Map<'v> = <Self::NestedFilter as NestedFilter<'v>>::Map;
+    type NestedFilter: NestedFilter<'v> = nested_filter::None;
 
     ///////////////////////////////////////////////////////////////////////////
     // Nested items.
@@ -279,7 +238,12 @@ pub trait Visitor<'v>: Sized {
     /// `panic!()`. This way, if a new `visit_nested_XXX` variant is
     /// added in the future, we will see the panic in your code and
     /// fix it appropriately.
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map>;
+    fn nested_visit_map(&mut self) -> Self::Map {
+        panic!(
+            "nested_visit_map must be implemented or consider using \
+            `type NestedFilter = nested_filter::None` (the default)"
+        );
+    }
 
     /// Invoked when a nested item is encountered. By default does
     /// nothing unless you override `nested_visit_map` to return other than
@@ -290,32 +254,40 @@ pub trait Visitor<'v>: Sized {
     /// reason to override this method is if you want a nested pattern
     /// but cannot supply a `Map`; see `nested_visit_map` for advice.
     fn visit_nested_item(&mut self, id: ItemId) {
-        let opt_item = self.nested_visit_map().inter().map(|map| map.item(id));
-        walk_list!(self, visit_item, opt_item);
+        if Self::NestedFilter::INTER {
+            let item = self.nested_visit_map().item(id);
+            self.visit_item(item);
+        }
     }
 
     /// Like `visit_nested_item()`, but for trait items. See
     /// `visit_nested_item()` for advice on when to override this
     /// method.
     fn visit_nested_trait_item(&mut self, id: TraitItemId) {
-        let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id));
-        walk_list!(self, visit_trait_item, opt_item);
+        if Self::NestedFilter::INTER {
+            let item = self.nested_visit_map().trait_item(id);
+            self.visit_trait_item(item);
+        }
     }
 
     /// Like `visit_nested_item()`, but for impl items. See
     /// `visit_nested_item()` for advice on when to override this
     /// method.
     fn visit_nested_impl_item(&mut self, id: ImplItemId) {
-        let opt_item = self.nested_visit_map().inter().map(|map| map.impl_item(id));
-        walk_list!(self, visit_impl_item, opt_item);
+        if Self::NestedFilter::INTER {
+            let item = self.nested_visit_map().impl_item(id);
+            self.visit_impl_item(item);
+        }
     }
 
     /// Like `visit_nested_item()`, but for foreign items. See
     /// `visit_nested_item()` for advice on when to override this
     /// method.
     fn visit_nested_foreign_item(&mut self, id: ForeignItemId) {
-        let opt_item = self.nested_visit_map().inter().map(|map| map.foreign_item(id));
-        walk_list!(self, visit_foreign_item, opt_item);
+        if Self::NestedFilter::INTER {
+            let item = self.nested_visit_map().foreign_item(id);
+            self.visit_foreign_item(item);
+        }
     }
 
     /// Invoked to visit the body of a function, method or closure. Like
@@ -323,8 +295,10 @@ fn visit_nested_foreign_item(&mut self, id: ForeignItemId) {
     /// `nested_visit_map` to return other than `None`, in which case it will walk
     /// the body.
     fn visit_nested_body(&mut self, id: BodyId) {
-        let opt_body = self.nested_visit_map().intra().map(|map| map.body(id));
-        walk_list!(self, visit_body, opt_body);
+        if Self::NestedFilter::INTRA {
+            let body = self.nested_visit_map().body(id);
+            self.visit_body(body);
+        }
     }
 
     fn visit_param(&mut self, param: &'v Param<'v>) {
@@ -827,12 +801,11 @@ pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
     visitor.visit_ident(type_binding.ident);
     visitor.visit_generic_args(type_binding.span, type_binding.gen_args);
     match type_binding.kind {
-        TypeBindingKind::Equality { ref ty } => {
-            visitor.visit_ty(ty);
-        }
-        TypeBindingKind::Constraint { bounds } => {
-            walk_list!(visitor, visit_param_bound, bounds);
-        }
+        TypeBindingKind::Equality { ref term } => match term {
+            Term::Ty(ref ty) => visitor.visit_ty(ty),
+            Term::Const(ref c) => visitor.visit_anon_const(c),
+        },
+        TypeBindingKind::Constraint { bounds } => walk_list!(visitor, visit_param_bound, bounds),
     }
 }
 
@@ -1088,7 +1061,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);
@@ -1251,10 +1225,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
         ExprKind::InlineAsm(ref asm) => {
             walk_inline_asm(visitor, asm);
         }
-        ExprKind::LlvmInlineAsm(ref asm) => {
-            walk_list!(visitor, visit_expr, asm.outputs_exprs);
-            walk_list!(visitor, visit_expr, asm.inputs_exprs);
-        }
         ExprKind::Yield(ref subexpression, _) => {
             visitor.visit_expr(subexpression);
         }
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 1df9b5f9c78a95b66d070d4f76a2c987f8fad802..f1d62d03cbc98e3c8c3c072b27f6b1ec3ca9f0f3 100644 (file)
@@ -2,6 +2,7 @@
 //!
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
 
+#![feature(associated_type_defaults)]
 #![feature(const_btree_new)]
 #![feature(crate_visibility_modifier)]
 #![feature(once_cell)]
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 4c9e2d7fe42b11f49f98b624aa54f238437f2e3c..a301c5e34565cabd107e279828293ab846d2c690 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_ast_pretty::pp::{self, Breaks};
 use rustc_ast_pretty::pprust::{Comments, PrintState};
 use rustc_hir as hir;
-use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node};
+use rustc_hir::{GenericArg, GenericParam, GenericParamKind, Node, Term};
 use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier};
 use rustc_span::source_map::{SourceMap, Spanned};
 use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol};
@@ -170,7 +170,7 @@ pub fn new_from_input(
         ann: &'a dyn PpAnn,
     ) -> State<'a> {
         State {
-            s: pp::mk_printer(),
+            s: pp::Printer::new(),
             comments: Some(Comments::new(sm, filename, input)),
             attrs,
             ann,
@@ -186,7 +186,7 @@ pub fn to_string<F>(ann: &dyn PpAnn, f: F) -> String
 where
     F: FnOnce(&mut State<'_>),
 {
-    let mut printer = State { s: pp::mk_printer(), comments: None, attrs: &|_| &[], ann };
+    let mut printer = State { s: pp::Printer::new(), comments: None, attrs: &|_| &[], ann };
     f(&mut printer);
     printer.s.eof()
 }
@@ -705,9 +705,7 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 self.bclose(item.span);
             }
             hir::ItemKind::TraitAlias(ref generics, ref bounds) => {
-                self.head("");
-                self.print_visibility(&item.vis);
-                self.word_nbsp("trait");
+                self.head(visibility_qualified(&item.vis, "trait"));
                 self.print_ident(item.ident);
                 self.print_generic_params(&generics.params);
                 let mut real_bounds = Vec::with_capacity(bounds.len());
@@ -725,6 +723,8 @@ pub fn print_item(&mut self, item: &hir::Item<'_>) {
                 self.print_bounds("=", real_bounds);
                 self.print_where_clause(&generics.where_clause);
                 self.word(";");
+                self.end(); // end inner head-block
+                self.end(); // end outer head-block
             }
         }
         self.ann.post(self, AnnNode::Item(item))
@@ -1581,67 +1581,6 @@ pub fn print_expr(&mut self, expr: &hir::Expr<'_>) {
                 self.word("asm!");
                 self.print_inline_asm(asm);
             }
-            hir::ExprKind::LlvmInlineAsm(ref a) => {
-                let i = &a.inner;
-                self.word("llvm_asm!");
-                self.popen();
-                self.print_symbol(i.asm, i.asm_str_style);
-                self.word_space(":");
-
-                let mut out_idx = 0;
-                self.commasep(Inconsistent, &i.outputs, |s, out| {
-                    let constraint = out.constraint.as_str();
-                    let mut ch = constraint.chars();
-                    match ch.next() {
-                        Some('=') if out.is_rw => {
-                            s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
-                        }
-                        _ => s.print_string(&constraint, ast::StrStyle::Cooked),
-                    }
-                    s.popen();
-                    s.print_expr(&a.outputs_exprs[out_idx]);
-                    s.pclose();
-                    out_idx += 1;
-                });
-                self.space();
-                self.word_space(":");
-
-                let mut in_idx = 0;
-                self.commasep(Inconsistent, &i.inputs, |s, &co| {
-                    s.print_symbol(co, ast::StrStyle::Cooked);
-                    s.popen();
-                    s.print_expr(&a.inputs_exprs[in_idx]);
-                    s.pclose();
-                    in_idx += 1;
-                });
-                self.space();
-                self.word_space(":");
-
-                self.commasep(Inconsistent, &i.clobbers, |s, &co| {
-                    s.print_symbol(co, ast::StrStyle::Cooked);
-                });
-
-                let mut options = vec![];
-                if i.volatile {
-                    options.push("volatile");
-                }
-                if i.alignstack {
-                    options.push("alignstack");
-                }
-                if i.dialect == ast::LlvmAsmDialect::Intel {
-                    options.push("intel");
-                }
-
-                if !options.is_empty() {
-                    self.space();
-                    self.word_space(":");
-                    self.commasep(Inconsistent, &options, |s, &co| {
-                        s.print_string(co, ast::StrStyle::Cooked);
-                    });
-                }
-
-                self.pclose();
-            }
             hir::ExprKind::Yield(ref expr, _) => {
                 self.word_space("yield");
                 self.print_expr_maybe_paren(&expr, parser::PREC_JUMP);
@@ -1813,9 +1752,12 @@ fn print_generic_args(
                 self.print_generic_args(binding.gen_args, false, false);
                 self.space();
                 match generic_args.bindings[0].kind {
-                    hir::TypeBindingKind::Equality { ref ty } => {
+                    hir::TypeBindingKind::Equality { ref term } => {
                         self.word_space("=");
-                        self.print_type(ty);
+                        match term {
+                            Term::Ty(ref ty) => self.print_type(ty),
+                            Term::Const(ref c) => self.print_anon_const(c),
+                        }
                     }
                     hir::TypeBindingKind::Constraint { bounds } => {
                         self.print_bounds(":", bounds);
index 0d0d09bde5b992e45ec75aa6918805ec642b2487..60b48e9bc8a0124d1b2fc793121ba42e901fb173 100644 (file)
 use rustc_graphviz as dot;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::dep_graph::{
     DepGraphQuery, DepKind, DepNode, DepNodeExt, DepNodeFilter, EdgeFilter,
 };
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
@@ -173,10 +173,10 @@ fn process_attrs(&mut self, hir_id: hir::HirId) {
 }
 
 impl<'tcx> Visitor<'tcx> for IfThisChanged<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
index 88795679943fb98e49b5b7f87df5d29b66d98c23..94c149dd23e6f4c7a92ae8a5a0f690867a2a01bf 100644 (file)
@@ -28,7 +28,7 @@
 use rustc_hir::Node as HirNode;
 use rustc_hir::{ImplItemKind, ItemKind as HirItem, TraitItemKind};
 use rustc_middle::dep_graph::{label_strs, DepNode, DepNodeExt};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
@@ -223,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 {
@@ -473,10 +472,10 @@ fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet<ast::AttrId>) {
 }
 
 impl<'tcx> intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_attribute(&mut self, _: hir::HirId, attr: &'tcx Attribute) {
index 392c5bdc15ad204472ec07f3d6cced7028d3bf53..68180a2214a50aa84b8d78cd5cae51978e884417 100644 (file)
@@ -190,7 +190,7 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &
 
 fn rustc_version(nightly_build: bool) -> String {
     if nightly_build {
-        if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
+        if let Some(val) = env::var_os("RUSTC_FORCE_RUSTC_VERSION") {
             return val.to_string_lossy().into_owned();
         }
     }
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 359b1859c6889052f02776ee85509347d32beade..7919e409253925a804346fdf36906041ca391a27 100644 (file)
@@ -9,7 +9,3 @@
 pub mod bit_set;
 pub mod interval;
 pub mod vec;
-
-// FIXME(#56935): Work around ICEs during cross-compilation.
-#[allow(unused)]
-extern crate rustc_macros;
index 6023973665360e46ec59c41e478feee9deaee030..9d40b3cba2952eb48d96b3cb4552bd0f8cb27824 100644 (file)
@@ -425,7 +425,7 @@ fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
                         // FIXME: perf problem described in #55921.
                         ui = ty::UniverseIndex::ROOT;
                         return self.canonicalize_const_var(
-                            CanonicalVarInfo { kind: CanonicalVarKind::Const(ui) },
+                            CanonicalVarInfo { kind: CanonicalVarKind::Const(ui, ct.ty) },
                             ct,
                         );
                     }
@@ -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 0c26639e9b0fec31a947e491217ac87dac5c5c61..2d2edb07d9eda871bce69855d3ba3cf8b7446c0a 100644 (file)
@@ -137,12 +137,9 @@ fn instantiate_canonical_var(
                 self.tcx.mk_region(ty::RePlaceholder(placeholder_mapped)).into()
             }
 
-            CanonicalVarKind::Const(ui) => self
+            CanonicalVarKind::Const(ui, ty) => self
                 .next_const_var_in_universe(
-                    self.next_ty_var_in_universe(
-                        TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span },
-                        universe_map(ui),
-                    ),
+                    ty,
                     ConstVariableOrigin { kind: ConstVariableOriginKind::MiscVariable, span },
                     universe_map(ui),
                 )
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 f0c73d0c2f3691f5e8983488bccdbf3bfb3ac8de..14ab635a2ae2b05cac26898141ca96f21fd42b83 100644 (file)
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{Item, ItemKind, Node};
 use rustc_middle::dep_graph::DepContext;
-use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{
     self,
+    error::TypeError,
     subst::{GenericArgKind, Subst, SubstsRef},
-    Region, Ty, TyCtxt, TypeFoldable,
+    Binder, Region, Ty, TyCtxt, TypeFoldable,
 };
 use rustc_span::{sym, BytePos, DesugaringKind, MultiSpan, Pos, Span};
 use rustc_target::spec::abi;
@@ -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");
                 }
             }
@@ -1774,7 +1765,7 @@ enum Mismatch<'a> {
         self.note_error_origin(diag, cause, exp_found, terr);
     }
 
-    pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+    pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Binder<'tcx, Ty<'tcx>>> {
         if let ty::Opaque(def_id, substs) = ty.kind() {
             let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
             // Future::Output
@@ -1784,13 +1775,20 @@ pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
 
             for (predicate, _) in bounds {
                 let predicate = predicate.subst(self.tcx, substs);
-                if let ty::PredicateKind::Projection(projection_predicate) =
-                    predicate.kind().skip_binder()
-                {
-                    if projection_predicate.projection_ty.item_def_id == item_def_id {
-                        // We don't account for multiple `Future::Output = Ty` contraints.
-                        return Some(projection_predicate.ty);
-                    }
+                let output = predicate
+                    .kind()
+                    .map_bound(|kind| match kind {
+                        ty::PredicateKind::Projection(projection_predicate)
+                            if projection_predicate.projection_ty.item_def_id == item_def_id =>
+                        {
+                            projection_predicate.term.ty()
+                        }
+                        _ => None,
+                    })
+                    .transpose();
+                if output.is_some() {
+                    // We don't account for multiple `Future::Output = Ty` contraints.
+                    return output;
                 }
             }
         }
@@ -1832,8 +1830,8 @@ fn suggest_await_on_expect_found(
         }
 
         match (
-            self.get_impl_future_output_ty(exp_found.expected),
-            self.get_impl_future_output_ty(exp_found.found),
+            self.get_impl_future_output_ty(exp_found.expected).map(Binder::skip_binder),
+            self.get_impl_future_output_ty(exp_found.found).map(Binder::skip_binder),
         ) {
             (Some(exp), Some(found)) if same_type_modulo_infer(exp, found) => match cause.code() {
                 ObligationCauseCode::IfExpression(box IfExpressionCause { then, .. }) => {
@@ -1924,7 +1922,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() {
@@ -2215,9 +2213,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
                     },
@@ -2248,7 +2246,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 ");
@@ -2294,12 +2292,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..1fc78f8f9e305eeb7879ed57d0c57a2d597b767b 100644 (file)
@@ -4,15 +4,15 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, MatchSource, Pat};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::infer::unify_key::ConstVariableOriginKind;
 use rustc_middle::ty::print::Print;
 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)) => {
@@ -83,10 +83,10 @@ fn is_try_conversion(&self, callee: &Expr<'tcx>) -> bool {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for FindHirNodeVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.infcx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.infcx.tcx.hir()
     }
 
     fn visit_local(&mut self, local: &'tcx Local<'tcx>) {
@@ -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 ac57796763fb3cf30082f085707e5428cdd6785e..4eec492b3aeb9d4b7c2d9ac3e64a1322e6b50462 100644 (file)
@@ -106,90 +106,47 @@ pub(super) fn try_report_anon_anon_conflict(&self) -> Option<ErrorReported> {
             None => String::new(),
         };
 
-        let (span_1, span_2, main_label, span_label, future_return_type) =
-            match (sup_is_ret_type, sub_is_ret_type) {
-                (None, None) => {
-                    let (main_label_1, span_label_1) = if ty_sup.hir_id == ty_sub.hir_id {
-                        (
-                            "this type is declared with multiple lifetimes...".to_owned(),
-                            "...but data with one lifetime flows into the other here".to_owned(),
-                        )
-                    } else {
-                        (
-                            "these two types are declared with different lifetimes...".to_owned(),
-                            format!("...but data{} flows{} here", span_label_var1, span_label_var2),
-                        )
-                    };
-                    (ty_sup.span, ty_sub.span, main_label_1, span_label_1, None)
-                }
+        debug!(
+            "try_report_anon_anon_conflict: sub_is_ret_type={:?} sup_is_ret_type={:?}",
+            sub_is_ret_type, sup_is_ret_type
+        );
 
-                (Some(ret_span), _) => {
-                    let sup_future = self.future_return_type(scope_def_id_sup);
-                    let (return_type, action) = if sup_future.is_some() {
-                        ("returned future", "held across an await point")
-                    } else {
-                        ("return type", "returned")
-                    };
+        let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
 
-                    (
-                        ty_sub.span,
-                        ret_span,
-                        format!(
-                            "this parameter and the {} are declared with different lifetimes...",
-                            return_type
-                        ),
-                        format!("...but data{} is {} here", span_label_var1, action),
-                        sup_future,
-                    )
-                }
-                (_, Some(ret_span)) => {
-                    let sub_future = self.future_return_type(scope_def_id_sub);
-                    let (return_type, action) = if sub_future.is_some() {
-                        ("returned future", "held across an await point")
-                    } else {
-                        ("return type", "returned")
-                    };
+        match (sup_is_ret_type, sub_is_ret_type) {
+            (ret_capture @ Some(ret_span), _) | (_, ret_capture @ Some(ret_span)) => {
+                let param_span =
+                    if sup_is_ret_type == ret_capture { ty_sub.span } else { ty_sup.span };
+
+                err.span_label(
+                    param_span,
+                    "this parameter and the return type are declared with different lifetimes...",
+                );
+                err.span_label(ret_span, "");
+                err.span_label(span, format!("...but data{} is returned here", span_label_var1));
+            }
 
-                    (
+            (None, None) => {
+                if ty_sup.hir_id == ty_sub.hir_id {
+                    err.span_label(ty_sup.span, "this type is declared with multiple lifetimes...");
+                    err.span_label(ty_sub.span, "");
+                    err.span_label(span, "...but data with one lifetime flows into the other here");
+                } else {
+                    err.span_label(
                         ty_sup.span,
-                        ret_span,
-                        format!(
-                            "this parameter and the {} are declared with different lifetimes...",
-                            return_type
-                        ),
-                        format!("...but data{} is {} here", span_label_var1, action),
-                        sub_future,
-                    )
+                        "these two types are declared with different lifetimes...",
+                    );
+                    err.span_label(ty_sub.span, "");
+                    err.span_label(
+                        span,
+                        format!("...but data{} flows{} here", span_label_var1, span_label_var2),
+                    );
                 }
-            };
-
-        let mut err = struct_span_err!(self.tcx().sess, span, E0623, "lifetime mismatch");
-
-        err.span_label(span_1, main_label);
-        err.span_label(span_2, String::new());
-        err.span_label(span, span_label);
+            }
+        }
 
         self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
 
-        if let Some(t) = future_return_type {
-            let snip = self
-                .tcx()
-                .sess
-                .source_map()
-                .span_to_snippet(t.span)
-                .ok()
-                .and_then(|s| match (&t.kind, s.as_str()) {
-                    (rustc_hir::TyKind::Tup(&[]), "") => Some("()".to_string()),
-                    (_, "") => None,
-                    _ => Some(s),
-                })
-                .unwrap_or_else(|| "{unnamed_type}".to_string());
-
-            err.span_label(
-                t.span,
-                &format!("this `async fn` implicitly returns an `impl Future<Output = {}>`", snip),
-            );
-        }
         err.emit();
         Some(ErrorReported)
     }
index 89023101f3cd2c68f1e23b0cd4e76ee24c6814c6..b1535701bb399dc86fbda3a1f0c57c1a3b63e75e 100644 (file)
@@ -1,7 +1,7 @@
 use rustc_hir as hir;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_hir::Node;
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime as rl;
 use rustc_middle::ty::{self, Region, TyCtxt};
 
@@ -24,25 +24,19 @@ pub(crate) fn find_anon_type<'tcx>(
     tcx: TyCtxt<'tcx>,
     region: Region<'tcx>,
     br: &ty::BoundRegionKind,
-) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnDecl<'tcx>)> {
+) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnSig<'tcx>)> {
     if let Some(anon_reg) = tcx.is_suitable_region(region) {
         let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
-        let fndecl = match tcx.hir().get(hir_id) {
-            Node::Item(&hir::Item { kind: hir::ItemKind::Fn(ref m, ..), .. })
-            | Node::TraitItem(&hir::TraitItem {
-                kind: hir::TraitItemKind::Fn(ref m, ..), ..
-            })
-            | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(ref m, ..), .. }) => {
-                &m.decl
-            }
-            _ => return None,
+        let Some(fn_sig) = tcx.hir().get(hir_id).fn_sig() else {
+            return None
         };
 
-        fndecl
+        fn_sig
+            .decl
             .inputs
             .iter()
             .find_map(|arg| find_component_for_bound_region(tcx, arg, br))
-            .map(|ty| (ty, &**fndecl))
+            .map(|ty| (ty, fn_sig))
     } else {
         None
     }
@@ -84,10 +78,10 @@ struct FindNestedTypeVisitor<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
@@ -208,10 +202,10 @@ struct TyPathVisitor<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Map<'tcx>> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Map<'tcx> {
+        self.tcx.hir()
     }
 
     fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) {
index b6dff2e53e9cd0e5eac97c50d8bbb4035685acf5..412a077959d01a9104d51275eaa26c3a69cc2f5d 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
 use rustc_middle::ty::{
     self, AssocItemContainer, RegionKind, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable,
@@ -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) => {
@@ -580,12 +575,6 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
 pub(super) struct HirTraitObjectVisitor<'a>(pub(super) &'a mut Vec<Span>, pub(super) DefId);
 
 impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
-    type Map = ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) {
         if let TyKind::TraitObject(
             poly_trait_refs,
index f5fb82dbf31d2c9bb95b85d4f8e73280097731a7..bbea450a76973a868c48b05e169bd936b50944c2 100644 (file)
@@ -9,6 +9,7 @@
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::print::RegionHighlightMode;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor};
 
@@ -80,26 +81,21 @@ fn emit_err(&self, sp: Span, expected: Ty<'tcx>, found: Ty<'tcx>, trait_def_id:
 
         // Mark all unnamed regions in the type with a number.
         // This diagnostic is called in response to lifetime errors, so be informative.
-        struct HighlightBuilder<'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 +105,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;
 
@@ -187,10 +183,10 @@ struct TypeParamSpanVisitor<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
-    type Map = rustc_middle::hir::map::Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
-        hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
index 04eceecc5f072a6e4faf48fdde71178f03a78a52..6d71d702cc89b069950d2cf733d37d07eb932b42 100644 (file)
@@ -4,7 +4,7 @@
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
-use rustc_middle::ty::{self, DefIdTree, Region, Ty};
+use rustc_middle::ty::{self, Binder, DefIdTree, Region, Ty, TypeFoldable};
 use rustc_span::Span;
 
 /// Information about the anonymous region we are searching for.
@@ -94,80 +94,42 @@ pub(super) fn find_param_with_region(
             })
     }
 
-    pub(super) fn future_return_type(
-        &self,
-        local_def_id: LocalDefId,
-    ) -> Option<&rustc_hir::Ty<'_>> {
-        if let Some(hir::IsAsync::Async) = self.asyncness(local_def_id) {
-            if let rustc_middle::ty::Opaque(def_id, _) =
-                self.tcx().type_of(local_def_id).fn_sig(self.tcx()).output().skip_binder().kind()
-            {
-                match self.tcx().hir().get_if_local(*def_id) {
-                    Some(hir::Node::Item(hir::Item {
-                        kind:
-                            hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                                bounds,
-                                origin: hir::OpaqueTyOrigin::AsyncFn(..),
-                                ..
-                            }),
-                        ..
-                    })) => {
-                        for b in bounds.iter() {
-                            if let hir::GenericBound::LangItemTrait(
-                                hir::LangItem::Future,
-                                _span,
-                                _hir_id,
-                                generic_args,
-                            ) = b
-                            {
-                                for type_binding in generic_args.bindings.iter() {
-                                    if type_binding.ident.name == rustc_span::sym::Output {
-                                        if let hir::TypeBindingKind::Equality { ty } =
-                                            type_binding.kind
-                                        {
-                                            return Some(ty);
-                                        }
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    _ => {}
-                }
-            }
-        }
-        None
-    }
-
-    pub(super) fn asyncness(&self, local_def_id: LocalDefId) -> Option<hir::IsAsync> {
-        // similar to the asyncness fn in rustc_ty_utils::ty
-        let hir_id = self.tcx().hir().local_def_id_to_hir_id(local_def_id);
-        let node = self.tcx().hir().get(hir_id);
-        let fn_kind = node.fn_kind()?;
-        Some(fn_kind.asyncness())
-    }
-
     // Here, we check for the case where the anonymous region
-    // is in the return type.
+    // is in the return type as written by the user.
     // FIXME(#42703) - Need to handle certain cases here.
     pub(super) fn is_return_type_anon(
         &self,
         scope_def_id: LocalDefId,
         br: ty::BoundRegionKind,
-        decl: &hir::FnDecl<'_>,
+        hir_sig: &hir::FnSig<'_>,
     ) -> Option<Span> {
-        let ret_ty = self.tcx().type_of(scope_def_id);
-        if let ty::FnDef(_, _) = ret_ty.kind() {
-            let sig = ret_ty.fn_sig(self.tcx());
-            let late_bound_regions =
-                self.tcx().collect_referenced_late_bound_regions(&sig.output());
-            if late_bound_regions.iter().any(|r| *r == br) {
-                return Some(decl.output.span());
-            }
+        let fn_ty = self.tcx().type_of(scope_def_id);
+        if let ty::FnDef(_, _) = fn_ty.kind() {
+            let ret_ty = fn_ty.fn_sig(self.tcx()).output();
+            let span = hir_sig.decl.output.span();
+            let future_output = if hir_sig.header.is_async() {
+                ret_ty.map_bound(|ty| self.infcx.get_impl_future_output_ty(ty)).transpose()
+            } else {
+                None
+            };
+            return match future_output {
+                Some(output) if self.includes_region(output, br) => Some(span),
+                None if self.includes_region(ret_ty, br) => Some(span),
+                _ => None,
+            };
         }
         None
     }
 
+    fn includes_region(
+        &self,
+        ty: Binder<'tcx, impl TypeFoldable<'tcx>>,
+        region: ty::BoundRegionKind,
+    ) -> bool {
+        let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty);
+        late_bound_regions.iter().any(|r| *r == region)
+    }
+
     // Here we check for the case where anonymous region
     // corresponds to self and if yes, we display E0312.
     // FIXME(#42700) - Need to format self properly to
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..4851e637d3a62eeb3f440bba63776549497b7107 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,
@@ -570,15 +584,10 @@ fn fold_opaque_ty(
             debug!(?predicate);
 
             if let ty::PredicateKind::Projection(projection) = predicate.kind().skip_binder() {
-                if projection.ty.references_error() {
-                    // No point on adding these obligations since there's a type error involved.
+                if projection.term.references_error() {
                     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 +628,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 74eb263a6339021bb7ab7315232f948b7836c7c6..a5276afc5bfa7ed03b59fd2cc5ccecaa4378a70c 100644 (file)
@@ -164,7 +164,7 @@ pub fn process_registered_region_obligations(
             "cannot process registered region obligations in a snapshot"
         );
 
-        debug!("process_registered_region_obligations()");
+        debug!(?param_env, "process_registered_region_obligations()");
 
         let my_region_obligations = self.take_registered_region_obligations();
 
@@ -356,6 +356,8 @@ fn projection_must_outlive(
         let trait_bounds: Vec<_> =
             self.verify_bound.projection_declared_bounds_from_trait(projection_ty).collect();
 
+        debug!(?trait_bounds);
+
         // Compute the bounds we can derive from the environment. This
         // is an "approximate" match -- in some cases, these bounds
         // may not apply.
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 9b53ab72b00dea078ce8b58767994a7622f77ff2..b45a6514d79347e05f8e1e47320901227486c2c1 100644 (file)
@@ -26,7 +26,8 @@ pub fn infer_projection(
             kind: TypeVariableOriginKind::NormalizeProjectionType,
             span: self.tcx.def_span(def_id),
         });
-        let projection = ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, ty: ty_var });
+        let projection =
+            ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, term: ty_var.into() });
         let obligation = Obligation::with_depth(
             cause,
             recursion_depth,
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..674c75fdee56113bb3b1b29067d7b7ecb235d549 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
@@ -241,10 +241,19 @@ fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
 
                             Component::UnresolvedInferenceVariable(_) => None,
 
-                            Component::Projection(_) | Component::EscapingProjection(_) => {
-                                // We can probably do more here. This
-                                // corresponds to a case like `<T as
-                                // Foo<'a>>::U: 'b`.
+                            Component::Projection(projection) => {
+                                // We might end up here if we have `Foo<<Bar as Baz>::Assoc>: 'a`.
+                                // With this, we can deduce that `<Bar as Baz>::Assoc: 'a`.
+                                let ty =
+                                    tcx.mk_projection(projection.item_def_id, projection.substs);
+                                Some(ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(
+                                    ty, r_min,
+                                )))
+                            }
+
+                            Component::EscapingProjection(_) => {
+                                // We might be able to do more here, but we don't
+                                // want to deal with escaping vars right now.
                                 None
                             }
                         })
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 816e770f01252ed97e1b5f4aa0ec81839d1ee8af..44acbd3cf2159d592a0523de7ed609883e5ed6e8 100644 (file)
@@ -646,6 +646,7 @@ macro_rules! untracked {
     untracked!(borrowck, String::from("other"));
     untracked!(deduplicate_diagnostics, false);
     untracked!(dep_tasks, true);
+    untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
     untracked!(dont_buffer_diagnostics, true);
     untracked!(dump_dep_graph, true);
     untracked!(dump_mir, Some(String::from("abc")));
@@ -677,7 +678,6 @@ macro_rules! untracked {
     // `pre_link_arg` is omitted because it just forwards to `pre_link_args`.
     untracked!(pre_link_args, vec![String::from("abc"), String::from("def")]);
     untracked!(profile_closures, true);
-    untracked!(print_link_args, true);
     untracked!(print_llvm_passes, true);
     untracked!(print_mono_items, Some(String::from("abc")));
     untracked!(print_type_sizes, true);
index cb51555f5cadfabe109ddb2be9ae9a37a39aec75..3921187baa55eda5c3ebe94ec0e758c9fe4ccf1d 100644 (file)
@@ -1,7 +1,7 @@
 use libloading::Library;
 use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *};
 use rustc_ast::ptr::P;
-use rustc_ast::{self as ast, AttrVec, BlockCheckMode};
+use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Term};
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 #[cfg(parallel_compiler)]
@@ -738,9 +738,14 @@ fn involves_impl_trait(ty: &ast::Ty) -> bool {
                                         | ast::GenericArg::Const(_) => false,
                                     },
                                     ast::AngleBracketedArg::Constraint(c) => match c.kind {
-                                        ast::AssocTyConstraintKind::Bound { .. } => true,
-                                        ast::AssocTyConstraintKind::Equality { ref ty } => {
-                                            involves_impl_trait(ty)
+                                        ast::AssocConstraintKind::Bound { .. } => true,
+                                        ast::AssocConstraintKind::Equality { ref term } => {
+                                            match term {
+                                                Term::Ty(ty) => involves_impl_trait(ty),
+                                                // FIXME(...): This should check if the constant
+                                                // involves a trait impl, but for now ignore.
+                                                Term::Const(_) => false,
+                                            }
                                         }
                                     },
                                 })
index 2b373a53b635d4c94b637b06b29454a3f5bcd29f..38e1669d331977ed5207eba26218ed452f1008dd 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,
                             );
                         }
@@ -1480,12 +1479,6 @@ struct WalkAssocTypes<'a, 'db> {
             err: &'a mut DiagnosticBuilder<'db>,
         }
         impl<'a, 'db, 'v> Visitor<'v> for WalkAssocTypes<'a, 'db> {
-            type Map = intravisit::ErasedMap<'v>;
-
-            fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-                intravisit::NestedVisitorMap::None
-            }
-
             fn visit_qpath(&mut self, qpath: &'v hir::QPath<'v>, id: hir::HirId, span: Span) {
                 if TypeAliasBounds::is_type_variable_assoc(qpath) {
                     self.err.span_help(
@@ -1663,7 +1656,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 c64a67b6b9f1b5c38dbc774948c62c0078930ed7..7353cd6b876b9642bbae981bd9b7d610c9f35015 100644 (file)
@@ -5,10 +5,7 @@
 use rustc_ast as ast;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::{
-    GenericArg, HirId, Item, ItemKind, MutTy, Mutability, Node, Path, PathSegment, QPath, Ty,
-    TyKind,
-};
+use rustc_hir::{GenericArg, HirId, Item, ItemKind, Node, Path, PathSegment, QPath, Ty, TyKind};
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
@@ -58,13 +55,6 @@ fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
     report_in_external_macro: true
 }
 
-declare_tool_lint! {
-    pub rustc::TY_PASS_BY_REFERENCE,
-    Allow,
-    "passing `Ty` or `TyCtxt` by reference",
-    report_in_external_macro: true
-}
-
 declare_tool_lint! {
     pub rustc::USAGE_OF_QUALIFIED_TY,
     Allow,
@@ -74,7 +64,6 @@ fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
 
 declare_lint_pass!(TyTyKind => [
     USAGE_OF_TY_TYKIND,
-    TY_PASS_BY_REFERENCE,
     USAGE_OF_QUALIFIED_TY,
 ]);
 
@@ -131,26 +120,6 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
                     }
                 }
             }
-            TyKind::Rptr(_, MutTy { ty: inner_ty, mutbl: Mutability::Not }) => {
-                if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
-                    if cx.tcx.impl_trait_ref(impl_did).is_some() {
-                        return;
-                    }
-                }
-                if let Some(t) = is_ty_or_ty_ctxt(cx, &inner_ty) {
-                    cx.struct_span_lint(TY_PASS_BY_REFERENCE, ty.span, |lint| {
-                        lint.build(&format!("passing `{}` by reference", t))
-                            .span_suggestion(
-                                ty.span,
-                                "try passing by value",
-                                t,
-                                // Changing type of function argument
-                                Applicability::MaybeIncorrect,
-                            )
-                            .emit();
-                    })
-                }
-            }
             _ => {}
         }
     }
index 773e5751f13706f768075eda261ea922224f4ee5..0ce760b64d9ca0e889f01d8877421d0852fc4521 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit as hir_visit;
 use rustc_hir::intravisit::Visitor;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::LintPass;
 use rustc_span::symbol::Symbol;
@@ -94,13 +94,13 @@ fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) {
 }
 
 impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPass<'tcx, T> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
     /// Because lints are scoped lexically, we want to walk nested
     /// items in the context of the outer item, so enable
     /// deep-walking.
-    fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
-        hir_visit::NestedVisitorMap::All(self.context.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.context.tcx.hir()
     }
 
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
index d3fa08650d8740937c6b132553831cf5133b5dae..6e95708b17fe4bcaf4296d66390ac7f0e954bc6f 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
 use rustc_hir::{intravisit, HirId, CRATE_HIR_ID};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::LevelAndSource;
 use rustc_middle::lint::LintDiagnosticBuilder;
 use rustc_middle::lint::{
@@ -599,10 +599,10 @@ fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F)
 }
 
 impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
index c7823032b0c23530d1edbe239e3f549abaed8d5e..4aa8505c9408dda782d97e677578a9bac5feec44 100644 (file)
@@ -56,6 +56,7 @@
 mod non_fmt_panic;
 mod nonstandard_style;
 mod noop_method_call;
+mod pass_by_value;
 mod passes;
 mod redundant_semicolon;
 mod traits;
@@ -85,6 +86,7 @@
 use non_fmt_panic::NonPanicFmt;
 use nonstandard_style::*;
 use noop_method_call::*;
+use pass_by_value::*;
 use redundant_semicolon::*;
 use traits::*;
 use types::*;
@@ -92,7 +94,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};
@@ -489,6 +492,8 @@ fn register_internals(store: &mut LintStore) {
     store.register_late_pass(|| Box::new(ExistingDocKeyword));
     store.register_lints(&TyTyKind::get_lints());
     store.register_late_pass(|| Box::new(TyTyKind));
+    store.register_lints(&PassByValue::get_lints());
+    store.register_late_pass(|| Box::new(PassByValue));
     store.register_group(
         false,
         "rustc::internal",
@@ -496,8 +501,8 @@ fn register_internals(store: &mut LintStore) {
         vec![
             LintId::of(DEFAULT_HASH_TYPES),
             LintId::of(USAGE_OF_TY_TYKIND),
+            LintId::of(PASS_BY_VALUE),
             LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO),
-            LintId::of(TY_PASS_BY_REFERENCE),
             LintId::of(USAGE_OF_QUALIFIED_TY),
             LintId::of(EXISTING_DOC_KEYWORD),
         ],
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;
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
new file mode 100644 (file)
index 0000000..26d0560
--- /dev/null
@@ -0,0 +1,94 @@
+use crate::{LateContext, LateLintPass, LintContext};
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::{GenericArg, PathSegment, QPath, TyKind};
+use rustc_middle::ty;
+use rustc_span::symbol::sym;
+
+declare_tool_lint! {
+    /// The `rustc_pass_by_value` lint marks a type with `#[rustc_pass_by_value]` requiring it to always be passed by value.
+    /// This is usually used for types that are thin wrappers around references, so there is no benefit to an extra
+    /// layer of indirection. (Example: `Ty` which is a reference to a `TyS`)
+    pub rustc::PASS_BY_VALUE,
+    Warn,
+    "pass by reference of a type flagged as `#[rustc_pass_by_value]`",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(PassByValue => [PASS_BY_VALUE]);
+
+impl<'tcx> LateLintPass<'tcx> for PassByValue {
+    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
+        match &ty.kind {
+            TyKind::Rptr(_, hir::MutTy { ty: inner_ty, mutbl: hir::Mutability::Not }) => {
+                if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
+                    if cx.tcx.impl_trait_ref(impl_did).is_some() {
+                        return;
+                    }
+                }
+                if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
+                    cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| {
+                        lint.build(&format!("passing `{}` by reference", t))
+                            .span_suggestion(
+                                ty.span,
+                                "try passing by value",
+                                t,
+                                // Changing type of function argument
+                                Applicability::MaybeIncorrect,
+                            )
+                            .emit();
+                    })
+                }
+            }
+            _ => {}
+        }
+    }
+}
+
+fn path_for_pass_by_value(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> Option<String> {
+    if let TyKind::Path(QPath::Resolved(_, path)) = &ty.kind {
+        match path.res {
+            Res::Def(_, def_id) if cx.tcx.has_attr(def_id, sym::rustc_pass_by_value) => {
+                let name = cx.tcx.item_name(def_id).to_ident_string();
+                let path_segment = path.segments.last().unwrap();
+                return Some(format!("{}{}", name, gen_args(cx, path_segment)));
+            }
+            Res::SelfTy(None, Some((did, _))) => {
+                if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
+                    if cx.tcx.has_attr(adt.did, sym::rustc_pass_by_value) {
+                        return Some(cx.tcx.def_path_str_with_substs(adt.did, substs));
+                    }
+                }
+            }
+            _ => (),
+        }
+    }
+
+    None
+}
+
+fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String {
+    if let Some(args) = &segment.args {
+        let params = args
+            .args
+            .iter()
+            .map(|arg| match arg {
+                GenericArg::Lifetime(lt) => lt.name.ident().to_string(),
+                GenericArg::Type(ty) => {
+                    cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_default()
+                }
+                GenericArg::Const(c) => {
+                    cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_default()
+                }
+                GenericArg::Infer(_) => String::from("_"),
+            })
+            .collect::<Vec<_>>();
+
+        if !params.is_empty() {
+            return format!("<{}>", params.join(", "));
+        }
+    }
+
+    String::new()
+}
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 f06fc3edf58595ea5a518089acc474f9f0a7993e..7030fd53704dd74efa27fae77a252d932767997a 100644 (file)
@@ -1168,25 +1168,6 @@ extern "C" void LLVMRustRunRestrictionPass(LLVMModuleRef M, char **Symbols,
   passes.run(*unwrap(M));
 }
 
-extern "C" void LLVMRustMarkAllFunctionsNounwind(LLVMModuleRef M) {
-  for (Module::iterator GV = unwrap(M)->begin(), E = unwrap(M)->end(); GV != E;
-       ++GV) {
-    GV->setDoesNotThrow();
-    Function *F = dyn_cast<Function>(GV);
-    if (F == nullptr)
-      continue;
-
-    for (Function::iterator B = F->begin(), BE = F->end(); B != BE; ++B) {
-      for (BasicBlock::iterator I = B->begin(), IE = B->end(); I != IE; ++I) {
-        if (isa<InvokeInst>(I)) {
-          InvokeInst *CI = cast<InvokeInst>(I);
-          CI->setDoesNotThrow();
-        }
-      }
-    }
-  }
-}
-
 extern "C" void
 LLVMRustSetDataLayoutFromTargetMachine(LLVMModuleRef Module,
                                        LLVMTargetMachineRef TMR) {
index 639d2e617c77a4ad6f09c89920daeae986a66880..13cd8e4a046b03ba3d8a84da0ad655868ff83fde 100644 (file)
@@ -274,11 +274,6 @@ fn register_native_lib(&mut self, span: Option<Span>, lib: NativeLib) {
                     span,
                     "`#[link(...)]` with `kind = \"raw-dylib\"` only supported on Windows",
                 );
-            } else if !self.tcx.sess.target.options.is_like_msvc {
-                self.tcx.sess.span_warn(
-                    span,
-                    "`#[link(...)]` with `kind = \"raw-dylib\"` not supported on windows-gnu",
-                );
             }
 
             if lib_name.as_str().contains('\0') {
index e39ea46c0c0ca53bac447a3ed7d48090a17d21b8..220bc9c5f752f556bcf41e55b433f3043e68ef56 100644 (file)
@@ -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>> {
@@ -414,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)))
         })
     }
 }
@@ -442,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)
@@ -706,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
@@ -721,7 +721,7 @@ fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro {
         &self.raw_proc_macros.unwrap()[pos]
     }
 
-    fn opt_item_ident(&self, item_index: DefIndex, sess: &Session) -> Option<Ident> {
+    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)),
@@ -737,15 +737,15 @@ fn opt_item_ident(&self, item_index: DefIndex, sess: &Session) -> Option<Ident>
         Some(Ident::new(name, span))
     }
 
-    fn item_ident(&self, item_index: DefIndex, sess: &Session) -> Ident {
+    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 {}",
@@ -756,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 {}",
@@ -767,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
@@ -776,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 =
@@ -807,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));
@@ -820,6 +820,7 @@ fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
                     data.skip_array_during_method_dispatch,
                     data.specialization_kind,
                     self.def_path_hash(item_id),
+                    data.must_implement_one_of,
                 )
             }
             EntryKind::TraitAlias => ty::TraitDef::new(
@@ -831,13 +832,14 @@ fn get_trait_def(&self, item_id: DefIndex, sess: &Session) -> ty::TraitDef {
                 false,
                 ty::trait_def::TraitSpecializationKind::None,
                 self.def_path_hash(item_id),
+                None,
             ),
             _ => bug!("def-index does not refer to trait or trait alias"),
         }
     }
 
     fn get_variant(
-        &self,
+        self,
         kind: &EntryKind,
         index: DefIndex,
         parent_did: DefId,
@@ -862,7 +864,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,
@@ -874,7 +876,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(),
@@ -886,7 +888,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);
 
@@ -914,7 +916,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> {
@@ -922,7 +924,7 @@ fn get_explicit_predicates(
     }
 
     fn get_inferred_outlives(
-        &self,
+        self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
@@ -935,7 +937,7 @@ fn get_inferred_outlives(
     }
 
     fn get_super_predicates(
-        &self,
+        self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> ty::GenericPredicates<'tcx> {
@@ -943,7 +945,7 @@ fn get_super_predicates(
     }
 
     fn get_explicit_item_bounds(
-        &self,
+        self,
         item_id: DefIndex,
         tcx: TyCtxt<'tcx>,
     ) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
@@ -955,11 +957,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
@@ -968,63 +970,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_trait_item_def_id(&self, id: DefIndex) -> Option<DefId> {
+    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> {
+    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> {
@@ -1032,46 +1034,34 @@ 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>)] {
-        // FIXME: For a proc macro crate, not sure whether we should return the "host"
-        // features or an empty Vec. Both don't cause ICEs.
+    fn get_lib_features(self, tcx: TyCtxt<'tcx>) -> &'tcx [(Symbol, Option<Symbol>)] {
         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)] {
-        if self.root.is_proc_macro_crate() {
-            // Proc macro crates do not export any lang-items to the target.
-            &[]
-        } else {
-            tcx.arena.alloc_from_iter(
-                self.root
-                    .lang_items
-                    .decode(self)
-                    .map(|(def_index, index)| (self.local_def_id(def_index), index)),
-            )
-        }
+    fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
+        tcx.arena.alloc_from_iter(
+            self.root
+                .lang_items
+                .decode(self)
+                .map(|(def_index, index)| (self.local_def_id(def_index), index)),
+        )
     }
 
     /// Iterates over the diagnostic items in the given crate.
-    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()
-        } else {
-            let mut id_to_name = FxHashMap::default();
-            let name_to_id = self
-                .root
-                .diagnostic_items
-                .decode(self)
-                .map(|(name, def_index)| {
-                    let id = self.local_def_id(def_index);
-                    id_to_name.insert(id, name);
-                    (name, id)
-                })
-                .collect();
-            DiagnosticItems { id_to_name, name_to_id }
-        }
+    fn get_diagnostic_items(self) -> DiagnosticItems {
+        let mut id_to_name = FxHashMap::default();
+        let name_to_id = self
+            .root
+            .diagnostic_items
+            .decode(self)
+            .map(|(name, def_index)| {
+                let id = self.local_def_id(def_index);
+                id_to_name.insert(id, name);
+                (name, id)
+            })
+            .collect();
+        DiagnosticItems { id_to_name, name_to_id }
     }
 
     /// Iterates over all named children of the given module,
@@ -1079,7 +1069,7 @@ fn get_diagnostic_items(&self) -> DiagnosticItems {
     /// 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,
+        self,
         id: DefIndex,
         mut callback: impl FnMut(ModChild),
         sess: &Session,
@@ -1177,15 +1167,15 @@ fn for_each_module_child(
         }
     }
 
-    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)
@@ -1194,7 +1184,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
@@ -1205,7 +1195,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
@@ -1217,7 +1207,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> {
@@ -1228,7 +1218,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
@@ -1237,7 +1227,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
@@ -1248,7 +1238,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, _)
@@ -1263,14 +1253,14 @@ 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_def_ids(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx [DefId] {
+    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)),
@@ -1280,7 +1270,7 @@ fn get_associated_item_def_ids(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> &'tcx
         }
     }
 
-    fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem {
+    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);
@@ -1307,11 +1297,11 @@ fn get_associated_item(&self, id: DefIndex, sess: &Session) -> ty::AssocItem {
         }
     }
 
-    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);
@@ -1322,7 +1312,7 @@ fn get_ctor_def_id_and_kind(&self, node_id: DefIndex) -> Option<(DefId, CtorKind
     }
 
     fn get_item_attrs(
-        &'a self,
+        self,
         id: DefIndex,
         sess: &'a Session,
     ) -> impl Iterator<Item = ast::Attribute> + 'a {
@@ -1346,30 +1336,32 @@ fn get_item_attrs(
             .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: &'a Session,
+    ) -> impl Iterator<Item = Spanned<Symbol>> + 'a {
         self.root
             .tables
             .children
             .get(self, id)
             .unwrap_or_else(Lazy::empty)
             .decode(self)
-            .map(|index| respan(self.get_span(index, sess), self.item_ident(index, sess).name))
-            .collect()
+            .map(move |index| respan(self.get_span(index, sess), self.item_ident(index, sess).name))
     }
 
-    fn get_struct_field_visibilities(&self, id: DefIndex) -> Vec<Visibility> {
+    fn get_struct_field_visibilities(self, id: DefIndex) -> impl Iterator<Item = Visibility> + 'a {
         self.root
             .tables
             .children
             .get(self, id)
             .unwrap_or_else(Lazy::empty)
             .decode(self)
-            .map(|field_index| self.get_visibility(field_index))
-            .collect()
+            .map(move |field_index| self.get_visibility(field_index))
     }
 
     fn get_inherent_implementations_for_type(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         id: DefIndex,
     ) -> &'tcx [DefId] {
@@ -1384,25 +1376,24 @@ 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_trait_impls(&'a self) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + 'a {
-        self.trait_impls.values().flat_map(move |impls| {
+    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(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
+                .map(move |(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
         })
     }
 
     fn get_implementations_of_trait(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
         trait_def_id: DefId,
     ) -> &'tcx [(DefId, Option<SimplifiedType>)] {
-        if self.root.is_proc_macro_crate() {
-            // proc-macro crates export no trait impls.
+        if self.trait_impls.is_empty() {
             return &[];
         }
 
@@ -1424,7 +1415,7 @@ fn get_implementations_of_trait(
         }
     }
 
-    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(..) => (),
@@ -1437,16 +1428,11 @@ fn get_trait_of_item(&self, id: DefIndex) -> Option<DefId> {
         })
     }
 
-    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![]
-        } else {
-            self.root.native_libraries.decode((self, sess)).collect()
-        }
+    fn get_native_libraries(self, sess: &'a Session) -> impl Iterator<Item = NativeLib> + 'a {
+        self.root.native_libraries.decode((self, sess))
     }
 
-    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
@@ -1455,19 +1441,12 @@ 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>> {
-        if self.root.is_proc_macro_crate() {
-            // Proc macro crates do not have any *target* foreign modules.
-            Lrc::new(FxHashMap::default())
-        } else {
-            let modules: FxHashMap<DefId, ForeignModule> =
-                self.root.foreign_modules.decode((self, tcx.sess)).map(|m| (m.def_id, m)).collect();
-            Lrc::new(modules)
-        }
+    fn get_foreign_modules(self, sess: &'a Session) -> impl Iterator<Item = ForeignModule> + '_ {
+        self.root.foreign_modules.decode((self, sess))
     }
 
     fn get_dylib_dependency_formats(
-        &self,
+        self,
         tcx: TyCtxt<'tcx>,
     ) -> &'tcx [(CrateNum, LinkagePreference)] {
         tcx.arena.alloc_from_iter(
@@ -1478,16 +1457,11 @@ fn get_dylib_dependency_formats(
         )
     }
 
-    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.
-            &[]
-        } else {
-            tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self))
-        }
+    fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
+        tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self))
     }
 
-    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,
@@ -1497,19 +1471,13 @@ 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() {
-            // If this crate is a custom derive crate, then we're not even going to
-            // link those in so we skip those crates.
-            &[]
-        } else {
-            tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx)))
-        }
+        tcx.arena.alloc_from_iter(self.root.exported_symbols.decode((self, tcx)))
     }
 
-    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)
@@ -1518,7 +1486,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!(),
@@ -1527,7 +1495,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,
@@ -1538,7 +1506,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,
@@ -1547,7 +1515,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
@@ -1556,7 +1524,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),
@@ -1564,19 +1532,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()
@@ -1585,13 +1553,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 {
@@ -1601,17 +1569,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));
@@ -1669,7 +1637,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 51b3cc7e4fa54bc32e9d4dec4cde5d733c3ec266..9b59c14c2fec82a342c4dd7c2183e953ac4004bb 100644 (file)
@@ -179,8 +179,10 @@ fn into_args(self) -> (DefId, DefId) {
 
         reachable_non_generics
     }
-    native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) }
-    foreign_modules => { cdata.get_foreign_modules(tcx) }
+    native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess).collect()) }
+    foreign_modules => {
+        Lrc::new(cdata.get_foreign_modules(tcx.sess).map(|m| (m.def_id, m)).collect())
+    }
     crate_hash => { cdata.root.hash }
     crate_host_hash => { cdata.host_hash }
     crate_name => { cdata.root.name }
@@ -352,7 +354,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)),
@@ -371,11 +373,18 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) {
 }
 
 impl CStore {
-    pub fn struct_field_names_untracked(&self, def: DefId, sess: &Session) -> Vec<Spanned<Symbol>> {
+    pub fn struct_field_names_untracked<'a>(
+        &'a self,
+        def: DefId,
+        sess: &'a Session,
+    ) -> impl Iterator<Item = Spanned<Symbol>> + 'a {
         self.get_crate_data(def.krate).get_struct_field_names(def.index, sess)
     }
 
-    pub fn struct_field_visibilities_untracked(&self, def: DefId) -> Vec<Visibility> {
+    pub fn struct_field_visibilities_untracked(
+        &self,
+        def: DefId,
+    ) -> impl Iterator<Item = Visibility> + '_ {
         self.get_crate_data(def.krate).get_struct_field_visibilities(def.index)
     }
 
@@ -460,8 +469,12 @@ pub fn num_def_ids_untracked(&self, cnum: CrateNum) -> usize {
         self.get_crate_data(cnum).num_def_ids()
     }
 
-    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()
+    pub fn item_attrs_untracked<'a>(
+        &'a self,
+        def_id: DefId,
+        sess: &'a Session,
+    ) -> impl Iterator<Item = ast::Attribute> + 'a {
+        self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess)
     }
 
     pub fn get_proc_macro_quoted_span_untracked(
@@ -473,15 +486,15 @@ pub fn get_proc_macro_quoted_span_untracked(
         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 traits_in_crate_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ {
+        self.get_crate_data(cnum).get_traits()
     }
 
     pub fn trait_impls_in_crate_untracked(
         &self,
         cnum: CrateNum,
-    ) -> Vec<(DefId, Option<SimplifiedType>)> {
-        self.get_crate_data(cnum).get_trait_impls().collect()
+    ) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + '_ {
+        self.get_crate_data(cnum).get_trait_impls()
     }
 }
 
index 2e556275fb517f20e5abb20712f83b311d93a501..ebb78adf343ced020eee4149784ef86687934eb5 100644 (file)
     CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE,
 };
 use rustc_hir::definitions::DefPathData;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::lang_items;
 use rustc_hir::{AnonConst, GenericParamKind};
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_index::vec::Idx;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::dependency_format::Linkage;
 use rustc_middle::middle::exported_symbols::{
     metadata_symbol_name, ExportedSymbol, SymbolExportLevel,
@@ -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`.
@@ -1138,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);
     }
 
@@ -1513,6 +1513,7 @@ fn encode_info_for_item(&mut self, def_id: DefId, item: &'tcx hir::Item<'tcx>) {
                     is_marker: trait_def.is_marker,
                     skip_array_during_method_dispatch: trait_def.skip_array_during_method_dispatch,
                     specialization_kind: trait_def.specialization_kind,
+                    must_implement_one_of: trait_def.must_implement_one_of.clone(),
                 };
 
                 EntryKind::Trait(self.lazy(data))
@@ -1579,12 +1580,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() {
@@ -1605,9 +1606,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);
@@ -1917,10 +1918,10 @@ fn encode_info_for_foreign_item(&mut self, def_id: DefId, nitem: &hir::ForeignIt
 
 // FIXME(eddyb) make metadata encoding walk over all definitions, instead of HIR.
 impl<'a, 'tcx> Visitor<'tcx> for EncodeContext<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
     fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         intravisit::walk_expr(self, ex);
@@ -1928,8 +1929,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);
@@ -1983,8 +1983,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);
         }
     }
 
index 75c5880f05d927a0b4e05978dd963f1a8acebd80..8424a31d59fce72a8b2ebddd8badee4b684ef5be 100644 (file)
@@ -378,6 +378,7 @@ struct TraitData {
     is_marker: bool,
     skip_array_during_method_dispatch: bool,
     specialization_kind: ty::trait_def::TraitSpecializationKind,
+    must_implement_one_of: Option<Box<[Ident]>>,
 }
 
 #[derive(TyEncodable, TyDecodable)]
index a9db8469384ed9b34ee081975bd9521414b71e3d..30664784ed8f8540a0a91e59ddac373a5f4f5d84 100644 (file)
@@ -12,8 +12,8 @@ bitflags = "1.2.1"
 either = "1.5.0"
 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 };
index 394a1fc227095ba0a6125ae3f8adeb5e91c7e8a2..82ea7ff6aab5445aea1e710ec85d7f9e3bd304ee 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::*;
 use rustc_index::vec::Idx;
+use rustc_middle::hir::nested_filter;
 use rustc_span::def_id::StableCrateId;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::Spanned;
@@ -117,13 +118,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 +142,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 +201,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 +341,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 +546,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 +794,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 +873,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 +942,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,
         })
     }
@@ -1256,10 +1273,10 @@ struct ModuleCollector<'tcx> {
     }
 
     impl<'hir> Visitor<'hir> for ModuleCollector<'hir> {
-        type Map = Map<'hir>;
+        type NestedFilter = nested_filter::All;
 
-        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-            intravisit::NestedVisitorMap::All(self.tcx.hir())
+        fn nested_visit_map(&mut self) -> Self::Map {
+            self.tcx.hir()
         }
 
         fn visit_item(&mut self, item: &'hir Item<'hir>) {
index 557dc25528f1314bf7be9a7f34ee94170b69e918..b4c7bb7eba79c82bcbdee45c4ac27a3723f5903d 100644 (file)
@@ -3,6 +3,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html
 
 pub mod map;
+pub mod nested_filter;
 pub mod place;
 
 use crate::ty::query::Providers;
@@ -58,13 +59,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 })
     };
diff --git a/compiler/rustc_middle/src/hir/nested_filter.rs b/compiler/rustc_middle/src/hir/nested_filter.rs
new file mode 100644 (file)
index 0000000..7cfb207
--- /dev/null
@@ -0,0 +1,27 @@
+use rustc_hir::intravisit::nested_filter::NestedFilter;
+
+/// Do not visit nested item-like things, but visit nested things
+/// that are inside of an item-like.
+///
+/// **This is the most common choice.** A very common pattern is
+/// to use `visit_all_item_likes()` as an outer loop,
+/// and to have the visitor that visits the contents of each item
+/// using this setting.
+pub struct OnlyBodies(());
+impl<'hir> NestedFilter<'hir> for OnlyBodies {
+    type Map = crate::hir::map::Map<'hir>;
+    const INTER: bool = false;
+    const INTRA: bool = true;
+}
+
+/// Visits all nested things, including item-likes.
+///
+/// **This is an unusual choice.** It is used when you want to
+/// process everything within their lexical context. Typically you
+/// kick off the visit by doing `walk_krate()`.
+pub struct All(());
+impl<'hir> NestedFilter<'hir> for All {
+    type Map = crate::hir::map::Map<'hir>;
+    const INTER: bool = true;
+    const INTRA: bool = true;
+}
index 605fff671db06dfca12e5f931d0f9b69a11c3aa4..28217aeab13ee51d91d752fcfc5802b5d167cc49 100644 (file)
@@ -23,7 +23,7 @@
 
 use crate::infer::MemberConstraint;
 use crate::ty::subst::GenericArg;
-use crate::ty::{self, BoundVar, List, Region, TyCtxt};
+use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt};
 use rustc_index::vec::IndexVec;
 use rustc_macros::HashStable;
 use smallvec::SmallVec;
@@ -104,7 +104,7 @@ pub fn is_existential(&self) -> bool {
             CanonicalVarKind::PlaceholderTy(_) => false,
             CanonicalVarKind::Region(_) => true,
             CanonicalVarKind::PlaceholderRegion(..) => false,
-            CanonicalVarKind::Const(_) => true,
+            CanonicalVarKind::Const(..) => true,
             CanonicalVarKind::PlaceholderConst(_) => false,
         }
     }
@@ -130,7 +130,7 @@ pub enum CanonicalVarKind<'tcx> {
     PlaceholderRegion(ty::PlaceholderRegion),
 
     /// Some kind of const inference variable.
-    Const(ty::UniverseIndex),
+    Const(ty::UniverseIndex, Ty<'tcx>),
 
     /// A "placeholder" that represents "any const".
     PlaceholderConst(ty::PlaceholderConst<'tcx>),
@@ -147,7 +147,7 @@ pub fn universe(self) -> ty::UniverseIndex {
             CanonicalVarKind::PlaceholderTy(placeholder) => placeholder.universe,
             CanonicalVarKind::Region(ui) => ui,
             CanonicalVarKind::PlaceholderRegion(placeholder) => placeholder.universe,
-            CanonicalVarKind::Const(ui) => ui,
+            CanonicalVarKind::Const(ui, _) => ui,
             CanonicalVarKind::PlaceholderConst(placeholder) => placeholder.universe,
         }
     }
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 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 52ef380001cb09e388ba7d8f84e0321c8b05745c..48f39b26152cbbc40103eadfbe4daa74216d739f 100644 (file)
@@ -162,7 +162,7 @@ pub fn phase_index(&self) -> usize {
 }
 
 /// Where a specific `mir::Body` comes from.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable)]
 pub struct MirSource<'tcx> {
     pub instance: InstanceDef<'tcx>,
@@ -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]
@@ -1254,17 +1255,7 @@ pub enum AssertKind<O> {
     ResumedAfterPanic(GeneratorKind),
 }
 
-#[derive(
-    Clone,
-    Debug,
-    PartialEq,
-    PartialOrd,
-    TyEncodable,
-    TyDecodable,
-    Hash,
-    HashStable,
-    TypeFoldable
-)]
+#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
 pub enum InlineAsmOperand<'tcx> {
     In {
         reg: InlineAsmRegOrRegClass,
@@ -1565,10 +1556,6 @@ pub enum StatementKind<'tcx> {
     /// End the current live range for the storage of the local.
     StorageDead(Local),
 
-    /// Executes a piece of inline Assembly. Stored in a Box to keep the size
-    /// of `StatementKind` low.
-    LlvmInlineAsm(Box<LlvmInlineAsm<'tcx>>),
-
     /// Retag references in the given place, ensuring they got fresh tags. This is
     /// part of the Stacked Borrows model. These statements are currently only interpreted
     /// by miri and only generated when "-Z mir-emit-retag" is passed.
@@ -1688,13 +1675,6 @@ pub enum FakeReadCause {
     ForIndex,
 }
 
-#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
-pub struct LlvmInlineAsm<'tcx> {
-    pub asm: hir::LlvmInlineAsmInner,
-    pub outputs: Box<[Place<'tcx>]>,
-    pub inputs: Box<[(Span, Operand<'tcx>)]>,
-}
-
 impl Debug for Statement<'_> {
     fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
         use self::StatementKind::*;
@@ -1719,9 +1699,6 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
             SetDiscriminant { ref place, variant_index } => {
                 write!(fmt, "discriminant({:?}) = {:?}", place, variant_index)
             }
-            LlvmInlineAsm(ref asm) => {
-                write!(fmt, "llvm_asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs)
-            }
             AscribeUserType(box (ref place, ref c_ty), ref variance) => {
                 write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
             }
@@ -1760,7 +1737,7 @@ pub struct CopyNonOverlapping<'tcx> {
 
 /// A path to a value; something that can be evaluated without
 /// changing or disturbing program state.
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, HashStable)]
 pub struct Place<'tcx> {
     pub local: Local,
 
@@ -2085,7 +2062,7 @@ pub struct SourceScopeLocalData {
 
 /// These are values that can appear inside an rvalue. They are intentionally
 /// limited to prevent rvalues from being nested in one another.
-#[derive(Clone, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub enum Operand<'tcx> {
     /// Copy: The value must be available for use afterwards.
     ///
@@ -2439,7 +2416,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()
                                 }
@@ -2449,7 +2426,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!(
@@ -2457,7 +2433,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)
@@ -2481,8 +2457,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
@@ -2515,7 +2490,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
 /// this does not necessarily mean that they are `==` in Rust. In
 /// particular, one must be wary of `NaN`!
 
-#[derive(Clone, Copy, PartialEq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable)]
+#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
 pub struct Constant<'tcx> {
     pub span: Span,
 
@@ -2529,7 +2504,7 @@ pub struct Constant<'tcx> {
     pub literal: ConstantKind<'tcx>,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
 #[derive(Lift)]
 pub enum ConstantKind<'tcx> {
     /// This constant came from the type system
@@ -2785,7 +2760,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..06cbc3383efff25c8020c404d75a8caa28a87af4 100644 (file)
@@ -245,7 +245,6 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
         SetDiscriminant { .. } => "SetDiscriminant",
         StorageLive(..) => "StorageLive",
         StorageDead(..) => "StorageDead",
-        LlvmInlineAsm(..) => "LlvmInlineAsm",
         Retag(..) => "Retag",
         AscribeUserType(..) => "AscribeUserType",
         Coverage(..) => "Coverage",
@@ -665,9 +664,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 51e4afaf2204afc6f3f2094fcebb0b92cef3a5ae..fafd847a1cbaa8ece09222a40c5623f1a1b1fad4 100644 (file)
@@ -105,7 +105,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
 
 impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {}
 
-#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq, PartialOrd)]
+#[derive(Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub enum TerminatorKind<'tcx> {
     /// Block should have one successor in the graph; we jump there.
     Goto { target: BasicBlock },
index f301c68a7c091d4476139397a9189f85e7e2456b..4452ac5e3e0d4b92f0f46dc7b1e91d5343feb8fc 100644 (file)
@@ -408,19 +408,6 @@ fn super_statement(&mut self,
                             location
                         );
                     }
-                    StatementKind::LlvmInlineAsm(asm) => {
-                        for output in & $($mutability)? asm.outputs[..] {
-                            self.visit_place(
-                                output,
-                                PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput),
-                                location
-                            );
-                        }
-                        for (span, input) in & $($mutability)? asm.inputs[..] {
-                            self.visit_span(span);
-                            self.visit_operand(input, location);
-                        }
-                    }
                     StatementKind::Retag(kind, place) => {
                         self.visit_retag(kind, place, location);
                     }
@@ -1178,10 +1165,6 @@ pub enum NonMutatingUseContext {
 pub enum MutatingUseContext {
     /// Appears as LHS of an assignment.
     Store,
-    /// Can often be treated as a `Store`, but needs to be separate because
-    /// ASM is allowed to read outputs as well, so a `Store`-`LlvmAsmOutput` sequence
-    /// cannot be simplified the way a `Store`-`Store` can be.
-    LlvmAsmOutput,
     /// Output operand of an inline assembly block.
     AsmOutput,
     /// Destination of a call.
@@ -1271,7 +1254,6 @@ pub fn is_place_assignment(&self) -> bool {
             PlaceContext::MutatingUse(
                 MutatingUseContext::Store
                     | MutatingUseContext::Call
-                    | MutatingUseContext::LlvmAsmOutput
                     | MutatingUseContext::AsmOutput,
             )
         )
index 3aca7a90194ee7cd348453f24c7b1dfa76e34dbe..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 { "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..11dc69ab71566f2289391e5c4671532d3305903a 100644 (file)
@@ -213,7 +213,7 @@ pub struct Expr<'tcx> {
 
 #[derive(Debug, HashStable)]
 pub enum ExprKind<'tcx> {
-    /// `Scope`s are used to explicitely mark destruction scopes,
+    /// `Scope`s are used to explicitly mark destruction scopes,
     /// and to track the `HirId` of the expressions within the scope.
     Scope {
         region_scope: region::Scope,
@@ -431,12 +431,6 @@ pub enum ExprKind<'tcx> {
     },
     /// An expression taking a reference to a thread local.
     ThreadLocalRef(DefId),
-    /// Inline LLVM assembly, i.e. `llvm_asm!()`.
-    LlvmInlineAsm {
-        asm: &'tcx hir::LlvmInlineAsmInner,
-        outputs: Box<[ExprId]>,
-        inputs: Box<[ExprId]>,
-    },
     /// A `yield` expression.
     Yield {
         value: ExprId,
@@ -726,7 +720,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 +732,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 7fc15e02fcd307511041e4743d8e851ca78382e4..9f9947341c5c1a6079fa9cad8dc83d3ec908e6e3 100644 (file)
@@ -145,14 +145,6 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
             }
         }
         ThreadLocalRef(_) => {}
-        LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
-            for &out_expr in &**outputs {
-                visitor.visit_expr(&visitor.thir()[out_expr]);
-            }
-            for &in_expr in &**inputs {
-                visitor.visit_expr(&visitor.thir()[in_expr]);
-            }
-        }
         Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
     }
 }
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 5af4eef40d4366481088f949b588cda45004e859..2776370ba6f465809b4a128928ae68d2cb799e60 100644 (file)
@@ -139,31 +139,29 @@ 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>,
+    /// Returns the associated item with the given name and `AssocKind`, if one exists.
+    pub fn find_by_name_and_kind(
+        &self,
+        tcx: TyCtxt<'_>,
         ident: Ident,
+        kind: AssocKind,
         parent_def_id: DefId,
-    ) -> impl 'a + Iterator<Item = &'a ty::AssocItem> {
+    ) -> Option<&ty::AssocItem> {
         self.filter_by_name_unhygienic(ident.name)
-            .filter(move |item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
+            .filter(|item| item.kind == kind)
+            .find(|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(
+    /// Returns the associated item with the given name and any of `AssocKind`, if one exists.
+    pub fn find_by_name_and_kinds(
         &self,
         tcx: TyCtxt<'_>,
         ident: Ident,
-        kind: AssocKind,
+        kinds: &[AssocKind],
         parent_def_id: DefId,
     ) -> Option<&ty::AssocItem> {
         self.filter_by_name_unhygienic(ident.name)
-            .filter(|item| item.kind == kind)
+            .filter(|item| kinds.contains(&item.kind))
             .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
     }
 
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..19a73732fcac3aaba32925a705fb4b9dd471385c 100644 (file)
@@ -36,15 +36,14 @@ pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx Self {
         Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id))
     }
 
+    #[instrument(skip(tcx), level = "debug")]
     pub fn from_opt_const_arg_anon_const(
         tcx: TyCtxt<'tcx>,
         def: ty::WithOptConstParam<LocalDefId>,
     ) -> &'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()),
@@ -53,6 +52,7 @@ pub fn from_opt_const_arg_anon_const(
         };
 
         let expr = &tcx.hir().body(body_id).value;
+        debug!(?expr);
 
         let ty = tcx.type_of(def.def_id_for_type_of());
 
@@ -61,7 +61,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,
@@ -69,11 +69,21 @@ pub fn from_opt_const_arg_anon_const(
         }
     }
 
+    #[instrument(skip(tcx), level = "debug")]
     fn try_eval_lit_or_param(
         tcx: TyCtxt<'tcx>,
         ty: Ty<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Option<&'tcx Self> {
+        // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
+        // currently have to be wrapped in curly brackets, so it's necessary to special-case.
+        let expr = match &expr.kind {
+            hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
+                block.expr.as_ref().unwrap()
+            }
+            _ => expr,
+        };
+
         let lit_input = match expr.kind {
             hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }),
             hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
@@ -88,22 +98,17 @@ fn try_eval_lit_or_param(
         if let Some(lit_input) = lit_input {
             // If an error occurred, ignore that it's a literal and leave reporting the error up to
             // mir.
-            if let Ok(c) = tcx.at(expr.span).lit_to_const(lit_input) {
-                return Some(c);
-            } else {
-                tcx.sess.delay_span_bug(expr.span, "Const::from_anon_const: couldn't lit_to_const");
+            match tcx.at(expr.span).lit_to_const(lit_input) {
+                Ok(c) => return Some(c),
+                Err(e) => {
+                    tcx.sess.delay_span_bug(
+                        expr.span,
+                        &format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
+                    );
+                }
             }
         }
 
-        // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
-        // currently have to be wrapped in curly brackets, so it's necessary to special-case.
-        let expr = match &expr.kind {
-            hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
-                block.expr.as_ref().unwrap()
-            }
-            _ => expr,
-        };
-
         use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
         match expr.kind {
             ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
@@ -153,14 +158,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 +265,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 86ad573b5d748dadbf591df77e6457b987e76e85..8d591d6781235d6861ece7b63210cd0fc7073591 100644 (file)
@@ -961,6 +961,7 @@ pub struct FreeRegionInfo {
 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/ty.html
 #[derive(Copy, Clone)]
 #[rustc_diagnostic_item = "TyCtxt"]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
 pub struct TyCtxt<'tcx> {
     gcx: &'tcx GlobalCtxt<'tcx>,
 }
@@ -1209,11 +1210,25 @@ pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty
         self.mk_ty(Error(DelaySpanBugEmitted(())))
     }
 
-    /// Like `err` but for constants.
+    /// Like [TyCtxt::ty_error] but for constants.
     #[track_caller]
     pub fn const_error(self, ty: Ty<'tcx>) -> &'tcx Const<'tcx> {
-        self.sess
-            .delay_span_bug(DUMMY_SP, "ty::ConstKind::Error constructed but no error reported.");
+        self.const_error_with_message(
+            ty,
+            DUMMY_SP,
+            "ty::ConstKind::Error constructed but no error reported",
+        )
+    }
+
+    /// Like [TyCtxt::ty_error_with_message] but for constants.
+    #[track_caller]
+    pub fn const_error_with_message<S: Into<MultiSpan>>(
+        self,
+        ty: Ty<'tcx>,
+        span: S,
+        msg: &str,
+    ) -> &'tcx Const<'tcx> {
+        self.sess.delay_span_bug(span, msg);
         self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty })
     }
 
@@ -1461,8 +1476,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 +1509,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 +1523,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 +1675,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 +1711,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 +2472,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),
         )
     }
 
index ee00f6c62f345005f9257a08de20dc0428b45125..d68c5514821a9b3904d57c1250501ea43093fb19 100644 (file)
@@ -4,7 +4,7 @@
 use crate::ty::TyKind::*;
 use crate::ty::{
     ConstKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, InferTy,
-    ProjectionTy, TyCtxt, TyS, TypeAndMut,
+    ProjectionTy, Term, TyCtxt, TyS, TypeAndMut,
 };
 
 use rustc_errors::{Applicability, DiagnosticBuilder};
@@ -105,8 +105,14 @@ fn const_is_suggestable(kind: ConstKind<'_>) -> bool {
                 ExistentialPredicate::Trait(ExistentialTraitRef { substs, .. }) => {
                     substs.iter().all(generic_arg_is_suggestible)
                 }
-                ExistentialPredicate::Projection(ExistentialProjection { substs, ty, .. }) => {
-                    ty.is_suggestable() && substs.iter().all(generic_arg_is_suggestible)
+                ExistentialPredicate::Projection(ExistentialProjection {
+                    substs, term, ..
+                }) => {
+                    let term_is_suggestable = match term {
+                        Term::Ty(ty) => ty.is_suggestable(),
+                        Term::Const(c) => const_is_suggestable(c.val),
+                    };
+                    term_is_suggestable && substs.iter().all(generic_arg_is_suggestible)
                 }
                 _ => true,
             }),
@@ -448,12 +454,6 @@ pub fn suggest_constraining_type_param(
 pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
 
 impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
-    type Map = rustc_hir::intravisit::ErasedMap<'v>;
-
-    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
-        hir::intravisit::NestedVisitorMap::None
-    }
-
     fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
         match ty.kind {
             hir::TyKind::TraitObject(
@@ -482,12 +482,6 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
 pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'tcx>);
 
 impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
-    type Map = rustc_hir::intravisit::ErasedMap<'v>;
-
-    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
-        hir::intravisit::NestedVisitorMap::None
-    }
-
     fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) {
         if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static =
             lt.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 617c522ac81971e27be38caa66622e34a1e361cc..f06a1b09cd82ab236553403b81ba572fd2d65dc6 100644 (file)
@@ -1,5 +1,5 @@
 use crate::ty::subst::{GenericArg, GenericArgKind};
-use crate::ty::{self, InferConst, Ty, TypeFlags};
+use crate::ty::{self, InferConst, Term, Ty, TypeFlags};
 use std::slice;
 
 #[derive(Debug)]
@@ -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);
             }
 
@@ -241,9 +241,12 @@ fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
                 self.add_ty(a);
                 self.add_ty(b);
             }
-            ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
+            ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
                 self.add_projection_ty(projection_ty);
-                self.add_ty(ty);
+                match term {
+                    Term::Ty(ty) => self.add_ty(ty),
+                    Term::Const(c) => self.add_const(c),
+                }
             }
             ty::PredicateKind::WellFormed(arg) => {
                 self.add_substs(slice::from_ref(&arg));
@@ -298,7 +301,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,29 +314,16 @@ 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);
     }
 
     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
         self.add_substs(projection.substs);
-        self.add_ty(projection.ty);
+        match projection.term {
+            ty::Term::Ty(ty) => self.add_ty(ty),
+            ty::Term::Const(ct) => self.add_const(ct),
+        }
     }
 
     fn add_projection_ty(&mut self, projection_ty: ty::ProjectionTy<'_>) {
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 f5f55dcf38cf4efb186221aedf669276d1b76f64..4bc3e23f4a588cb26b1e9218edfe29a2324a57e9 100644 (file)
@@ -20,6 +20,7 @@
 pub use vtable::*;
 
 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,6 +124,7 @@ 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)>,
@@ -462,6 +464,7 @@ fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHas
 }
 
 #[rustc_diagnostic_item = "Ty"]
+#[cfg_attr(not(bootstrap), rustc_pass_by_value)]
 pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 
 impl ty::EarlyBoundRegion {
@@ -481,7 +484,7 @@ pub fn has_name(&self) -> bool {
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(PredicateInner<'_>, 48);
+static_assert_size!(PredicateInner<'_>, 56);
 
 #[derive(Clone, Copy, Lift)]
 pub struct Predicate<'tcx> {
@@ -792,6 +795,31 @@ pub struct CoercePredicate<'tcx> {
 }
 pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(HashStable, TypeFoldable)]
+pub enum Term<'tcx> {
+    Ty(Ty<'tcx>),
+    Const(&'tcx Const<'tcx>),
+}
+
+impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
+    fn from(ty: Ty<'tcx>) -> Self {
+        Term::Ty(ty)
+    }
+}
+
+impl<'tcx> From<&'tcx Const<'tcx>> for Term<'tcx> {
+    fn from(c: &'tcx Const<'tcx>) -> Self {
+        Term::Const(c)
+    }
+}
+
+impl<'tcx> Term<'tcx> {
+    pub fn ty(&self) -> Option<Ty<'tcx>> {
+        if let Term::Ty(ty) = self { Some(ty) } else { None }
+    }
+}
+
 /// This kind of predicate has no *direct* correspondent in the
 /// syntax, but it roughly corresponds to the syntactic forms:
 ///
@@ -808,7 +836,7 @@ pub struct CoercePredicate<'tcx> {
 #[derive(HashStable, TypeFoldable)]
 pub struct ProjectionPredicate<'tcx> {
     pub projection_ty: ProjectionTy<'tcx>,
-    pub ty: Ty<'tcx>,
+    pub term: Term<'tcx>,
 }
 
 pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
@@ -833,8 +861,8 @@ pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
         self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
     }
 
-    pub fn ty(&self) -> Binder<'tcx, Ty<'tcx>> {
-        self.map_bound(|predicate| predicate.ty)
+    pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
+        self.map_bound(|predicate| predicate.term)
     }
 
     /// The `DefId` of the `TraitItem` for the associated type.
@@ -1415,7 +1443,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 +1530,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 +1559,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 +1571,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 +1588,7 @@ pub fn new(
         VariantDef {
             def_id: variant_did.unwrap_or(parent_did),
             ctor_def_id,
-            ident,
+            name,
             discr,
             fields,
             ctor_kind,
@@ -1580,6 +1607,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 +1630,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 +1805,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 +1926,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 +2108,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 +2155,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 c6454f3e0d02ae836fb1aa2ed15404386c51f92d..bbdaf248a9e7216a3c994c7debbab5cc1ee8b129 100644 (file)
@@ -1,6 +1,6 @@
 use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
-use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable};
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sso::SsoHashSet;
@@ -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
@@ -801,7 +799,7 @@ fn pretty_print_opaque_impl_type(
                     let trait_ref = proj_ref.required_poly_trait_ref(self.tcx());
 
                     // Projection type entry -- the def-id for naming, and the ty.
-                    let proj_ty = (proj_ref.projection_def_id(), proj_ref.ty());
+                    let proj_ty = (proj_ref.projection_def_id(), proj_ref.term());
 
                     self.insert_trait_and_projection(
                         trait_ref,
@@ -852,8 +850,10 @@ fn pretty_print_opaque_impl_type(
                     }
 
                     p!(")");
-                    if !return_ty.skip_binder().is_unit() {
-                        p!("-> ", print(return_ty));
+                    if let Term::Ty(ty) = return_ty.skip_binder() {
+                        if !ty.is_unit() {
+                            p!("-> ", print(return_ty));
+                        }
                     }
                     p!(write("{}", if paren_needed { ")" } else { "" }));
 
@@ -904,23 +904,28 @@ fn pretty_print_opaque_impl_type(
                     first = false;
                 }
 
-                for (assoc_item_def_id, ty) in assoc_items {
+                for (assoc_item_def_id, term) in assoc_items {
                     if !first {
                         p!(", ");
                     }
                     p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
 
-                    // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
-                    match ty.skip_binder().kind() {
-                        ty::Projection(ty::ProjectionTy { item_def_id, .. })
-                            if Some(*item_def_id) == self.tcx().lang_items().generator_return() =>
-                        {
-                            p!("[async output]")
+                    match term.skip_binder() {
+                        Term::Ty(ty) => {
+                            // Skip printing `<[generator@] as Generator<_>>::Return` from async blocks
+                            if matches!(
+                              ty.kind(), ty::Projection(ty::ProjectionTy { item_def_id, .. })
+                              if Some(*item_def_id) == self.tcx().lang_items().generator_return()
+                            ) {
+                                p!("[async output]")
+                            } else {
+                                p!(print(ty))
+                            }
                         }
-                        _ => {
-                            p!(print(ty))
+                        Term::Const(c) => {
+                            p!(print(c));
                         }
-                    }
+                    };
 
                     first = false;
                 }
@@ -945,8 +950,11 @@ fn pretty_print_opaque_impl_type(
     fn insert_trait_and_projection(
         &mut self,
         trait_ref: ty::PolyTraitRef<'tcx>,
-        proj_ty: Option<(DefId, ty::Binder<'tcx, Ty<'tcx>>)>,
-        traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, BTreeMap<DefId, ty::Binder<'tcx, Ty<'tcx>>>>,
+        proj_ty: Option<(DefId, ty::Binder<'tcx, Term<'tcx>>)>,
+        traits: &mut BTreeMap<
+            ty::PolyTraitRef<'tcx>,
+            BTreeMap<DefId, ty::Binder<'tcx, Term<'tcx>>>,
+        >,
         fn_traits: &mut BTreeMap<ty::PolyTraitRef<'tcx>, OpaqueFnEntry<'tcx>>,
     ) {
         let trait_def_id = trait_ref.def_id();
@@ -1021,7 +1029,11 @@ fn pretty_print_dyn_existential(
                         let mut projections = predicates.projection_bounds();
                         if let (Some(proj), None) = (projections.next(), projections.next()) {
                             let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect();
-                            p!(pretty_fn_sig(&tys, false, proj.skip_binder().ty));
+                            p!(pretty_fn_sig(
+                                &tys,
+                                false,
+                                proj.skip_binder().term.ty().expect("Return type was a const")
+                            ));
                             resugared = true;
                         }
                     }
@@ -1153,28 +1165,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 +1432,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 +1440,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 +1486,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 +1795,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 +2258,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 +2265,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 +2295,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(),
         };
@@ -2450,7 +2456,7 @@ pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPat
 
     ty::ExistentialProjection<'tcx> {
         let name = cx.tcx().associated_item(self.item_def_id).ident;
-        p!(write("{} = ", name), print(self.ty))
+        p!(write("{} = ", name), print(self.term))
     }
 
     ty::ExistentialPredicate<'tcx> {
@@ -2507,7 +2513,14 @@ pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPat
     }
 
     ty::ProjectionPredicate<'tcx> {
-        p!(print(self.projection_ty), " == ", print(self.ty))
+        p!(print(self.projection_ty), " == ", print(self.term))
+    }
+
+    ty::Term<'tcx> {
+      match self {
+        ty::Term::Ty(ty) => p!(print(ty)),
+        ty::Term::Const(c) => p!(print(c)),
+      }
     }
 
     ty::ProjectionTy<'tcx> {
@@ -2547,7 +2560,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), "`")
@@ -2717,5 +2730,5 @@ pub struct OpaqueFnEntry<'tcx> {
     has_fn_once: bool,
     fn_mut_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
     fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
-    return_ty: Option<ty::Binder<'tcx, Ty<'tcx>>>,
+    return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
 }
index 63ed318cadb890932a851bcec4bb75a7966e3a65..bb040acd2703d6e91db73855a38224eaa14b6eef 100644 (file)
@@ -7,7 +7,7 @@
 use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
 use crate::ty::error::{ExpectedFound, TypeError};
 use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
-use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
+use crate::ty::{self, Term, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as ast;
 use rustc_hir::def_id::DefId;
 use rustc_span::DUMMY_SP;
@@ -291,11 +291,11 @@ fn relate<R: TypeRelation<'tcx>>(
                 b.item_def_id,
             )))
         } else {
-            let ty = relation.relate_with_variance(
+            let term = relation.relate_with_variance(
                 ty::Invariant,
                 ty::VarianceDiagInfo::default(),
-                a.ty,
-                b.ty,
+                a.term,
+                b.term,
             )?;
             let substs = relation.relate_with_variance(
                 ty::Invariant,
@@ -303,7 +303,7 @@ fn relate<R: TypeRelation<'tcx>>(
                 a.substs,
                 b.substs,
             )?;
-            Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, ty })
+            Ok(ty::ExistentialProjection { item_def_id: a.item_def_id, substs, term })
         }
     }
 }
@@ -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,
@@ -833,6 +833,20 @@ fn relate<R: TypeRelation<'tcx>>(
     }
 }
 
+impl<'tcx> Relate<'tcx> for ty::Term<'tcx> {
+    fn relate<R: TypeRelation<'tcx>>(
+        relation: &mut R,
+        a: Self,
+        b: Self,
+    ) -> RelateResult<'tcx, Self> {
+        Ok(match (a, b) {
+            (Term::Ty(a), Term::Ty(b)) => relation.relate(a, b)?.into(),
+            (Term::Const(a), Term::Const(b)) => relation.relate(a, b)?.into(),
+            _ => return Err(TypeError::Mismatch),
+        })
+    }
+}
+
 impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
@@ -841,7 +855,7 @@ fn relate<R: TypeRelation<'tcx>>(
     ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> {
         Ok(ty::ProjectionPredicate {
             projection_ty: relation.relate(a.projection_ty, b.projection_ty)?,
-            ty: relation.relate(a.ty, b.ty)?,
+            term: relation.relate(a.term, b.term)?.into(),
         })
     }
 }
index 98b1a8b4d7631f84d22f8b5863280c456a314a51..1c5bc7860db2de7280f0446399e3f3ec796fa051 100644 (file)
@@ -6,7 +6,7 @@
 use crate::mir::ProjectionKind;
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
-use crate::ty::{self, InferConst, Lift, Ty, TyCtxt};
+use crate::ty::{self, InferConst, Lift, Term, Ty, TyCtxt};
 use rustc_data_structures::functor::IdFunctor;
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::CRATE_DEF_INDEX;
@@ -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))
@@ -164,7 +158,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.ty)
+        write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.term)
     }
 }
 
@@ -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) => {
@@ -225,7 +219,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     ::rustc_hir::def_id::DefId,
     ::rustc_hir::def_id::LocalDefId,
     ::rustc_hir::HirId,
-    ::rustc_hir::LlvmInlineAsmInner,
     ::rustc_hir::MatchSource,
     ::rustc_hir::Mutability,
     ::rustc_hir::Unsafety,
@@ -363,6 +356,16 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
     }
 }
 
+impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
+    type Lifted = ty::Term<'tcx>;
+    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
+        Some(match self {
+            Term::Ty(ty) => Term::Ty(tcx.lift(ty)?),
+            Term::Const(c) => Term::Const(tcx.lift(c)?),
+        })
+    }
+}
+
 impl<'a, 'tcx> Lift<'tcx> for ty::TraitPredicate<'a> {
     type Lifted = ty::TraitPredicate<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::TraitPredicate<'tcx>> {
@@ -410,8 +413,8 @@ fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionTy<'tcx>> {
 impl<'a, 'tcx> Lift<'tcx> for ty::ProjectionPredicate<'a> {
     type Lifted = ty::ProjectionPredicate<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ty::ProjectionPredicate<'tcx>> {
-        tcx.lift((self.projection_ty, self.ty))
-            .map(|(projection_ty, ty)| ty::ProjectionPredicate { projection_ty, ty })
+        tcx.lift((self.projection_ty, self.term))
+            .map(|(projection_ty, term)| ty::ProjectionPredicate { projection_ty, term })
     }
 }
 
@@ -420,7 +423,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ExistentialProjection<'a> {
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         tcx.lift(self.substs).map(|substs| ty::ExistentialProjection {
             substs,
-            ty: tcx.lift(self.ty).expect("type must lift when substs do"),
+            term: tcx.lift(self.term).expect("type must lift when substs do"),
             item_def_id: self.item_def_id,
         })
     }
@@ -1232,7 +1235,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 +1245,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 +1256,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 +1266,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..20db25f7899ddc3082062efc1b1a6f145d8633cb 100644 (file)
@@ -8,7 +8,7 @@
 use crate::ty::fold::ValidateBoundVars;
 use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
 use crate::ty::InferTy::{self, *};
-use crate::ty::{self, AdtDef, DefIdTree, Discr, Ty, TyCtxt, TypeFlags, TypeFoldable};
+use crate::ty::{self, AdtDef, DefIdTree, Discr, Term, Ty, TyCtxt, TypeFlags, TypeFoldable};
 use crate::ty::{DelaySpanBugEmitted, List, ParamEnv, TyS};
 use polonius_engine::Atom;
 use rustc_data_structures::captures::Captures;
@@ -1540,7 +1540,7 @@ fn from(var: BoundVar) -> Self {
 pub struct ExistentialProjection<'tcx> {
     pub item_def_id: DefId,
     pub substs: SubstsRef<'tcx>,
-    pub ty: Ty<'tcx>,
+    pub term: Term<'tcx>,
 }
 
 pub type PolyExistentialProjection<'tcx> = Binder<'tcx, ExistentialProjection<'tcx>>;
@@ -1570,7 +1570,7 @@ pub fn with_self_ty(
                 item_def_id: self.item_def_id,
                 substs: tcx.mk_substs_trait(self_ty, self.substs),
             },
-            ty: self.ty,
+            term: self.term,
         }
     }
 
@@ -1584,7 +1584,7 @@ pub fn erase_self_ty(
         Self {
             item_def_id: projection_predicate.projection_ty.item_def_id,
             substs: tcx.intern_substs(&projection_predicate.projection_ty.substs[1..]),
-            ty: projection_predicate.ty,
+            term: projection_predicate.term,
         }
     }
 }
@@ -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..63e9b58584c5f3f1c60ca399f6aac5de055bb830 100644 (file)
@@ -275,10 +275,6 @@ pub fn fill_single<F>(
         }
     }
 
-    pub fn is_noop(&self) -> bool {
-        self.is_empty()
-    }
-
     #[inline]
     pub fn types(&'a self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'a {
         self.iter()
@@ -505,7 +501,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 34d059f4ec849c28625f05730bf0cf5fb56891d4..9f8053d4a4eac7893c57dc9743f402638732c0c1 100644 (file)
@@ -1,7 +1,7 @@
 use crate::traits::specialization_graph;
 use crate::ty::fast_reject::{self, SimplifiedType, SimplifyParams, StripReferences};
 use crate::ty::fold::TypeFoldable;
-use crate::ty::{Ty, TyCtxt};
+use crate::ty::{Ident, Ty, TyCtxt};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::definitions::DefPathHash;
@@ -44,6 +44,10 @@ pub struct TraitDef {
     /// The ICH of this trait's DefPath, cached here so it doesn't have to be
     /// recomputed all the time.
     pub def_path_hash: DefPathHash,
+
+    /// List of functions from `#[rustc_must_implement_one_of]` attribute one of which
+    /// must be implemented.
+    pub must_implement_one_of: Option<Box<[Ident]>>,
 }
 
 /// Whether this trait is treated specially by the standard library
@@ -87,6 +91,7 @@ pub fn new(
         skip_array_during_method_dispatch: bool,
         specialization_kind: TraitSpecializationKind,
         def_path_hash: DefPathHash,
+        must_implement_one_of: Option<Box<[Ident]>>,
     ) -> TraitDef {
         TraitDef {
             def_id,
@@ -97,6 +102,7 @@ pub fn new(
             skip_array_during_method_dispatch,
             specialization_kind,
             def_path_hash,
+            must_implement_one_of,
         }
     }
 
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..38aa76333851f76007966ce0738f9aa323942ca4 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
@@ -172,7 +157,7 @@ fn push_inner<'tcx>(
                 stack.extend(obj.iter().rev().flat_map(|predicate| {
                     let (substs, opt_ty) = match predicate.skip_binder() {
                         ty::ExistentialPredicate::Trait(tr) => (tr.substs, None),
-                        ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.ty)),
+                        ty::ExistentialPredicate::Projection(p) => (p.substs, Some(p.term)),
                         ty::ExistentialPredicate::AutoTrait(_) =>
                         // Empty iterator
                         {
@@ -180,7 +165,10 @@ fn push_inner<'tcx>(
                         }
                     };
 
-                    substs.iter().rev().chain(opt_ty.map(|ty| ty.into()))
+                    substs.iter().rev().chain(opt_ty.map(|term| match term {
+                        ty::Term::Ty(ty) => ty.into(),
+                        ty::Term::Const(ct) => ct.into(),
+                    }))
                 }));
             }
             ty::Adt(_, substs)
@@ -211,11 +199,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..1e94c41d88daa01b4816a106b9199e3c1c80b1cb 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 {
@@ -573,7 +569,6 @@ fn expr_as_place(
             | ExprKind::ConstBlock { .. }
             | ExprKind::StaticRef { .. }
             | ExprKind::InlineAsm { .. }
-            | ExprKind::LlvmInlineAsm { .. }
             | ExprKind::Yield { .. }
             | ExprKind::ThreadLocalRef(_)
             | ExprKind::Call { .. } => {
index 9a86d465f98ca7a277d691a3ea5e0b2cb08bde1a..1dc49256a6a9f6430039a43211e94f14a8c70572 100644 (file)
@@ -350,7 +350,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             | ExprKind::Continue { .. }
             | ExprKind::Return { .. }
             | ExprKind::InlineAsm { .. }
-            | ExprKind::LlvmInlineAsm { .. }
             | ExprKind::PlaceTypeAscription { .. }
             | ExprKind::ValueTypeAscription { .. } => {
                 // these do not have corresponding `Rvalue` variants,
index fcda52e558126155cdabf09d2d83a2cccc1305de..d31f6ed93840ad08deb23604ceb72a6f91d2c915 100644 (file)
@@ -67,8 +67,7 @@ impl Category {
             | ExprKind::Repeat { .. }
             | ExprKind::Assign { .. }
             | ExprKind::AssignOp { .. }
-            | ExprKind::ThreadLocalRef(_)
-            | ExprKind::LlvmInlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
+            | ExprKind::ThreadLocalRef(_) => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
 
             ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => {
                 Some(Category::Constant)
index d9896ff5ac93ecd9c910e1ca792541c3a834b7fd..da8fbdbf3bce4b2e72434a639a5d03b5a377ff13 100644 (file)
@@ -90,17 +90,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 };
 
                 let join_block = this.cfg.start_new_block();
-                this.cfg.terminate(
-                    then_blk,
-                    source_info,
-                    TerminatorKind::Goto { target: join_block },
-                );
-                this.cfg.terminate(
-                    else_blk,
-                    source_info,
-                    TerminatorKind::Goto { target: join_block },
-                );
-
+                this.cfg.goto(then_blk, source_info, join_block);
+                this.cfg.goto(else_blk, source_info, join_block);
                 join_block.unit()
             }
             ExprKind::Let { expr, ref pat } => {
@@ -109,8 +100,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     this.lower_let_expr(block, &this.thir[expr], pat, scope, expr_span)
                 });
 
-                let join_block = this.cfg.start_new_block();
-
                 this.cfg.push_assign_constant(
                     true_block,
                     source_info,
@@ -133,6 +122,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     },
                 );
 
+                let join_block = this.cfg.start_new_block();
                 this.cfg.goto(true_block, source_info, join_block);
                 this.cfg.goto(false_block, source_info, join_block);
                 join_block.unit()
@@ -477,9 +467,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
 
             // These cases don't actually need a destination
-            ExprKind::Assign { .. }
-            | ExprKind::AssignOp { .. }
-            | ExprKind::LlvmInlineAsm { .. } => {
+            ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
                 unpack!(block = this.stmt_expr(block, expr, None));
                 this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
                 block.unit()
index 4245535450a27490e5de6fdaab206435b732ae3a..7419c5b2f7588e56a556db5ad4fcc3efbd386517 100644 (file)
@@ -101,38 +101,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 BreakableTarget::Return,
                 source_info,
             ),
-            ExprKind::LlvmInlineAsm { asm, ref outputs, ref inputs } => {
-                debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr);
-                this.block_context.push(BlockFrame::SubExpr);
-                let outputs = outputs
-                    .into_iter()
-                    .copied()
-                    .map(|output| unpack!(block = this.as_place(block, &this.thir[output])))
-                    .collect::<Vec<_>>()
-                    .into_boxed_slice();
-                let inputs = inputs
-                    .into_iter()
-                    .copied()
-                    .map(|input| {
-                        let input = &this.thir[input];
-                        (input.span, unpack!(block = this.as_local_operand(block, &input)))
-                    })
-                    .collect::<Vec<_>>()
-                    .into_boxed_slice();
-                this.cfg.push(
-                    block,
-                    Statement {
-                        source_info,
-                        kind: StatementKind::LlvmInlineAsm(Box::new(LlvmInlineAsm {
-                            asm: asm.clone(),
-                            outputs,
-                            inputs,
-                        })),
-                    },
-                );
-                this.block_context.pop();
-                block.unit()
-            }
             _ => {
                 assert!(
                     statement_scope.is_some(),
index e3a05e01ea8f089a0750aa4498fb04d439d50df2..85950d82419408d1cb2ed7c387f8c2d8bdd2f3fc 100644 (file)
@@ -47,6 +47,25 @@ pub(crate) fn then_else_break(
         let expr_span = expr.span;
 
         match expr.kind {
+            ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => {
+                let lhs_then_block = unpack!(this.then_else_break(
+                    block,
+                    &this.thir[lhs],
+                    temp_scope_override,
+                    break_scope,
+                    variable_scope_span,
+                ));
+
+                let rhs_then_block = unpack!(this.then_else_break(
+                    lhs_then_block,
+                    &this.thir[rhs],
+                    temp_scope_override,
+                    break_scope,
+                    variable_scope_span,
+                ));
+
+                rhs_then_block.unit()
+            }
             ExprKind::Scope { region_scope, lint_level, value } => {
                 let region_scope = (region_scope, this.source_info(expr_span));
                 this.in_scope(region_scope, lint_level, |this| {
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 fc46c54c2fc35033769aa4b7d577c4b123acad45..84d6c1d2db87f1c3834a2cafb9b5d121af446d97 100644 (file)
@@ -498,7 +498,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ///
     /// if let Some(x) = a && let Some(y) = b && let Some(z) = c { ... }
     ///
-    /// there are three possible ways the condition can be false and we may have
+    /// There are three possible ways the condition can be false and we may have
     /// to drop `x`, `x` and `y`, or neither depending on which binding fails.
     /// To handle this correctly we use a `DropTree` in a similar way to a
     /// `loop` expression and 'break' out on all of the 'else' paths.
index 7940bd1f33dc1bb35eacf2459708a02195c6d657..8ca2449cea9c47d12ab4d8bd82bca5ef2f0c8338 100644 (file)
@@ -329,7 +329,6 @@ fn visit_expr(&mut self, expr: &Expr<'tcx>) {
             | ExprKind::Box { .. }
             | ExprKind::If { .. }
             | ExprKind::InlineAsm { .. }
-            | ExprKind::LlvmInlineAsm { .. }
             | ExprKind::LogicalOp { .. }
             | ExprKind::Use { .. } => {
                 // We don't need to save the old value and restore it
@@ -377,7 +376,7 @@ fn visit_expr(&mut self, expr: &Expr<'tcx>) {
                     self.requires_unsafe(expr.span, DerefOfRawPointer);
                 }
             }
-            ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => {
+            ExprKind::InlineAsm { .. } => {
                 self.requires_unsafe(expr.span, UseOfInlineAssembly);
             }
             ExprKind::Adt(box Adt {
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 bdde6b4a356c195206cb146b006d1df6946aa919..a43388808cd5ce2c3664b5ea6377304f43c2cf73 100644 (file)
@@ -315,7 +315,6 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                             lhs: self.mirror_expr(lhs),
                             rhs: self.mirror_expr(rhs),
                         },
-
                         _ => {
                             let op = bin_op(op.node);
                             ExprKind::Binary {
@@ -570,12 +569,6 @@ fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx>
                 line_spans: asm.line_spans,
             },
 
-            hir::ExprKind::LlvmInlineAsm(ref asm) => ExprKind::LlvmInlineAsm {
-                asm: &asm.inner,
-                outputs: self.mirror_exprs(asm.outputs_exprs),
-                inputs: self.mirror_exprs(asm.inputs_exprs),
-            },
-
             hir::ExprKind::ConstBlock(ref anon_const) => {
                 let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
                 let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
@@ -1108,9 +1101,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..34204c3852ad0842e839fa1bb21368019ecaa780 100644 (file)
 use rustc_hir as hir;
 use rustc_hir::def::*;
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, Pat};
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
 use rustc_session::lint::builtin::{
     BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
 };
 use rustc_session::Session;
+use rustc_span::source_map::Spanned;
 use rustc_span::{DesugaringKind, ExpnKind, Span};
 
 crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
@@ -54,12 +55,6 @@ struct MatchVisitor<'a, 'p, 'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, '_, 'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
         intravisit::walk_expr(self, ex);
         match &ex.kind {
@@ -327,7 +322,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();
@@ -451,6 +446,10 @@ fn check_let_reachability<'p, 'tcx>(
     pat: &'p DeconstructedPat<'p, 'tcx>,
     span: Span,
 ) {
+    if is_let_chain(cx.tcx, pat_id) {
+        return;
+    }
+
     let arms = [MatchArm { pat, hir_id: pat_id, has_guard: false }];
     let report = compute_match_usefulness(&cx, &arms, pat_id, pat.ty());
 
@@ -627,7 +626,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.
@@ -770,8 +769,11 @@ pub enum LetSource {
 
 fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
     let hir = tcx.hir();
+
     let parent = hir.get_parent_node(pat_id);
-    match hir.get(parent) {
+    let parent_node = hir.get(parent);
+
+    match parent_node {
         hir::Node::Arm(hir::Arm {
             guard: Some(hir::Guard::IfLet(&hir::Pat { hir_id, .. }, _)),
             ..
@@ -786,6 +788,7 @@ fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
         }
         _ => {}
     }
+
     let parent_parent = hir.get_parent_node(parent);
     let parent_parent_node = hir.get(parent_parent);
 
@@ -798,12 +801,30 @@ fn let_source(tcx: TyCtxt<'_>, pat_id: HirId) -> LetSource {
         ..
     }) = parent_parent_parent_parent_node
     {
-        LetSource::WhileLet
-    } else if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If { .. }, .. }) =
-        parent_parent_node
-    {
-        LetSource::IfLet
-    } else {
-        LetSource::GenericLet
+        return LetSource::WhileLet;
     }
+
+    if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::If(..), .. }) = parent_parent_node {
+        return LetSource::IfLet;
+    }
+
+    LetSource::GenericLet
+}
+
+// Since this function is called within a let context, it is reasonable to assume that any parent
+// `&&` infers a let chain
+fn is_let_chain(tcx: TyCtxt<'_>, pat_id: HirId) -> bool {
+    let hir = tcx.hir();
+    let parent = hir.get_parent_node(pat_id);
+    let parent_parent = hir.get_parent_node(parent);
+    matches!(
+        hir.get(parent_parent),
+        hir::Node::Expr(
+            hir::Expr {
+                kind: hir::ExprKind::Binary(Spanned { node: hir::BinOpKind::And, .. }, ..),
+                ..
+            },
+            ..
+        )
+    )
 }
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 65c388f8124a3cd25d6801c959aec590c572d9af..4871320fdb5c08e11e1cbae159cb00407eaab561 100644 (file)
@@ -176,7 +176,6 @@ fn for_place(context: PlaceContext) -> Option<DefUse> {
             // All other contexts are uses...
             PlaceContext::MutatingUse(
                 MutatingUseContext::AddressOf
-                | MutatingUseContext::LlvmAsmOutput
                 | MutatingUseContext::Borrow
                 | MutatingUseContext::Drop
                 | MutatingUseContext::Retag,
index 896377f2bc30714064280ef855b130117f7c44b5..60cde6546dcfc62d2a7c0e5be2fa7e999d463869 100644 (file)
@@ -134,11 +134,6 @@ fn before_statement_effect(
             | StatementKind::SetDiscriminant { box place, .. } => {
                 trans.gen(place.local);
             }
-            StatementKind::LlvmInlineAsm(asm) => {
-                for place in &*asm.outputs {
-                    trans.gen(place.local);
-                }
-            }
 
             // Nothing to do for these. Match exhaustively so this fails to compile when new
             // variants are added.
index 2e00b4f9a5e7cbb4ba1ad3a7e3d122963d9c99c1..26bbc34e780bb03a5545706f6f1bc6ddaba3a9f3 100644 (file)
@@ -4,7 +4,6 @@
 use rustc_middle::ty::{self, TyCtxt};
 use smallvec::{smallvec, SmallVec};
 
-use std::iter;
 use std::mem;
 
 use super::abs_domain::Lift;
@@ -293,16 +292,6 @@ fn gather_statement(&mut self, stmt: &Statement<'tcx>) {
             StatementKind::FakeRead(box (_, place)) => {
                 self.create_move_path(*place);
             }
-            StatementKind::LlvmInlineAsm(ref asm) => {
-                for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
-                    if !kind.is_indirect {
-                        self.gather_init(output.as_ref(), InitKind::Deep);
-                    }
-                }
-                for (_, input) in asm.inputs.iter() {
-                    self.gather_operand(input);
-                }
-            }
             StatementKind::StorageLive(_) => {}
             StatementKind::StorageDead(local) => {
                 self.gather_move(Place::from(*local));
index a40c4d1c3662b302c152d88490e26b03bca9553f..fd93744d400919749b66793bb8774e0a9ee07c25 100644 (file)
@@ -104,10 +104,6 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 // safe (at least as emitted during MIR construction)
             }
 
-            StatementKind::LlvmInlineAsm { .. } => self.require_unsafe(
-                UnsafetyViolationKind::General,
-                UnsafetyViolationDetails::UseOfInlineAssembly,
-            ),
             StatementKind::CopyNonOverlapping(..) => unreachable!(),
         }
         self.super_statement(statement, location);
@@ -208,7 +204,6 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
                             MutatingUseContext::Store
                                 | MutatingUseContext::Drop
                                 | MutatingUseContext::AsmOutput
-                                | MutatingUseContext::LlvmAsmOutput
                         )
                     );
                 // If this is just an assignment, determine if the assigned type needs dropping.
@@ -398,12 +393,6 @@ struct UnusedUnsafeVisitor<'a> {
 }
 
 impl<'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'_> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::None
-    }
-
     fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
         intravisit::walk_block(self, block);
 
index e3ff6ad45490d4074f420a721ffc9fb95b8a1b7a..98de64cd97c9c49140d806f213359ce64bcb4063 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(),
@@ -475,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;
         }
 
@@ -490,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
@@ -728,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;
         }
 
@@ -1035,8 +1032,7 @@ fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
 
             // These could be propagated with a smarter analysis or just some careful thinking about
             // whether they'd be fine right now.
-            MutatingUse(MutatingUseContext::LlvmAsmOutput)
-            | MutatingUse(MutatingUseContext::Yield)
+            MutatingUse(MutatingUseContext::Yield)
             | MutatingUse(MutatingUseContext::Drop)
             | MutatingUse(MutatingUseContext::Retag)
             // These can't ever be propagated under any scheme, as we can't reason about indirect
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 b5356a817f7ac5e25dc8c7d05268450172c9334f..a9161580bc68185ac0b268c1474dd44ef34477db 100644 (file)
@@ -835,7 +835,6 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
         | StatementKind::CopyNonOverlapping(..)
         | StatementKind::Assign(_)
         | StatementKind::SetDiscriminant { .. }
-        | StatementKind::LlvmInlineAsm(_)
         | StatementKind::Retag(_, _)
         | StatementKind::AscribeUserType(_, _) => {
             Some(statement.source_info.span)
index 2b382468be0f5d01c00fa61a740b60683063947a..d469be746414414175e81a914b086d3d32fa383d 100644 (file)
@@ -534,25 +534,6 @@ fn record_statement_conflicts(&mut self, stmt: &Statement<'_>) {
             // eliminate the resulting self-assignments automatically.
             StatementKind::Assign(_) => {}
 
-            StatementKind::LlvmInlineAsm(asm) => {
-                // Inputs and outputs must not overlap.
-                for (_, input) in &*asm.inputs {
-                    if let Some(in_place) = input.place() {
-                        if !in_place.is_indirect() {
-                            for out_place in &*asm.outputs {
-                                if !out_place.is_indirect() && !in_place.is_indirect() {
-                                    self.record_local_conflict(
-                                        in_place.local,
-                                        out_place.local,
-                                        "aliasing llvm_asm! operands",
-                                    );
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-
             StatementKind::SetDiscriminant { .. }
             | StatementKind::StorageLive(..)
             | StatementKind::StorageDead(..)
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..433a1c6ad67cc2694dd6c2d636555d537e7b7ffc 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 {
@@ -1447,9 +1449,6 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
                 self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location));
             }
 
-            // FIXME: Does `llvm_asm!` have any aliasing requirements?
-            StatementKind::LlvmInlineAsm(_) => {}
-
             StatementKind::FakeRead(..)
             | StatementKind::SetDiscriminant { .. }
             | StatementKind::StorageLive(_)
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..bf6f13fa67b58e10e7f9fc5db8ed090b4087679c 100644 (file)
@@ -22,7 +22,7 @@
 use rustc_data_structures::steal::Steal;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_index::vec::IndexVec;
 use rustc_middle::mir::visit::Visitor as _;
 use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
@@ -162,10 +162,6 @@ fn visit_variant_data(
             }
             intravisit::walk_struct_def(self, v)
         }
-        type Map = intravisit::ErasedMap<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
     }
     tcx.hir().visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor());
 
@@ -342,7 +338,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 +362,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 +525,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 +552,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 2a73e341f1653f77984b618e1d6e05501a1b7ee5..77fb092d5806f31c95a10be67d9bae9be2b08cee 100644 (file)
@@ -50,7 +50,6 @@ fn is_nop_landing_pad(
 
                 StatementKind::Assign { .. }
                 | StatementKind::SetDiscriminant { .. }
-                | StatementKind::LlvmInlineAsm { .. }
                 | StatementKind::CopyNonOverlapping(..)
                 | StatementKind::Retag { .. } => {
                     return false;
index 612fce71f9167a1bf88df39dc130c0fdf6ceaf30..d265720e18296bfad3ff6469aa7e406a3c6cf8bb 100644 (file)
@@ -239,10 +239,6 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
                 }
             }
 
-            // If inline assembly is found, we probably should
-            // not try to analyze the code
-            StatementKind::LlvmInlineAsm(_) => return false,
-
             // These statements have no influence on the place
             // we are interested in
             StatementKind::FakeRead(_)
@@ -320,10 +316,6 @@ fn find_determining_place<'tcx>(
             | StatementKind::CopyNonOverlapping(_)
             | StatementKind::Nop => {}
 
-            // If inline assembly is found, we probably should
-            // not try to analyze the code
-            StatementKind::LlvmInlineAsm(_) => return None,
-
             // If the discriminant is set, it is always set
             // as a constant, so the job is already done.
             // As we are **ignoring projections**, if the place
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 7992124bacd43d924c7252578a435bf510d94bac..7e0c8e233e9e8cfd94efa213717d79e860f08261 100644 (file)
@@ -483,8 +483,7 @@ fn visit_lhs(&mut self, place: &Place<'_>, location: Location) {
 impl<'tcx> Visitor<'tcx> for UsedLocals {
     fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
         match statement.kind {
-            StatementKind::LlvmInlineAsm(..)
-            | StatementKind::CopyNonOverlapping(..)
+            StatementKind::CopyNonOverlapping(..)
             | StatementKind::Retag(..)
             | StatementKind::Coverage(..)
             | StatementKind::FakeRead(..)
index 7761d4006d3dbd06f4cea316e70ef823360603e9..d5507fcc78cad8016befb447a1bad1c52fa23e39 100644 (file)
@@ -631,10 +631,6 @@ fn find(&self) -> Vec<SimplifyBranchSameOptimization> {
                     .filter(|(_, bb)| {
                         // Reaching `unreachable` is UB so assume it doesn't happen.
                         bb.terminator().kind != TerminatorKind::Unreachable
-                    // But `asm!(...)` could abort the program,
-                    // so we cannot assume that the `unreachable` terminator itself is reachable.
-                    // FIXME(Centril): use a normalization pass instead of a check.
-                    || bb.statements.iter().any(|stmt| matches!(stmt.kind, StatementKind::LlvmInlineAsm(..)))
                     })
                     .peekable();
 
index 77bc209539b34133a3aaff29739ae22dce4bc276..cda9ba9dcc87ff5c982382777bcfbd6b47cb8416 100644 (file)
@@ -3,8 +3,7 @@
 use crate::MirPass;
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_middle::mir::{
-    BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets,
-    TerminatorKind,
+    BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, TerminatorKind,
 };
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{Ty, TyCtxt};
@@ -56,7 +55,10 @@ fn variant_discriminants<'tcx>(
     match &layout.variants {
         Variants::Single { index } => {
             let mut res = FxHashSet::default();
-            res.insert(index.as_u32() as u128);
+            res.insert(
+                ty.discriminant_for_variant(tcx, *index)
+                    .map_or(index.as_u32() as u128, |discr| discr.val),
+            );
             res
         }
         Variants::Multiple { variants, .. } => variants
@@ -75,16 +77,9 @@ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if body.source.promoted.is_some() {
-            return;
-        }
-
         trace!("UninhabitedEnumBranching starting for {:?}", body.source);
 
-        let basic_block_count = body.basic_blocks().len();
-
-        for bb in 0..basic_block_count {
-            let bb = BasicBlock::from_usize(bb);
+        for bb in body.basic_blocks().indices() {
             trace!("processing block {:?}", bb);
 
             let Some(discriminant_ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) else {
index 9e755ab141a489e5860075e21887648b93bce2a5..f916ca36217b4c0ff4c0ceb15d81cb8e97801b48 100644 (file)
@@ -23,23 +23,14 @@ fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 
         for (bb, bb_data) in traversal::postorder(body) {
             let terminator = bb_data.terminator();
-            // HACK: If the block contains any asm statement it is not regarded as unreachable.
-            // This is a temporary solution that handles possibly diverging asm statements.
-            // Accompanying testcases: mir-opt/unreachable_asm.rs and mir-opt/unreachable_asm_2.rs
-            let asm_stmt_in_block = || {
-                bb_data.statements.iter().any(|stmt: &Statement<'_>| {
-                    matches!(stmt.kind, StatementKind::LlvmInlineAsm(..))
-                })
-            };
-
-            if terminator.kind == TerminatorKind::Unreachable && !asm_stmt_in_block() {
+            if terminator.kind == TerminatorKind::Unreachable {
                 unreachable_blocks.insert(bb);
             } else {
                 let is_unreachable = |succ: BasicBlock| unreachable_blocks.contains(&succ);
                 let terminator_kind_opt = remove_successors(&terminator.kind, is_unreachable);
 
                 if let Some(terminator_kind) = terminator_kind_opt {
-                    if terminator_kind == TerminatorKind::Unreachable && !asm_stmt_in_block() {
+                    if terminator_kind == TerminatorKind::Unreachable {
                         unreachable_blocks.insert(bb);
                     }
                     replacements.insert(bb, terminator_kind);
index 3e06e7f36d419583a02dc03b48488dd8f7a92562..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,
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..c41f2d3299bf7dbcecf10c6219810edc47d6cc4a 100644 (file)
@@ -1,5 +1,5 @@
 use super::pat::Expected;
-use super::ty::AllowPlus;
+use super::ty::{AllowPlus, IsAsCast};
 use super::{
     BlockMode, Parser, PathStyle, RecoverColon, RecoverComma, Restrictions, SemiColonMode, SeqSep,
     TokenExpectType, TokenType,
@@ -27,7 +27,7 @@
 use tracing::{debug, trace};
 
 const TURBOFISH_SUGGESTION_STR: &str =
-    "use `::<...>` instead of `<...>` to specify type or const arguments";
+    "use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments";
 
 /// Creates a placeholder argument.
 pub(super) fn dummy_arg(ident: Ident) -> Param {
@@ -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
@@ -731,21 +731,28 @@ pub(super) fn check_mistyped_turbofish_with_multiple_type_params(
                     match x {
                         Ok((_, _, false)) => {
                             if self.eat(&token::Gt) {
-                                match self.parse_expr() {
-                                    Ok(_) => {
-                                        e.span_suggestion_verbose(
-                                            binop.span.shrink_to_lo(),
-                                            TURBOFISH_SUGGESTION_STR,
-                                            "::".to_string(),
-                                            Applicability::MaybeIncorrect,
-                                        );
-                                        e.emit();
-                                        *expr =
-                                            self.mk_expr_err(expr.span.to(self.prev_token.span));
-                                        return Ok(());
-                                    }
-                                    Err(mut err) => {
-                                        err.cancel();
+                                let turbo_err = e.span_suggestion_verbose(
+                                    binop.span.shrink_to_lo(),
+                                    TURBOFISH_SUGGESTION_STR,
+                                    "::".to_string(),
+                                    Applicability::MaybeIncorrect,
+                                );
+                                if self.check(&TokenKind::Semi) {
+                                    turbo_err.emit();
+                                    *expr = self.mk_expr_err(expr.span);
+                                    return Ok(());
+                                } else {
+                                    match self.parse_expr() {
+                                        Ok(_) => {
+                                            turbo_err.emit();
+                                            *expr = self
+                                                .mk_expr_err(expr.span.to(self.prev_token.span));
+                                            return Ok(());
+                                        }
+                                        Err(mut err) => {
+                                            turbo_err.cancel();
+                                            err.cancel();
+                                        }
                                     }
                                 }
                             }
@@ -1032,6 +1039,34 @@ pub(super) fn maybe_report_ambiguous_plus(
         }
     }
 
+    /// Swift lets users write `Ty?` to mean `Option<Ty>`. Parse the construct and recover from it.
+    pub(super) fn maybe_recover_from_question_mark(
+        &mut self,
+        ty: P<Ty>,
+        is_as_cast: IsAsCast,
+    ) -> P<Ty> {
+        if let IsAsCast::Yes = is_as_cast {
+            return ty;
+        }
+        if self.token == token::Question {
+            self.bump();
+            self.struct_span_err(self.prev_token.span, "invalid `?` in type")
+                .span_label(self.prev_token.span, "`?` is only allowed on expressions, not types")
+                .multipart_suggestion(
+                    "if you meant to express that the type might not contain a value, use the `Option` wrapper type",
+                    vec![
+                        (ty.span.shrink_to_lo(), "Option<".to_string()),
+                        (self.prev_token.span, ">".to_string()),
+                    ],
+                    Applicability::MachineApplicable,
+                )
+                .emit();
+            self.mk_ty(ty.span.to(self.prev_token.span), TyKind::Err)
+        } else {
+            ty
+        }
+    }
+
     pub(super) fn maybe_recover_from_bad_type_plus(
         &mut self,
         allow_plus: AllowPlus,
index f706a98a4fcfa76fa625eed83bad1f2556b19f61..192e87b4c01f7aea84b48ef09c3f454f8c44992f 100644 (file)
@@ -682,7 +682,7 @@ fn parse_assoc_op_cast(
         // Save the state of the parser before parsing type normally, in case there is a
         // LessThan comparison after this cast.
         let parser_snapshot_before_type = self.clone();
-        let cast_expr = match self.parse_ty_no_plus() {
+        let cast_expr = match self.parse_as_cast_ty() {
             Ok(rhs) => mk_expr(self, lhs, rhs),
             Err(mut type_err) => {
                 // Rewind to before attempting to parse the type with generics, to recover
@@ -808,7 +808,7 @@ fn parse_and_disallow_postfix_after_cast(
                 "casts cannot be followed by {}",
                 match with_postfix.kind {
                     ExprKind::Index(_, _) => "indexing",
-                    ExprKind::Try(_) => "?",
+                    ExprKind::Try(_) => "`?`",
                     ExprKind::Field(_, _) => "a field access",
                     ExprKind::MethodCall(_, _, _) => "a method call",
                     ExprKind::Call(_, _) => "a function call",
@@ -1443,7 +1443,7 @@ fn parse_labeled_expr(
         &mut self,
         label: Label,
         attrs: AttrVec,
-        consume_colon: bool,
+        mut consume_colon: bool,
     ) -> PResult<'a, P<Expr>> {
         let lo = label.ident.span;
         let label = Some(label);
@@ -1456,6 +1456,12 @@ fn parse_labeled_expr(
             self.parse_loop_expr(label, lo, attrs)
         } else if self.check(&token::OpenDelim(token::Brace)) || self.token.is_whole_block() {
             self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs)
+        } else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) {
+            // We're probably inside of a `Path<'a>` that needs a turbofish, so suppress the
+            // "must be followed by a colon" error.
+            self.diagnostic().delay_span_bug(lo, "this label wasn't parsed correctly");
+            consume_colon = false;
+            Ok(self.mk_expr_err(lo))
         } else {
             let msg = "expected `while`, `for`, `loop` or `{` after a label";
             self.struct_span_err(self.token.span, msg).span_label(self.token.span, msg).emit();
index 7f8fadb33bd8af58de28ee95c09865d98c17bc90..48502112e3a715420ace19a46ecd5c6aff154228 100644 (file)
@@ -4,8 +4,8 @@
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Token};
 use rustc_ast::{
-    self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocTyConstraint,
-    AssocTyConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
+    self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocConstraint,
+    AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
     Path, PathSegment, QSelf,
 };
 use rustc_errors::{pluralize, Applicability, PResult};
@@ -139,22 +139,46 @@ pub(super) fn parse_path_inner(
         style: PathStyle,
         ty_generics: Option<&Generics>,
     ) -> PResult<'a, Path> {
-        maybe_whole!(self, NtPath, |path| {
+        let reject_generics_if_mod_style = |parser: &Parser<'_>, path: &Path| {
+            // Ensure generic arguments don't end up in attribute paths, such as:
+            //
+            //     macro_rules! m {
+            //         ($p:path) => { #[$p] struct S; }
+            //     }
+            //
+            //     m!(inline<u8>); //~ ERROR: unexpected generic arguments in path
+            //
             if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
             {
-                self.struct_span_err(
-                    path.segments
-                        .iter()
-                        .filter_map(|segment| segment.args.as_ref())
-                        .map(|arg| arg.span())
-                        .collect::<Vec<_>>(),
-                    "unexpected generic arguments in path",
-                )
-                .emit();
+                parser
+                    .struct_span_err(
+                        path.segments
+                            .iter()
+                            .filter_map(|segment| segment.args.as_ref())
+                            .map(|arg| arg.span())
+                            .collect::<Vec<_>>(),
+                        "unexpected generic arguments in path",
+                    )
+                    .emit();
             }
+        };
+
+        maybe_whole!(self, NtPath, |path| {
+            reject_generics_if_mod_style(self, &path);
             path
         });
 
+        if let token::Interpolated(nt) = &self.token.kind {
+            if let token::NtTy(ty) = &**nt {
+                if let ast::TyKind::Path(None, path) = &ty.kind {
+                    let path = path.clone();
+                    self.bump();
+                    reject_generics_if_mod_style(self, &path);
+                    return Ok(path);
+                }
+            }
+        }
+
         let lo = self.token.span;
         let mut segments = Vec::new();
         let mod_sep_ctxt = self.token.span.ctxt();
@@ -469,12 +493,9 @@ fn parse_angle_arg(
                         // Parse associated type constraint bound.
 
                         let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
-                        AssocTyConstraintKind::Bound { bounds }
+                        AssocConstraintKind::Bound { bounds }
                     } else if self.eat(&token::Eq) {
-                        // Parse associated type equality constraint
-
-                        let ty = self.parse_assoc_equality_term(ident, self.prev_token.span)?;
-                        AssocTyConstraintKind::Equality { ty }
+                        self.parse_assoc_equality_term(ident, self.prev_token.span)?
                     } else {
                         unreachable!();
                     };
@@ -482,11 +503,11 @@ fn parse_angle_arg(
                     let span = lo.to(self.prev_token.span);
 
                     // Gate associated type bounds, e.g., `Iterator<Item: Ord>`.
-                    if let AssocTyConstraintKind::Bound { .. } = kind {
+                    if let AssocConstraintKind::Bound { .. } = kind {
                         self.sess.gated_spans.gate(sym::associated_type_bounds, span);
                     }
                     let constraint =
-                        AssocTyConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
+                        AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span };
                     Ok(Some(AngleBracketedArg::Constraint(constraint)))
                 } else {
                     Ok(Some(AngleBracketedArg::Arg(arg)))
@@ -499,22 +520,25 @@ fn parse_angle_arg(
     /// Parse the term to the right of an associated item equality constraint.
     /// That is, parse `<term>` in `Item = <term>`.
     /// Right now, this only admits types in `<term>`.
-    fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P<ast::Ty>> {
+    fn parse_assoc_equality_term(
+        &mut self,
+        ident: Ident,
+        eq: Span,
+    ) -> PResult<'a, AssocConstraintKind> {
         let arg = self.parse_generic_arg(None)?;
         let span = ident.span.to(self.prev_token.span);
-        match arg {
-            Some(GenericArg::Type(ty)) => return Ok(ty),
-            Some(GenericArg::Const(expr)) => {
-                self.struct_span_err(span, "cannot constrain an associated constant to a value")
-                    .span_label(ident.span, "this associated constant...")
-                    .span_label(expr.value.span, "...cannot be constrained to this value")
-                    .emit();
+        let term = match arg {
+            Some(GenericArg::Type(ty)) => ty.into(),
+            Some(GenericArg::Const(c)) => {
+                self.sess.gated_spans.gate(sym::associated_const_equality, span);
+                c.into()
             }
             Some(GenericArg::Lifetime(lt)) => {
                 self.struct_span_err(span, "associated lifetimes are not supported")
                     .span_label(lt.ident.span, "the lifetime is given here")
                     .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
                     .emit();
+                self.mk_ty(span, ast::TyKind::Err).into()
             }
             None => {
                 let after_eq = eq.shrink_to_hi();
@@ -542,8 +566,8 @@ fn parse_assoc_equality_term(&mut self, ident: Ident, eq: Span) -> PResult<'a, P
                 };
                 return Err(err);
             }
-        }
-        Ok(self.mk_ty(span, ast::TyKind::Err))
+        };
+        Ok(AssocConstraintKind::Equality { term })
     }
 
     /// We do not permit arbitrary expressions as const arguments. They must be one of:
index 02a774ba1291cf4228441acb11a1d863bc3d53bd..566b77a5e9e555f841b8010f72619ec5ad1738eb 100644 (file)
@@ -44,6 +44,11 @@ pub(super) enum RecoverQPath {
     No,
 }
 
+pub(super) enum IsAsCast {
+    Yes,
+    No,
+}
+
 /// Signals whether parsing a type should recover `->`.
 ///
 /// More specifically, when parsing a function like:
@@ -100,6 +105,7 @@ pub fn parse_ty(&mut self) -> PResult<'a, P<Ty>> {
             RecoverQPath::Yes,
             RecoverReturnSign::Yes,
             None,
+            IsAsCast::No,
         )
     }
 
@@ -113,6 +119,7 @@ pub(super) fn parse_ty_with_generics_recovery(
             RecoverQPath::Yes,
             RecoverReturnSign::Yes,
             Some(ty_params),
+            IsAsCast::No,
         )
     }
 
@@ -126,6 +133,7 @@ pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P<Ty>> {
             RecoverQPath::Yes,
             RecoverReturnSign::Yes,
             None,
+            IsAsCast::No,
         )
     }
 
@@ -142,9 +150,22 @@ pub(super) fn parse_ty_no_plus(&mut self) -> PResult<'a, P<Ty>> {
             RecoverQPath::Yes,
             RecoverReturnSign::Yes,
             None,
+            IsAsCast::No,
         )
     }
 
+    /// Parses a type following an `as` cast. Similar to `parse_ty_no_plus`, but signaling origin
+    /// for better diagnostics involving `?`.
+    pub(super) fn parse_as_cast_ty(&mut self) -> PResult<'a, P<Ty>> {
+        self.parse_ty_common(
+            AllowPlus::No,
+            AllowCVariadic::No,
+            RecoverQPath::Yes,
+            RecoverReturnSign::Yes,
+            None,
+            IsAsCast::Yes,
+        )
+    }
     /// Parse a type without recovering `:` as `->` to avoid breaking code such as `where fn() : for<'a>`
     pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
         self.parse_ty_common(
@@ -153,6 +174,7 @@ pub(super) fn parse_ty_for_where_clause(&mut self) -> PResult<'a, P<Ty>> {
             RecoverQPath::Yes,
             RecoverReturnSign::OnlyFatArrow,
             None,
+            IsAsCast::No,
         )
     }
 
@@ -171,6 +193,7 @@ pub(super) fn parse_ret_ty(
                 recover_qpath,
                 recover_return_sign,
                 None,
+                IsAsCast::No,
             )?;
             FnRetTy::Ty(ty)
         } else if recover_return_sign.can_recover(&self.token.kind) {
@@ -191,6 +214,7 @@ pub(super) fn parse_ret_ty(
                 recover_qpath,
                 recover_return_sign,
                 None,
+                IsAsCast::No,
             )?;
             FnRetTy::Ty(ty)
         } else {
@@ -205,6 +229,7 @@ fn parse_ty_common(
         recover_qpath: RecoverQPath,
         recover_return_sign: RecoverReturnSign,
         ty_generics: Option<&Generics>,
+        is_as_cast: IsAsCast,
     ) -> PResult<'a, P<Ty>> {
         let allow_qpath_recovery = recover_qpath == RecoverQPath::Yes;
         maybe_recover_from_interpolated_ty_qpath!(self, allow_qpath_recovery);
@@ -280,6 +305,7 @@ fn parse_ty_common(
         // Try to recover from use of `+` with incorrect priority.
         self.maybe_report_ambiguous_plus(allow_plus, impl_dyn_multi, &ty);
         self.maybe_recover_from_bad_type_plus(allow_plus, &ty)?;
+        let ty = self.maybe_recover_from_question_mark(ty, is_as_cast);
         self.maybe_recover_from_bad_qpath(ty, allow_qpath_recovery)
     }
 
index d7b00699491d4d71f4efb8959b497aa8edd4f271..c3d5bae32e6818a975ba3cdf758ec883fb58ba7f 100644 (file)
@@ -4,19 +4,18 @@
 //! conflicts between multiple such attributes attached to the same
 //! item.
 
-use rustc_middle::hir::map::Map;
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
-
 use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
 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::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID};
 use rustc_hir::{MethodKind, Target};
+use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::query::Providers;
+use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::{
     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES,
 };
@@ -32,7 +31,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(),
@@ -114,6 +113,7 @@ fn check_attributes(
                 }
                 sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
                 sym::must_use => self.check_must_use(hir_id, &attr, span, target),
+                sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target),
                 sym::rustc_const_unstable
                 | sym::rustc_const_stable
                 | sym::unstable
@@ -126,6 +126,7 @@ fn check_attributes(
             // lint-only checks
             match attr.name_or_empty() {
                 sym::cold => self.check_cold(hir_id, attr, span, target),
+                sym::link => self.check_link(hir_id, attr, span, target),
                 sym::link_name => self.check_link_name(hir_id, attr, span, target),
                 sym::link_section => self.check_link_section(hir_id, attr, span, target),
                 sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
@@ -134,7 +135,6 @@ fn check_attributes(
                 }
                 sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
                 sym::path => self.check_generic_attr(hir_id, attr, target, &[Target::Mod]),
-                sym::cfg_attr => self.check_cfg_attr(hir_id, attr),
                 sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
                 sym::macro_export => self.check_macro_export(hir_id, attr, target),
                 sym::ignore | sym::should_panic | sym::proc_macro_derive => {
@@ -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)
                         {
@@ -1066,6 +1066,24 @@ fn check_doc_attrs(
         is_valid
     }
 
+    /// Warns against some misuses of `#[pass_by_value]`
+    fn check_pass_by_value(&self, attr: &Attribute, span: &Span, target: Target) -> bool {
+        match target {
+            Target::Struct | Target::Enum | Target::TyAlias => true,
+            _ => {
+                self.tcx
+                    .sess
+                    .struct_span_err(
+                        attr.span,
+                        "`pass_by_value` attribute should be applied to a struct, enum or type alias.",
+                    )
+                    .span_label(*span, "is not a struct, enum or type alias")
+                    .emit();
+                false
+            }
+        }
+    }
+
     /// Warns against some misuses of `#[must_use]`
     fn check_must_use(
         &self,
@@ -1140,6 +1158,26 @@ fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Targe
         }
     }
 
+    /// Checks if `#[link]` is applied to an item other than a foreign module.
+    fn check_link(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
+        match target {
+            Target::ForeignMod => {}
+            _ => {
+                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
+                    let mut diag = lint.build("attribute should be applied to an `extern` block");
+                    diag.warn(
+                        "this was previously accepted by the compiler but is \
+                         being phased out; it will become a hard error in \
+                         a future release!",
+                    );
+
+                    diag.span_label(*span, "not an `extern` block");
+                    diag.emit();
+                });
+            }
+        }
+    }
+
     /// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
     fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) {
         match target {
@@ -1823,16 +1861,6 @@ fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
         }
     }
 
-    fn check_cfg_attr(&self, hir_id: HirId, attr: &Attribute) {
-        if let Some((_, attrs)) = rustc_parse::parse_cfg_attr(&attr, &self.tcx.sess.parse_sess) {
-            if attrs.is_empty() {
-                self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                    lint.build("`#[cfg_attr]` does not expand to any attributes").emit();
-                });
-            }
-        }
-    }
-
     fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) {
         if target != Target::Fn {
             self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
@@ -1843,10 +1871,10 @@ fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target
 }
 
 impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
index b755f686f6aac15e5222a016f1a99ed1081ce7d5..2b11f6b0c1d029efbf0d0a4d0812390ede307722 100644 (file)
@@ -11,8 +11,8 @@
 use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_middle::hir::map::Map;
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
@@ -262,10 +262,10 @@ fn recurse_into(
 }
 
 impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) {
index 3b15332c678fdd9e4101a60c6560de47d8fff262..7f15aacc532b31bf0f8300b55b2584b789016498 100644 (file)
@@ -3,18 +3,20 @@
 // from live codes are live, and everything else is dead.
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::pluralize;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{Node, PatKind, TyKind};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::privacy;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::lint;
 use rustc_span::symbol::{sym, Symbol};
+use rustc_span::Span;
 use std::mem;
 
 // Any local node that may call something in its body block should be
@@ -23,7 +25,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(..)
@@ -47,6 +49,10 @@ struct MarkSymbolVisitor<'tcx> {
     ignore_variant_stack: Vec<DefId>,
     // maps from tuple struct constructors to tuple struct items
     struct_constructors: FxHashMap<LocalDefId, LocalDefId>,
+    // maps from ADTs to ignored derived traits (e.g. Debug and Clone)
+    // and the span of their respective impl (i.e., part of the derive
+    // macro)
+    ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>,
 }
 
 impl<'tcx> MarkSymbolVisitor<'tcx> {
@@ -232,7 +238,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);
             }
@@ -242,7 +248,7 @@ fn mark_live_symbols(&mut self) {
     /// Automatically generated items marked with `rustc_trivial_field_reads`
     /// will be ignored for the purposes of dead code analysis (see PR #85200
     /// for discussion).
-    fn should_ignore_item(&self, def_id: DefId) -> bool {
+    fn should_ignore_item(&mut self, def_id: DefId) -> bool {
         if let Some(impl_of) = self.tcx.impl_of_method(def_id) {
             if !self.tcx.has_attr(impl_of, sym::automatically_derived) {
                 return false;
@@ -250,6 +256,16 @@ fn should_ignore_item(&self, def_id: DefId) -> bool {
 
             if let Some(trait_of) = self.tcx.trait_id_of_impl(impl_of) {
                 if self.tcx.has_attr(trait_of, sym::rustc_trivial_field_reads) {
+                    let trait_ref = self.tcx.impl_trait_ref(impl_of).unwrap();
+                    if let ty::Adt(adt_def, _) = trait_ref.self_ty().kind() {
+                        let impl_span = self.tcx.def_span(impl_of);
+                        if let Some(v) = self.ignored_derived_traits.get_mut(&adt_def.did) {
+                            v.push((impl_span, trait_of));
+                        } else {
+                            self.ignored_derived_traits
+                                .insert(adt_def.did, vec![(impl_span, trait_of)]);
+                        }
+                    }
                     return true;
                 }
             }
@@ -323,12 +339,6 @@ fn mark_as_used_if_union(&mut self, adt: &ty::AdtDef, fields: &[hir::ExprField<'
 }
 
 impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_nested_body(&mut self, body: hir::BodyId) {
         let old_maybe_typeck_results =
             self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
@@ -577,7 +587,7 @@ fn create_and_seed_worklist<'tcx>(
 fn find_live<'tcx>(
     tcx: TyCtxt<'tcx>,
     access_levels: &privacy::AccessLevels,
-) -> FxHashSet<LocalDefId> {
+) -> (FxHashSet<LocalDefId>, FxHashMap<DefId, Vec<(Span, DefId)>>) {
     let (worklist, struct_constructors) = create_and_seed_worklist(tcx, access_levels);
     let mut symbol_visitor = MarkSymbolVisitor {
         worklist,
@@ -590,14 +600,16 @@ fn find_live<'tcx>(
         pub_visibility: false,
         ignore_variant_stack: vec![],
         struct_constructors,
+        ignored_derived_traits: FxHashMap::default(),
     };
     symbol_visitor.mark_live_symbols();
-    symbol_visitor.live_symbols
+    (symbol_visitor.live_symbols, symbol_visitor.ignored_derived_traits)
 }
 
 struct DeadVisitor<'tcx> {
     tcx: TyCtxt<'tcx>,
     live_symbols: FxHashSet<LocalDefId>,
+    ignored_derived_traits: FxHashMap<DefId, Vec<(Span, DefId)>>,
 }
 
 impl<'tcx> DeadVisitor<'tcx> {
@@ -666,21 +678,51 @@ fn warn_dead_code(
             self.tcx.struct_span_lint_hir(lint::builtin::DEAD_CODE, id, span, |lint| {
                 let def_id = self.tcx.hir().local_def_id(id);
                 let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
-                lint.build(&format!("{} is never {}: `{}`", descr, participle, name)).emit()
+                let mut err = lint.build(&format!("{} is never {}: `{}`", descr, participle, name));
+                let hir = self.tcx.hir();
+                if let Some(encl_scope) = hir.get_enclosing_scope(id) {
+                    if let Some(encl_def_id) = hir.opt_local_def_id(encl_scope) {
+                        if let Some(ign_traits) =
+                            self.ignored_derived_traits.get(&encl_def_id.to_def_id())
+                        {
+                            let traits_str = ign_traits
+                                .iter()
+                                .map(|(_, t)| format!("`{}`", self.tcx.item_name(*t)))
+                                .collect::<Vec<_>>()
+                                .join(" and ");
+                            let plural_s = pluralize!(ign_traits.len());
+                            let article = if ign_traits.len() > 1 { "" } else { "a " };
+                            let is_are = if ign_traits.len() > 1 { "these are" } else { "this is" };
+                            let msg = format!(
+                                "`{}` has {}derived impl{} for the trait{} {}, but {} \
+                                 intentionally ignored during dead code analysis",
+                                self.tcx.item_name(encl_def_id.to_def_id()),
+                                article,
+                                plural_s,
+                                plural_s,
+                                traits_str,
+                                is_are
+                            );
+                            let multispan = ign_traits.iter().map(|(s, _)| *s).collect::<Vec<_>>();
+                            err.span_note(multispan, &msg);
+                        }
+                    }
+                }
+                err.emit();
             });
         }
     }
 }
 
 impl<'tcx> Visitor<'tcx> for DeadVisitor<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
     /// Walk nested items in place so that we don't report dead-code
     /// on inner functions when the outer function is already getting
     /// an error. We could do this also by checking the parents, but
     /// this is how the code is setup and it seems harmless enough.
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -796,7 +838,7 @@ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem<'tcx>) {
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
     let access_levels = &tcx.privacy_access_levels(());
-    let live_symbols = find_live(tcx, access_levels);
-    let mut visitor = DeadVisitor { tcx, live_symbols };
+    let (live_symbols, ignored_derived_traits) = find_live(tcx, access_levels);
+    let mut visitor = DeadVisitor { tcx, live_symbols, ignored_derived_traits };
     tcx.hir().walk_toplevel_module(&mut visitor);
 }
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..56755d68686e3d27b4c70df96de00d5ef82db02d 100644 (file)
@@ -6,6 +6,7 @@
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::{HirId, ItemLocalId};
 use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 
 pub fn check_crate(tcx: TyCtxt<'_>) {
@@ -57,22 +58,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 +84,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);
 
@@ -140,10 +140,10 @@ fn check<F: FnOnce(&mut HirIdValidator<'a, 'hir>)>(&mut self, hir_id: HirId, wal
 }
 
 impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> {
-    type Map = Map<'hir>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::OnlyBodies(self.hir_map)
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.hir_map
     }
 
     fn visit_id(&mut self, hir_id: HirId) {
index d665c12f762c5baa49a0fb6974c847191d196f34..6cf1aa480d298e1d64eefeb00cc95b23fe913fab 100644 (file)
@@ -95,12 +95,6 @@ fn visit_param(&mut self, param: &'v hir::Param<'v>) {
         hir_visit::walk_param(self, param)
     }
 
-    type Map = Map<'v>;
-
-    fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
-        panic!("visit_nested_xxx must be manually implemented in this visitor")
-    }
-
     fn visit_nested_item(&mut self, id: hir::ItemId) {
         let nested_item = self.krate.unwrap().item(id);
         self.visit_item(nested_item)
@@ -338,9 +332,9 @@ fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v ast::PathSeg
         ast_visit::walk_path_segment(self, path_span, path_segment)
     }
 
-    fn visit_assoc_ty_constraint(&mut self, constraint: &'v ast::AssocTyConstraint) {
-        self.record("AssocTyConstraint", Id::None, constraint);
-        ast_visit::walk_assoc_ty_constraint(self, constraint)
+    fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
+        self.record("AssocConstraint", Id::None, constraint);
+        ast_visit::walk_assoc_constraint(self, constraint)
     }
 
     fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
index 064c46966284254e8de0ecb9f2e36e8d443dcd71..1031ba01c1b480f0b73b0c4dc6fff9d8a355121d 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_index::vec::Idx;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
 use rustc_middle::ty::query::Providers;
@@ -294,9 +294,8 @@ fn check_asm_operand_type(
         // (!). In that case we still need the earlier check to verify that the
         // register class is usable at all.
         if let Some(feature) = feature {
-            let feat_sym = Symbol::intern(feature);
-            if !self.tcx.sess.target_features.contains(&feat_sym)
-                && !target_features.contains(&feat_sym)
+            if !self.tcx.sess.target_features.contains(&feature)
+                && !target_features.contains(&feature)
             {
                 let msg = &format!("`{}` target feature is not enabled", feature);
                 let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
@@ -377,9 +376,8 @@ fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, hir_id: hir::HirId) {
                     {
                         match feature {
                             Some(feature) => {
-                                let feat_sym = Symbol::intern(feature);
-                                if self.tcx.sess.target_features.contains(&feat_sym)
-                                    || attrs.target_features.contains(&feat_sym)
+                                if self.tcx.sess.target_features.contains(&feature)
+                                    || attrs.target_features.contains(&feature)
                                 {
                                     missing_required_features.clear();
                                     break;
@@ -413,7 +411,11 @@ fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, hir_id: hir::HirId) {
                             let msg = format!(
                                 "register class `{}` requires at least one of the following target features: {}",
                                 reg_class.name(),
-                                features.join(", ")
+                                features
+                                    .iter()
+                                    .map(|f| f.as_str())
+                                    .intersperse(", ")
+                                    .collect::<String>(),
                             );
                             self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
                             // register isn't enabled, don't do more checks
@@ -488,12 +490,6 @@ fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, hir_id: hir::HirId) {
 }
 
 impl<'tcx> Visitor<'tcx> for ItemVisitor<'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_nested_body(&mut self, body_id: hir::BodyId) {
         let owner_def_id = self.tcx.hir().body_owner_def_id(body_id);
         let body = self.tcx.hir().body(body_id);
@@ -505,12 +501,6 @@ fn visit_nested_body(&mut self, body_id: hir::BodyId) {
 }
 
 impl<'tcx> Visitor<'tcx> for ExprVisitor<'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         match expr.kind {
             hir::ExprKind::Path(ref qpath) => {
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..2075fee7171052ada4084fa4213e8015767a5371 100644 (file)
@@ -6,6 +6,8 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(crate_visibility_modifier)]
+#![feature(iter_intersperse)]
+#![feature(let_else)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
 #![feature(nll)]
index 40d12c4a22dd37d1ed085ffd82e2ee9b0207b997..00445690f8f02124ff6d8d5840e4f445257dca05 100644 (file)
@@ -6,8 +6,8 @@
 
 use rustc_ast::{Attribute, MetaItemKind};
 use rustc_errors::struct_span_err;
-use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
-use rustc_middle::hir::map::Map;
+use rustc_hir::intravisit::Visitor;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::lib_features::LibFeatures;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
@@ -111,10 +111,10 @@ fn span_feature_error(&self, span: Span, msg: &str) {
 }
 
 impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_attribute(&mut self, _: rustc_hir::HirId, attr: &'tcx Attribute) {
index 9ee305b712f61ba495a9db0356fe4c2627be2f0a..69cd1b4fed589b5d772dce7fc64892c0fdb40d67 100644 (file)
 use rustc_hir as hir;
 use rustc_hir::def::*;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet};
 use rustc_index::vec::IndexVec;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, DefIdTree, RootVariableMinCaptureList, Ty, TyCtxt};
 use rustc_session::lint;
 use std::collections::VecDeque;
 use std::io;
 use std::io::prelude::*;
-use std::iter;
 use std::rc::Rc;
 
 mod rwu_table;
@@ -317,10 +316,10 @@ fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) {
 }
 
 impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) {
@@ -470,7 +469,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
             | hir::ExprKind::Struct(..)
             | hir::ExprKind::Repeat(..)
             | hir::ExprKind::InlineAsm(..)
-            | hir::ExprKind::LlvmInlineAsm(..)
             | hir::ExprKind::Box(..)
             | hir::ExprKind::Type(..)
             | hir::ExprKind::Err
@@ -726,7 +724,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 => {}
                     }
                 }
             }
@@ -1091,26 +1089,6 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
                 succ
             }
 
-            hir::ExprKind::LlvmInlineAsm(ref asm) => {
-                let ia = &asm.inner;
-                let outputs = asm.outputs_exprs;
-                let inputs = asm.inputs_exprs;
-                let succ = iter::zip(&ia.outputs, outputs).rev().fold(succ, |succ, (o, output)| {
-                    // see comment on places
-                    // in propagate_through_place_components()
-                    if o.is_indirect {
-                        self.propagate_through_expr(output, succ)
-                    } else {
-                        let acc = if o.is_rw { ACC_WRITE | ACC_READ } else { ACC_WRITE };
-                        let succ = self.write_place(output, succ, acc);
-                        self.propagate_through_place_components(output, succ)
-                    }
-                });
-
-                // Inputs are executed first. Propagate last because of rev order
-                self.propagate_through_exprs(inputs, succ)
-            }
-
             hir::ExprKind::Lit(..)
             | hir::ExprKind::ConstBlock(..)
             | hir::ExprKind::Err
@@ -1327,12 +1305,6 @@ fn warn_about_unreachable(
 // Checking for error conditions
 
 impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
         self.check_unused_vars_in_pat(&local.pat, None, |spans, hir_id, ln, var| {
             if local.init.is_some() {
@@ -1387,20 +1359,6 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
             }
         }
 
-        hir::ExprKind::LlvmInlineAsm(ref asm) => {
-            for input in asm.inputs_exprs {
-                this.visit_expr(input);
-            }
-
-            // Output operands must be places
-            for (o, output) in iter::zip(&asm.inner.outputs, asm.outputs_exprs) {
-                if !o.is_indirect {
-                    this.check_place(output);
-                }
-                this.visit_expr(output);
-            }
-        }
-
         hir::ExprKind::Let(let_expr) => {
             this.check_unused_vars_in_pat(let_expr.pat, None, |_, _, _, _| {});
         }
@@ -1481,7 +1439,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 4bfac1b72983eba1db0c674e346a9fa9ec7a49ea..02b09daf0a41e443b012f19621971e0e685f23a8 100644 (file)
@@ -3,9 +3,10 @@
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Destination, Movability, Node};
 use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
@@ -41,10 +42,10 @@ pub(crate) fn provide(providers: &mut Providers) {
 }
 
 impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
-    type Map = Map<'hir>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.hir_map)
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.hir_map
     }
 
     fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) {
index 07cb165d79670ee4dc2c75ee1e2d8788405bcd38..0228196d1a1a1c47fd5c5b6e20aa9e2bb508e7aa 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_ast::{Attribute, InlineAsmOptions};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{ErasedMap, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{FnKind, Visitor};
 use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
@@ -29,12 +29,6 @@ struct CheckNakedFunctions<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
-    type Map = ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_fn(
         &mut self,
         fk: FnKind<'_>,
@@ -129,12 +123,6 @@ struct CheckParameters<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
-    type Map = ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         if let hir::ExprKind::Path(hir::QPath::Resolved(
             _,
@@ -236,22 +224,6 @@ fn check_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, span: Span) {
                 self.check_inline_asm(expr.hir_id, asm, span);
             }
 
-            ExprKind::LlvmInlineAsm(..) => {
-                self.items.push((ItemKind::Asm, span));
-                self.tcx.struct_span_lint_hir(
-                    UNSUPPORTED_NAKED_FUNCTIONS,
-                    expr.hir_id,
-                    span,
-                    |lint| {
-                        lint.build(
-                            "the LLVM-style inline assembly is unsupported in naked functions",
-                        )
-                        .help("use the new asm! syntax specified in RFC 2873")
-                        .emit();
-                    },
-                );
-            }
-
             ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
                 hir::intravisit::walk_expr(self, expr);
             }
@@ -312,12 +284,6 @@ fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span:
 }
 
 impl<'tcx> Visitor<'tcx> for CheckInlineAssembly<'tcx> {
-    type Map = ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
         match stmt.kind {
             StmtKind::Item(..) => {}
index 707e6b123daa2ea69c78ee7c7f4d67575dae4103..6cd9dc23285a963d9bb2dfb46c6ecbbd7e406e0d 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::itemlikevisit::ItemLikeVisitor;
 use rustc_hir::Node;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
@@ -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"),
     }
@@ -74,12 +74,6 @@ struct ReachableContext<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for ReachableContext<'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_nested_body(&mut self, body: hir::BodyId) {
         let old_maybe_typeck_results =
             self.maybe_typeck_results.replace(self.tcx.typeck_body(body));
@@ -140,14 +134,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 +160,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 +190,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 8968c163987dcc01951856789412932ab3d63145..db699a56645c2ae641e27eca378ea50755ab7537 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
 use rustc_index::vec::Idx;
 use rustc_middle::middle::region::*;
@@ -721,12 +721,6 @@ fn enter_node_scope_with_dtor(&mut self, id: hir::ItemLocalId) {
 }
 
 impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_block(&mut self, b: &'tcx Block<'tcx>) {
         resolve_block(self, b);
     }
index c136411df2712f970a9b55396e5cdefbfdd71b7a..3521b6fc1696c7978072e63fe92636be9baf4ecb 100644 (file)
@@ -9,9 +9,9 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE};
 use rustc_hir::hir_id::CRATE_HIR_ID;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{FieldDef, Generics, HirId, Item, TraitRef, Ty, TyKind, Variant};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::middle::stability::{DeprecationEntry, Index};
 use rustc_middle::ty::{self, query::Providers, TyCtxt};
@@ -378,10 +378,10 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
     /// Because stability levels are scoped lexically, we want to walk
     /// nested items in the context of the outer item, so enable
     /// deep-walking.
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
@@ -593,10 +593,10 @@ fn check_missing_const_stability(&self, def_id: LocalDefId, span: Span) {
 }
 
 impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_item(&mut self, i: &'tcx Item<'tcx>) {
@@ -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);
         }
@@ -738,13 +738,13 @@ struct Checker<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
     /// Because stability levels are scoped lexically, we want to walk
     /// nested items in the context of the outer item, so enable
     /// deep-walking.
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -860,12 +860,6 @@ struct CheckTraitImplStable<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for CheckTraitImplStable<'tcx> {
-    type Map = Map<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) {
         if let Some(def_id) = path.res.opt_def_id() {
             if let Some(stab) = self.tcx.lookup_stability(def_id) {
index 2d84c8caada80a0ac178f3bb3c0e7325976e6c0c..25fe8e4582535eb391855e0f5bbba24ee533a992 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self, HirId};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
@@ -43,12 +43,6 @@ struct LocalCollector {
 }
 
 impl<'tcx> Visitor<'tcx> for LocalCollector {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
         if let hir::PatKind::Binding(_, hir_id, ..) = pat.kind {
             self.locals.insert(hir_id);
@@ -72,12 +66,6 @@ fn visit_local_use(&mut self, var_id: HirId, span: Span) {
 }
 
 impl<'tcx> Visitor<'tcx> for CaptureCollector<'_, 'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
         if let Res::Local(var_id) = path.res {
             self.visit_local_use(var_id, path.span);
index 61c82f031dd5b055ae639ca5570afdaa0da79e71..6b73c95011940a1cc0c3883574ab46d33420d44e 100644 (file)
@@ -1,10 +1,9 @@
 //! 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;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::lang_items::{self, LangItem};
 use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
 use rustc_middle::middle::lang_items::required;
@@ -96,16 +95,9 @@ fn register(&mut self, name: Symbol, span: Span) {
 }
 
 impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
-    type Map = intravisit::ErasedMap<'v>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     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 16418e627f2dcf994c637da1d1d792fa3326e544..0b4579b299d099cec7e674eb2fa77fc889f03fd5 100644 (file)
 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::intravisit::{self, DeepVisitor, NestedVisitorMap, Visitor};
+use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
+use rustc_hir::intravisit::{self, DeepVisitor, Visitor};
 use rustc_hir::{AssocItemKind, HirIdSet, Node, PatKind};
 use rustc_middle::bug;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
 use rustc_middle::span_bug;
 use rustc_middle::thir::abstract_const::Node as ACNode;
@@ -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};
 
@@ -128,8 +127,8 @@ fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<V::
                 constness: _,
                 polarity: _,
             }) => self.visit_trait(trait_ref),
-            ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, ty }) => {
-                ty.visit_with(self)?;
+            ty::PredicateKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
+                term.visit_with(self)?;
                 self.visit_projection_ty(projection_ty)
             }
             ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => {
@@ -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`.
@@ -310,10 +305,10 @@ struct PubRestrictedVisitor<'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for PubRestrictedVisitor<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
     fn visit_vis(&mut self, vis: &'tcx hir::Visibility<'tcx>) {
         self.has_pub_restricted = self.has_pub_restricted || vis.node.is_pub_restricted();
@@ -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);
@@ -623,116 +627,37 @@ 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> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     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_reexports(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)
             )
@@ -1066,12 +964,12 @@ fn check_field(
 }
 
 impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
@@ -1195,12 +1093,12 @@ fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display)
 }
 
 impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
@@ -1250,19 +1148,11 @@ fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
                 if self.visit(ty).is_break() {
                     return;
                 }
+            } else {
+                // We don't do anything for const infers here.
             }
         } else {
-            let local_id = self.tcx.hir().local_def_id(inf.hir_id);
-            if let Some(did) = self.tcx.opt_const_param_of(local_id) {
-                if self.visit_def_id(did, "inferred", &"").is_break() {
-                    return;
-                }
-            }
-
-            // FIXME see above note for same issue.
-            if self.visit(rustc_typeck::hir_ty_to_ty(self.tcx, &inf.to_ty())).is_break() {
-                return;
-            }
+            bug!("visit_infer without typeck_results");
         }
         intravisit::walk_inf(self, inf);
     }
@@ -1287,10 +1177,10 @@ fn visit_trait_ref(&mut self, trait_ref: &'tcx hir::TraitRef<'tcx>) {
             }
 
             for (poly_predicate, _) in bounds.projection_bounds {
-                if self.visit(poly_predicate.skip_binder().ty).is_break()
-                    || self
-                        .visit_projection_ty(poly_predicate.skip_binder().projection_ty)
-                        .is_break()
+                let pred = poly_predicate.skip_binder();
+                let poly_pred_term = self.visit(pred.term);
+                if poly_pred_term.is_break()
+                    || self.visit_projection_ty(pred.projection_ty).is_break()
                 {
                     return;
                 }
@@ -1497,12 +1387,6 @@ fn item_is_public(&self, def_id: LocalDefId, vis: &hir::Visibility<'_>) -> bool
 }
 
 impl<'a, 'b, 'tcx, 'v> Visitor<'v> for ObsoleteCheckTypeForPrivatenessVisitor<'a, 'b, 'tcx> {
-    type Map = intravisit::ErasedMap<'v>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) {
         match generic_arg {
             hir::GenericArg::Type(t) => self.visit_ty(t),
@@ -1533,12 +1417,12 @@ fn visit_expr(&mut self, _: &hir::Expr<'_>) {}
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
     /// We want to visit items in the context of their containing
     /// module and so forth, so supply a crate for doing a deep walk.
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -1982,10 +1866,10 @@ fn check_assoc_item(
 }
 
 impl<'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -2122,7 +2006,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 +2050,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 +2064,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 7c96f68ffb3765e17fc741001784ba3bbd33a521..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;
@@ -165,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"
+                );
             })
         }
     }
@@ -174,7 +179,7 @@ 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,
@@ -227,10 +232,7 @@ pub fn with_query_deserialization<OP, R>(&self, op: OP) -> R
     where
         OP: FnOnce() -> R,
     {
-        let mut deps = TaskDeps::default();
-        deps.read_allowed = false;
-        let deps = Lock::new(deps);
-        K::with_deps(Some(&deps), op)
+        K::with_deps(TaskDepsRef::Forbid, op)
     }
 
     /// Starts a new dep-graph task. Dep-graph tasks are specified
@@ -313,10 +315,15 @@ fn with_task_impl<Ctxt: HasDepContext<DepKind = K>, A: Debug, R>(
                 reads: SmallVec::new(),
                 read_set: Default::default(),
                 phantom_data: PhantomData,
-                read_allowed: true,
             }))
         };
-        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();
@@ -369,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;
 
@@ -422,47 +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 !task_deps.read_allowed {
-                        panic!("Illegal read of: {:?}", dep_node_index);
+                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;
 
-                    if cfg!(debug_assertions) {
-                        data.current.total_read_count.fetch_add(1, Relaxed);
-                    }
+                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());
-                        }
+                // 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);
                 }
             })
         }
@@ -1185,21 +1192,34 @@ 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,
     read_set: FxHashSet<DepNodeIndex>,
     phantom_data: PhantomData<DepNode<K>>,
-    /// Whether or not we allow `DepGraph::read_index` to run.
-    /// This is normally true, except inside `with_query_deserialization`,
-    /// where it set to `false` to enforce that no new `DepNode` edges are
-    /// created. See the documentation of `with_query_deserialization` for
-    /// more details.
-    read_allowed: bool,
 }
 
-impl<K> Default for TaskDeps<K> {
+impl<K: DepKind> Default for TaskDeps<K> {
     fn default() -> Self {
         Self {
             #[cfg(debug_assertions)]
@@ -1207,7 +1227,6 @@ fn default() -> Self {
             reads: EdgesVec::new(),
             read_set: FxHashSet::default(),
             phantom_data: PhantomData,
-            read_allowed: true,
         }
     }
 }
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 3117140a5b61269bbed304be17d4a2a2903d6b36..bf3cf6a48fd03d706f11ebba2f091d0bc2aa446f 100644 (file)
@@ -11,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.
             }
@@ -89,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;
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 944e71851840cfacda90f818fe7970590e25aedc..631b8fef668db35181a33b8468819615d62e18ca 100644 (file)
@@ -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,
@@ -999,12 +999,14 @@ fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) {
         let cstore = self.r.cstore();
         match res {
             Res::Def(DefKind::Struct, def_id) => {
-                let field_names = cstore.struct_field_names_untracked(def_id, self.r.session);
+                let field_names =
+                    cstore.struct_field_names_untracked(def_id, self.r.session).collect();
                 let ctor = cstore.ctor_def_id_and_kind_untracked(def_id);
                 if let Some((ctor_def_id, ctor_kind)) = ctor {
                     let ctor_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
                     let ctor_vis = cstore.visibility_untracked(ctor_def_id);
-                    let field_visibilities = cstore.struct_field_visibilities_untracked(def_id);
+                    let field_visibilities =
+                        cstore.struct_field_visibilities_untracked(def_id).collect();
                     self.r
                         .struct_constructors
                         .insert(def_id, (ctor_res, ctor_vis, field_visibilities));
@@ -1012,7 +1014,8 @@ fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) {
                 self.insert_field_names(def_id, field_names);
             }
             Res::Def(DefKind::Union, def_id) => {
-                let field_names = cstore.struct_field_names_untracked(def_id, self.r.session);
+                let field_names =
+                    cstore.struct_field_names_untracked(def_id, self.r.session).collect();
                 self.insert_field_names(def_id, field_names);
             }
             Res::Def(DefKind::AssocFn, def_id) => {
index 4feeae5cab1ded3c12fefa1e327e220330038133..c7edcb077b917ec7a0582ae891aae2138fd66efe 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,11 +914,8 @@ 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_untracked(did, this.session)
-                                        .iter()
-                                        .any(|attr| {
+                                    && this.cstore().item_attrs_untracked(did, this.session).any(
+                                        |attr| {
                                             if attr.has_name(sym::rustc_diagnostic_item) {
                                                 [sym::TryInto, sym::TryFrom, sym::FromIterator]
                                                     .map(|x| Some(x))
@@ -907,7 +923,8 @@ fn lookup_import_candidates_from_module<FilterFn>(
                                             } else {
                                                 false
                                             }
-                                        });
+                                        },
+                                    );
 
                                 requires_note.then(|| {
                                     format!(
index 2832f59a5efc68340635b16672de6aad0f1c9e63..e7f76a18ad31addf4cb8608b1b052c2ed4260f1f 100644 (file)
@@ -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;
index 1b02511fd7c2f29934c626631aad5aa259ad6886..ccaaa2eaf4672d71f719b468017aad57ee00ac65 100644 (file)
@@ -1247,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()));
                 }
             }
@@ -1324,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,
@@ -1359,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,
@@ -1386,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,
@@ -1416,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,
@@ -1424,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]) {
index 02e57109bbd830cd56f86146fd3e8e533853f899..b077a5c9144c5d0c6a9460274e7e26644e7495f7 100644 (file)
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefIdMap, LocalDefId};
 use rustc_hir::hir_id::ItemLocalId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericArg, GenericParam, LifetimeName, Node, ParamName, QPath};
 use rustc_hir::{GenericParamKind, HirIdMap, HirIdSet, LifetimeParamKind};
 use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_lifetime::*;
 use rustc_middle::ty::{self, DefIdTree, GenericParamDefKind, TyCtxt};
 use rustc_middle::{bug, span_bug};
@@ -376,12 +377,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 +512,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);
@@ -654,10 +652,10 @@ fn poly_trait_ref_binder_info(&mut self) -> (Vec<ty::BoundVariableKind>, BinderS
     }
 }
 impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     // We want to nest trait/impl items in their parent, but nothing else.
@@ -1137,7 +1135,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 +1204,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,
@@ -1616,12 +1614,6 @@ struct GatherLabels<'a, 'tcx> {
     gather.visit_body(body);
 
     impl<'v, 'a, 'tcx> Visitor<'v> for GatherLabels<'a, 'tcx> {
-        type Map = intravisit::ErasedMap<'v>;
-
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-
         fn visit_expr(&mut self, ex: &hir::Expr<'_>) {
             if let Some(label) = expression_label(ex) {
                 for prior_label in &self.labels_in_fn[..] {
@@ -1672,13 +1664,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 +1899,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 +1940,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 +2022,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 +2043,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 +2058,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 +2104,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 +2127,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 +2751,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 +2764,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 =
@@ -2837,12 +2827,6 @@ fn is_self_ty(&self, res: Res) -> bool {
             }
 
             impl<'a> Visitor<'a> for SelfVisitor<'a> {
-                type Map = intravisit::ErasedMap<'a>;
-
-                fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-                    NestedVisitorMap::None
-                }
-
                 fn visit_ty(&mut self, ty: &'a hir::Ty<'a>) {
                     if let hir::TyKind::Rptr(lifetime_ref, ref mt) = ty.kind {
                         if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.kind
@@ -2927,12 +2911,6 @@ struct GatherLifetimes<'a> {
         }
 
         impl<'v, 'a> Visitor<'v> for GatherLifetimes<'a> {
-            type Map = intravisit::ErasedMap<'v>;
-
-            fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-                NestedVisitorMap::None
-            }
-
             fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
                 if let hir::TyKind::BareFn(_) = ty.kind {
                     self.outer_index.shift_in(1);
@@ -3010,12 +2988,6 @@ struct GatherAnonLifetimes {
             anon_count: u32,
         }
         impl<'v> Visitor<'v> for GatherAnonLifetimes {
-            type Map = intravisit::ErasedMap<'v>;
-
-            fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-                NestedVisitorMap::None
-            }
-
             #[instrument(skip(self), level = "trace")]
             fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
                 // If we enter a `BareFn`, then we enter a *new* binding scope
@@ -3339,13 +3311,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;
@@ -3516,12 +3485,6 @@ struct ConstrainedCollector {
     }
 
     impl<'v> Visitor<'v> for ConstrainedCollector {
-        type Map = intravisit::ErasedMap<'v>;
-
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-
         fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
             match ty.kind {
                 hir::TyKind::Path(
@@ -3560,12 +3523,6 @@ struct AllCollector {
     }
 
     impl<'v> Visitor<'v> for AllCollector {
-        type Map = intravisit::ErasedMap<'v>;
-
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-
         fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
             self.regions.insert(lifetime_ref.name.normalize_to_macros_2_0());
         }
index 37be0e228d27ade0f3e022cc04e4a5b2cb5cbe38..f5b2ba8fd72eb213ae793230a67d60982b368fef 100644 (file)
@@ -50,6 +50,7 @@
 use rustc_index::vec::IndexVec;
 use rustc_metadata::creader::{CStore, CrateLoader};
 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};
 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> {
@@ -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.
@@ -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);
@@ -1452,10 +1467,12 @@ pub fn into_outputs(self) -> ResolverOutputs {
         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,
             reexport_map,
             glob_map,
@@ -1477,6 +1494,7 @@ 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(),
@@ -1532,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 +3442,6 @@ pub fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option<Vec<usize>> {
                 let attr = self
                     .cstore()
                     .item_attrs_untracked(def_id, self.session)
-                    .into_iter()
                     .find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
                 let mut ret = Vec::new();
                 for meta in attr.meta_item_list()? {
index 23f5b17fa78893187e796d3fe5c5fa452041cb27..754c2b03e667125da971456e796424799630a3f5 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir_pretty::{bounds_to_string, fn_to_string, generic_params_to_string, ty_to_string};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
 use rustc_session::config::Input;
@@ -1137,10 +1137,10 @@ fn process_bounds(&mut self, bounds: hir::GenericBounds<'tcx>) {
 }
 
 impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
index a83f02308145e57a704b599d001b1d24706d1fee..21cb93cc5f48bfb3adaec849c9767fdb0d99e6d3 100644 (file)
@@ -18,7 +18,7 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::Node;
 use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::{self, print::with_no_trimmed_paths, DefIdTree, TyCtxt};
 use rustc_middle::{bug, span_bug};
@@ -859,10 +859,10 @@ fn new(tcx: TyCtxt<'l>) -> PathCollector<'l> {
 }
 
 impl<'l> Visitor<'l> for PathCollector<'l> {
-    type Map = Map<'l>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_pat(&mut self, p: &'l hir::Pat<'l>) {
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 f2ef14816813ffcc8f97f94bace4b99c149ae28b..078237801be695142e5a6c8d8bb1fadcd5273b58 100644 (file)
@@ -560,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> {
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 62b351f5e0279a54eabbcdbe6386df03ebdf4585..92ad0723f4879f31690307761dffb600296f75ce 100644 (file)
@@ -565,6 +565,7 @@ pub enum PrintRequest {
     TargetSpec,
     NativeStaticLibs,
     StackProtectorStrategies,
+    LinkArgs,
 }
 
 #[derive(Copy, Clone)]
@@ -1187,7 +1188,8 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
             "Compiler information to print on stdout",
             "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
              target-cpus|target-features|relocation-models|code-models|\
-             tls-models|target-spec-json|native-static-libs|stack-protector-strategies]",
+             tls-models|target-spec-json|native-static-libs|stack-protector-strategies\
+             link-args]",
         ),
         opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
         opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
@@ -1619,6 +1621,7 @@ fn collect_print_requests(
                 );
             }
         }
+        "link-args" => PrintRequest::LinkArgs,
         req => early_error(error_format, &format!("unknown print request `{}`", req)),
     }));
 
index 0b9623d1c7d6f69c4e99cd5265fc27e618e9b666..e7ab8fffdf35c4440f3392151b7590c6eefb193d 100644 (file)
@@ -1161,6 +1161,8 @@ mod parse {
     dep_tasks: bool = (false, parse_bool, [UNTRACKED],
         "print tasks that execute and the color their dep node gets (requires debug build) \
         (default: no)"),
+    dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+        "import library generation tool (windows-gnu only)"),
     dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
         "emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
         (default: no)"),
@@ -1337,8 +1339,6 @@ mod parse {
         See #77382 and #74551."),
     print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
         "make rustc print the total optimization fuel used by a crate"),
-    print_link_args: bool = (false, parse_bool, [UNTRACKED],
-        "print the arguments passed to the linker (default: no)"),
     print_llvm_passes: bool = (false, parse_bool, [UNTRACKED],
         "print the LLVM optimization passes being run (default: no)"),
     print_mono_items: Option<String> = (None, parse_opt_string, [UNTRACKED],
index 24d2a8ac0738295d5c457797895843a950d98e1f..5390eed89fadc70f168f201e4c069f3fc8daa56c 100644 (file)
@@ -176,9 +176,9 @@ pub fn new(crate_name: &str, is_exe: bool, mut metadata: Vec<String>) -> StableC
         // and no -Cmetadata, symbols from the same crate compiled with different versions of
         // rustc are named the same.
         //
-        // RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER is used to inject rustc version information
+        // RUSTC_FORCE_RUSTC_VERSION is used to inject rustc version information
         // during testing.
-        if let Some(val) = std::env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
+        if let Some(val) = std::env::var_os("RUSTC_FORCE_RUSTC_VERSION") {
             hasher.write(val.to_string_lossy().into_owned().as_bytes())
         } else {
             hasher.write(option_env!("CFG_VERSION").unwrap_or("unknown version").as_bytes());
@@ -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
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 84cf8878af8095fb00b090386bb3cb09f98f543a..702e35946607954b772a17f30cc3e98f2a7498e9 100644 (file)
         LinkedList,
         LintPass,
         Mutex,
+        N,
         None,
         Ok,
         Option,
         allow_internal_unsafe,
         allow_internal_unstable,
         allowed,
+        alu32,
         always,
         and,
         and_then,
         array,
         arrays,
         as_ptr,
+        as_ref,
         as_str,
         asm,
         asm_const,
         asm_sym,
         asm_unwind,
         assert,
+        assert_eq_macro,
         assert_inhabited,
         assert_macro,
+        assert_ne_macro,
         assert_receiver_is_total_eq,
         assert_uninit_valid,
         assert_zero_valid,
+        associated_const_equality,
         associated_consts,
         associated_type_bounds,
         associated_type_defaults,
         augmented_assignments,
         auto_traits,
         automatically_derived,
+        avx,
         avx512_target_feature,
+        avx512bw,
+        avx512f,
         await_macro,
         bang,
         begin_panic,
         cfg_doctest,
         cfg_eval,
         cfg_hide,
+        cfg_macro,
         cfg_panic,
         cfg_sanitize,
         cfg_target_abi,
         coerce_unsized,
         cold,
         column,
+        column_macro,
         compare_and_swap,
         compare_exchange,
         compare_exchange_weak,
         compile_error,
+        compile_error_macro,
         compiler_builtins,
         compiler_fence,
         concat,
         concat_bytes,
         concat_idents,
+        concat_macro,
         conservative_impl_trait,
         console,
         const_allocate,
         custom_inner_attributes,
         custom_test_frameworks,
         d,
+        dbg_macro,
         dead_code,
         dealloc,
         debug,
+        debug_assert_eq_macro,
         debug_assert_macro,
+        debug_assert_ne_macro,
         debug_assertions,
         debug_struct,
         debug_trait_builder,
         doc_spotlight,
         doctest,
         document_private_items,
+        dotdot: "..",
         dotdot_in_tuple_patterns,
         dotdoteq_in_patterns,
         dreg,
         dylib,
         dyn_metadata,
         dyn_trait,
+        e,
         edition_macro_pats,
         edition_panic,
         eh_catch_typeinfo,
         enable,
         enclosing_scope,
         encode,
+        end,
         env,
+        env_macro,
+        eprint_macro,
+        eprintln_macro,
         eq,
         ermsb_target_feature,
         exact_div,
         field,
         field_init_shorthand,
         file,
+        file_macro,
         fill,
         finish,
         flags,
         format,
         format_args,
         format_args_capture,
+        format_args_macro,
         format_args_nl,
         format_macro,
+        fp,
         freeze,
         freg,
         frem_fast,
         in_band_lifetimes,
         include,
         include_bytes,
+        include_bytes_macro,
+        include_macro,
         include_str,
+        include_str_macro,
         inclusive_range_syntax,
         index,
         index_mut,
         lifetime,
         likely,
         line,
+        line_macro,
         link,
         link_args,
         link_cfg,
         linkage,
         lint_reasons,
         literal,
-        llvm_asm,
         load,
         loaded_from_disk,
         local,
         masked,
         match_beginning_vert,
         match_default_bindings,
+        matches_macro,
         maxnumf32,
         maxnumf64,
         may_dangle,
         modifiers,
         module,
         module_path,
+        module_path_macro,
         more_qualified_paths,
         more_struct_aliases,
         movbe_target_feature,
         neg,
         negate_unsigned,
         negative_impls,
+        neon,
         never,
         never_type,
         never_type_fallback,
         optin_builtin_traits,
         option,
         option_env,
+        option_env_macro,
         options,
         or,
         or_patterns,
         prelude_import,
         preserves_flags,
         primitive,
+        print_macro,
+        println_macro,
         proc_dash_macro: "proc-macro",
         proc_macro,
         proc_macro_attribute,
         repr_packed,
         repr_simd,
         repr_transparent,
+        reserved_r9: "reserved-r9",
         residual,
         result,
         rhs,
         rustc_macro_transparency,
         rustc_main,
         rustc_mir,
+        rustc_must_implement_one_of,
         rustc_nonnull_optimization_guaranteed,
         rustc_object_lifetime_default,
         rustc_on_unimplemented,
         rustc_paren_sugar,
         rustc_partition_codegened,
         rustc_partition_reused,
+        rustc_pass_by_value,
         rustc_peek,
         rustc_peek_definite_init,
         rustc_peek_liveness,
         simd,
         simd_add,
         simd_and,
+        simd_as,
         simd_bitmask,
         simd_cast,
         simd_ceil,
         sqrtf64,
         sreg,
         sreg_low16,
+        sse,
         sse4a_target_feature,
         stable,
         staged_api,
         str,
         str_alloc,
         stringify,
+        stringify_macro,
         struct_field_attributes,
         struct_inherit,
         struct_variant,
         then_with,
         thread,
         thread_local,
+        thread_local_macro,
+        thumb2,
+        thumb_mode: "thumb-mode",
+        todo_macro,
         tool_attributes,
         tool_lints,
         trace_macros,
         underscore_imports,
         underscore_lifetimes,
         uniform_paths,
+        unimplemented_macro,
         unit,
         universal_impl_trait,
         unix,
         unpin,
         unreachable,
         unreachable_code,
+        unreachable_macro,
         unrestricted_attribute_tokens,
         unsafe_block_in_unsafe_fn,
         unsafe_cell,
         var,
         variant_count,
         vec,
+        vec_macro,
         version,
+        vfp2,
         vis,
         visible_private_types,
         volatile,
         wrapping_sub,
         wreg,
         write_bytes,
+        write_macro,
         write_str,
+        writeln_macro,
         x87_reg,
         xer,
         xmm_reg,
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 1f38240ee41461b4832d92b2156ae01112b0a584..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)
     };
index c2519adcbe416c53f8f177b2666312868f318f7f..0d51f7779e18f8844a284007f1a278b7709c69f2 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(
@@ -561,7 +559,10 @@ fn print_dyn_existential(
                         let name = cx.tcx.associated_item(projection.item_def_id).ident;
                         cx.push("p");
                         cx.push_ident(name.as_str());
-                        cx = projection.ty.print(cx)?;
+                        cx = match projection.term {
+                            ty::Term::Ty(ty) => ty.print(cx),
+                            ty::Term::Const(c) => c.print(cx),
+                        }?;
                     }
                     ty::ExistentialPredicate::AutoTrait(def_id) => {
                         cx = cx.print_def_path(*def_id, &[])?;
@@ -771,9 +772,9 @@ fn path_append(
         disambiguated_data: &DisambiguatedDefPathData,
     ) -> Result<Self::Path, Self::Error> {
         let ns = match disambiguated_data.data {
-            // FIXME: It shouldn't be necessary to add anything for extern block segments,
-            // but we add 't' for backward compatibility.
-            DefPathData::ForeignMod => 't',
+            // Extern block segments can be skipped, names from extern blocks
+            // are effectively living in their parent modules.
+            DefPathData::ForeignMod => return print_prefix(self),
 
             // Uppercase categories are more stable than lowercase ones.
             DefPathData::TypeNs(_) => 't',
index 4bf909ce46d257955a319c518726ae605b1cba26..da875508676d4cd489234aaec7c282bd02a82dac 100644 (file)
@@ -1,6 +1,8 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -58,11 +60,11 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => types! { _: I8, I16, I32, I64, F32, F64; },
             Self::vreg | Self::vreg_low16 => types! {
-                "fp": I8, I16, I32, I64, F32, F64,
+                fp: I8, I16, I32, I64, F32, F64,
                     VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2), VecF64(1),
                     VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
             },
@@ -73,7 +75,7 @@ pub fn supported_types(
 
 pub fn reserved_x18(
     _arch: InlineAsmArch,
-    _has_feature: impl FnMut(&str) -> bool,
+    _target_features: &FxHashSet<Symbol>,
     target: &Target,
 ) -> Result<(), &'static str> {
     if target.os == "android"
index b03594b3151a3788a54f5296b0d105b850c39ef5..e3615b43c70eba508b11cc8e903a5f044117a327 100644 (file)
@@ -1,6 +1,8 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_macros::HashStable_Generic;
+use rustc_span::{sym, Symbol};
 use std::fmt;
 
 def_reg_class! {
@@ -44,31 +46,31 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => types! { _: I8, I16, I32, F32; },
-            Self::sreg | Self::sreg_low16 => types! { "vfp2": I32, F32; },
+            Self::sreg | Self::sreg_low16 => types! { vfp2: I32, F32; },
             Self::dreg | Self::dreg_low16 | Self::dreg_low8 => types! {
-                "vfp2": I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
+                vfp2: I64, F64, VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2);
             },
             Self::qreg | Self::qreg_low8 | Self::qreg_low4 => types! {
-                "neon": VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4);
+                neon: VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4);
             },
         }
     }
 }
 
 // This uses the same logic as useR7AsFramePointer in LLVM
-fn frame_pointer_is_r7(mut has_feature: impl FnMut(&str) -> bool, target: &Target) -> bool {
-    target.is_like_osx || (!target.is_like_windows && has_feature("thumb-mode"))
+fn frame_pointer_is_r7(target_features: &FxHashSet<Symbol>, target: &Target) -> bool {
+    target.is_like_osx || (!target.is_like_windows && target_features.contains(&sym::thumb_mode))
 }
 
 fn frame_pointer_r11(
     _arch: InlineAsmArch,
-    has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     target: &Target,
 ) -> Result<(), &'static str> {
-    if !frame_pointer_is_r7(has_feature, target) {
+    if !frame_pointer_is_r7(target_features, target) {
         Err("the frame pointer (r11) cannot be used as an operand for inline asm")
     } else {
         Ok(())
@@ -77,10 +79,10 @@ fn frame_pointer_r11(
 
 fn frame_pointer_r7(
     _arch: InlineAsmArch,
-    has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     target: &Target,
 ) -> Result<(), &'static str> {
-    if frame_pointer_is_r7(has_feature, target) {
+    if frame_pointer_is_r7(target_features, target) {
         Err("the frame pointer (r7) cannot be used as an operand for inline asm")
     } else {
         Ok(())
@@ -89,10 +91,10 @@ fn frame_pointer_r7(
 
 fn not_thumb1(
     _arch: InlineAsmArch,
-    mut has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
-    if has_feature("thumb-mode") && !has_feature("thumb2") {
+    if target_features.contains(&sym::thumb_mode) && !target_features.contains(&sym::thumb2) {
         Err("high registers (r8+) cannot be used in Thumb-1 code")
     } else {
         Ok(())
@@ -101,14 +103,14 @@ fn not_thumb1(
 
 fn reserved_r9(
     arch: InlineAsmArch,
-    mut has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     target: &Target,
 ) -> Result<(), &'static str> {
-    not_thumb1(arch, &mut has_feature, target)?;
+    not_thumb1(arch, target_features, target)?;
 
     // We detect this using the reserved-r9 feature instead of using the target
     // because the relocation model can be changed with compiler options.
-    if has_feature("reserved-r9") {
+    if target_features.contains(&sym::reserved_r9) {
         Err("the RWPI static base register (r9) cannot be used as an operand for inline asm")
     } else {
         Ok(())
index 82a4f8bacb3fadbd887283529adae08062ac57e9..9a96a61f5b2cdccb976ed6bfb8b9190917645146 100644 (file)
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -39,7 +40,7 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => types! { _: I8; },
             Self::reg_upper => types! { _: I8; },
index ecb6bdc95ce0991b13573983f431e1b83ecdc0e0..d94fcb53e24c9fcd62930cb3da118856ac4eba44 100644 (file)
@@ -1,5 +1,7 @@
 use super::{InlineAsmArch, InlineAsmType, Target};
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_macros::HashStable_Generic;
+use rustc_span::{sym, Symbol};
 use std::fmt;
 
 def_reg_class! {
@@ -33,20 +35,20 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => types! { _: I8, I16, I32, I64; },
-            Self::wreg => types! { "alu32": I8, I16, I32; },
+            Self::wreg => types! { alu32: I8, I16, I32; },
         }
     }
 }
 
 fn only_alu32(
     _arch: InlineAsmArch,
-    mut has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
-    if !has_feature("alu32") {
+    if !target_features.contains(&sym::alu32) {
         Err("register can't be used without the `alu32` target feature")
     } else {
         Ok(())
index 74afddb69dc753461abb81fe71d64a24cd58b19f..d20270ac9e95a111b5dc2f55089cf06996281210 100644 (file)
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -32,7 +33,7 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => types! { _: I8, I16, I32, F32; },
         }
index b19489aa439bf54ddcb27cbbd52baca70c503f1f..b1e8737b52b90a45d0ecc3d49615d0f292518697 100644 (file)
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -33,7 +34,7 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match (self, arch) {
             (Self::reg, InlineAsmArch::Mips64) => types! { _: I8, I16, I32, I64, F32, F64; },
             (Self::reg, _) => types! { _: I8, I16, I32, F32; },
index 9128e54682f3dbba83ed26923de8b44bb26c444f..6b82bb337e6c1fd68a70876ecbccf31b79f89c1a 100644 (file)
@@ -81,14 +81,14 @@ pub fn reg_class(self) -> $arch_regclass {
 
             pub fn parse(
                 _arch: super::InlineAsmArch,
-                mut _has_feature: impl FnMut(&str) -> bool,
+                _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
                 _target: &crate::spec::Target,
                 name: &str,
             ) -> Result<Self, &'static str> {
                 match name {
                     $(
                         $($alias)|* | $reg_name => {
-                            $($filter(_arch, &mut _has_feature, _target)?;)?
+                            $($filter(_arch, _target_features, _target)?;)?
                             Ok(Self::$reg)
                         }
                     )*
@@ -102,7 +102,7 @@ pub fn parse(
 
         pub(super) fn fill_reg_map(
             _arch: super::InlineAsmArch,
-            mut _has_feature: impl FnMut(&str) -> bool,
+            _target_features: &rustc_data_structures::fx::FxHashSet<Symbol>,
             _target: &crate::spec::Target,
             _map: &mut rustc_data_structures::fx::FxHashMap<
                 super::InlineAsmRegClass,
@@ -112,7 +112,7 @@ pub(super) fn fill_reg_map(
             #[allow(unused_imports)]
             use super::{InlineAsmReg, InlineAsmRegClass};
             $(
-                if $($filter(_arch, &mut _has_feature, _target).is_ok() &&)? true {
+                if $($filter(_arch, _target_features, _target).is_ok() &&)? true {
                     if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
                         set.insert(InlineAsmReg::$arch($arch_reg::$reg));
                     }
@@ -130,7 +130,7 @@ pub(super) fn fill_reg_map(
 macro_rules! types {
     (
         $(_ : $($ty:expr),+;)?
-        $($feature:literal: $($ty2:expr),+;)*
+        $($feature:ident: $($ty2:expr),+;)*
     ) => {
         {
             use super::InlineAsmType::*;
@@ -139,7 +139,7 @@ macro_rules! types {
                     ($ty, None),
                 )*)?
                 $($(
-                    ($ty2, Some($feature)),
+                    ($ty2, Some(rustc_span::sym::$feature)),
                 )*)*
             ]
         }
@@ -289,7 +289,7 @@ pub fn reg_class(self) -> InlineAsmRegClass {
 
     pub fn parse(
         arch: InlineAsmArch,
-        has_feature: impl FnMut(&str) -> bool,
+        target_features: &FxHashSet<Symbol>,
         target: &Target,
         name: Symbol,
     ) -> Result<Self, &'static str> {
@@ -298,43 +298,43 @@ pub fn parse(
         let name = name.as_str();
         Ok(match arch {
             InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
-                Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::X86(X86InlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Arm => {
-                Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::AArch64 => {
-                Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::AArch64(AArch64InlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
-                Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::RiscV(RiscVInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Nvptx64 => {
-                Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Nvptx(NvptxInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
-                Self::PowerPC(PowerPCInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::PowerPC(PowerPCInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Hexagon => {
-                Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Hexagon(HexagonInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
-                Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Mips(MipsInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::S390x => {
-                Self::S390x(S390xInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::S390x(S390xInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::SpirV => {
-                Self::SpirV(SpirVInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::SpirV(SpirVInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
-                Self::Wasm(WasmInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Wasm(WasmInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Bpf => {
-                Self::Bpf(BpfInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, name)?)
             }
             InlineAsmArch::Avr => {
-                Self::Avr(AvrInlineAsmReg::parse(arch, has_feature, target, name)?)
+                Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, name)?)
             }
         })
     }
@@ -510,7 +510,7 @@ pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::X86(r) => r.supported_types(arch),
             Self::Arm(r) => r.supported_types(arch),
@@ -695,73 +695,73 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 // falling back to an external assembler.
 pub fn allocatable_registers(
     arch: InlineAsmArch,
-    has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     target: &crate::spec::Target,
 ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
     match arch {
         InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
             let mut map = x86::regclass_map();
-            x86::fill_reg_map(arch, has_feature, target, &mut map);
+            x86::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Arm => {
             let mut map = arm::regclass_map();
-            arm::fill_reg_map(arch, has_feature, target, &mut map);
+            arm::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::AArch64 => {
             let mut map = aarch64::regclass_map();
-            aarch64::fill_reg_map(arch, has_feature, target, &mut map);
+            aarch64::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
             let mut map = riscv::regclass_map();
-            riscv::fill_reg_map(arch, has_feature, target, &mut map);
+            riscv::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Nvptx64 => {
             let mut map = nvptx::regclass_map();
-            nvptx::fill_reg_map(arch, has_feature, target, &mut map);
+            nvptx::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {
             let mut map = powerpc::regclass_map();
-            powerpc::fill_reg_map(arch, has_feature, target, &mut map);
+            powerpc::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Hexagon => {
             let mut map = hexagon::regclass_map();
-            hexagon::fill_reg_map(arch, has_feature, target, &mut map);
+            hexagon::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
             let mut map = mips::regclass_map();
-            mips::fill_reg_map(arch, has_feature, target, &mut map);
+            mips::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::S390x => {
             let mut map = s390x::regclass_map();
-            s390x::fill_reg_map(arch, has_feature, target, &mut map);
+            s390x::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::SpirV => {
             let mut map = spirv::regclass_map();
-            spirv::fill_reg_map(arch, has_feature, target, &mut map);
+            spirv::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {
             let mut map = wasm::regclass_map();
-            wasm::fill_reg_map(arch, has_feature, target, &mut map);
+            wasm::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Bpf => {
             let mut map = bpf::regclass_map();
-            bpf::fill_reg_map(arch, has_feature, target, &mut map);
+            bpf::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
         InlineAsmArch::Avr => {
             let mut map = avr::regclass_map();
-            avr::fill_reg_map(arch, has_feature, target, &mut map);
+            avr::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
     }
@@ -794,7 +794,7 @@ impl InlineAsmClobberAbi {
     /// clobber ABIs for the target.
     pub fn parse(
         arch: InlineAsmArch,
-        has_feature: impl FnMut(&str) -> bool,
+        target_features: &FxHashSet<Symbol>,
         target: &Target,
         name: Symbol,
     ) -> Result<Self, &'static [&'static str]> {
@@ -819,7 +819,7 @@ pub fn parse(
             },
             InlineAsmArch::AArch64 => match name {
                 "C" | "system" | "efiapi" => {
-                    Ok(if aarch64::reserved_x18(arch, has_feature, target).is_err() {
+                    Ok(if aarch64::reserved_x18(arch, target_features, target).is_err() {
                         InlineAsmClobberAbi::AArch64NoX18
                     } else {
                         InlineAsmClobberAbi::AArch64
index 43d16ae0f5d102a51db4d16691e503c8f1b7fc3f..8e1e91e7c5f1fec65ff83ac0b4d0dd3d5f221f14 100644 (file)
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 
 def_reg_class! {
     Nvptx NvptxInlineAsmRegClass {
@@ -33,7 +34,7 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg16 => types! { _: I8, I16; },
             Self::reg32 => types! { _: I8, I16, I32, F32; },
index 51a4303689e67f64a39de6bf08fa9c7de0ab97cb..d3ccb30350a27dd3be00e6e678397f6876e5cada 100644 (file)
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -36,7 +37,7 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg | Self::reg_nonzero => {
                 if arch == InlineAsmArch::PowerPC {
index 314bd01de12278f480cc85868e5555048bce9b44..39644d232badbfc923c5328fe6f5b5af90b12ea4 100644 (file)
@@ -1,6 +1,8 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_macros::HashStable_Generic;
+use rustc_span::{sym, Symbol};
 use std::fmt;
 
 def_reg_class! {
@@ -35,7 +37,7 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => {
                 if arch == InlineAsmArch::RiscV64 {
@@ -44,7 +46,7 @@ pub fn supported_types(
                     types! { _: I8, I16, I32, F32; }
                 }
             }
-            Self::freg => types! { "f": F32; "d": F64; },
+            Self::freg => types! { f: F32; d: F64; },
             Self::vreg => &[],
         }
     }
@@ -52,10 +54,10 @@ pub fn supported_types(
 
 fn not_e(
     _arch: InlineAsmArch,
-    mut has_feature: impl FnMut(&str) -> bool,
+    target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
-    if has_feature("e") {
+    if target_features.contains(&sym::e) {
         Err("register can't be used with the `e` target feature")
     } else {
         Ok(())
index a74873f17476ea4d9f96ddc8c9c1a9dd211be751..0a50064f58755cea2844589c0854ac4031d8d00c 100644 (file)
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -33,7 +34,7 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match (self, arch) {
             (Self::reg, _) => types! { _: I8, I16, I32, I64; },
             (Self::freg, _) => types! { _: F32, F64; },
index da82749e96a16704719374cbe2fdafc23045aa69..31073da10b21b5b153b81c20067a2f30883a2cac 100644 (file)
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 
 def_reg_class! {
     SpirV SpirVInlineAsmRegClass {
@@ -31,7 +32,7 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg => {
                 types! { _: I8, I16, I32, I64, F32, F64; }
index 1b33f8f96326deedadf320aaee0dd6222c2ce17e..f095b7c6e118ca9010b058c9fa16d06f571d1530 100644 (file)
@@ -1,5 +1,6 @@
 use super::{InlineAsmArch, InlineAsmType};
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 
 def_reg_class! {
     Wasm WasmInlineAsmRegClass {
@@ -31,7 +32,7 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
     pub fn supported_types(
         self,
         _arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::local => {
                 types! { _: I8, I16, I32, I64, F32, F64; }
index 5e3828d7d8521063be64bf93c632b098f9460f53..01d32570f78a2cc28b2c6200ffea4d57adec5c7d 100644 (file)
@@ -1,6 +1,8 @@
 use super::{InlineAsmArch, InlineAsmType};
 use crate::spec::Target;
+use rustc_data_structures::stable_set::FxHashSet;
 use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
 use std::fmt;
 
 def_reg_class! {
@@ -101,7 +103,7 @@ pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str
     pub fn supported_types(
         self,
         arch: InlineAsmArch,
-    ) -> &'static [(InlineAsmType, Option<&'static str>)] {
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
         match self {
             Self::reg | Self::reg_abcd => {
                 if arch == InlineAsmArch::X86_64 {
@@ -112,23 +114,23 @@ pub fn supported_types(
             }
             Self::reg_byte => types! { _: I8; },
             Self::xmm_reg => types! {
-                "sse": I32, I64, F32, F64,
+                sse: I32, I64, F32, F64,
                   VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
             },
             Self::ymm_reg => types! {
-                "avx": I32, I64, F32, F64,
+                avx: I32, I64, F32, F64,
                     VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2),
                     VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4);
             },
             Self::zmm_reg => types! {
-                "avx512f": I32, I64, F32, F64,
+                avx512f: I32, I64, F32, F64,
                     VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2),
                     VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4),
                     VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF32(16), VecF64(8);
             },
             Self::kreg => types! {
-                "avx512f": I8, I16;
-                "avx512bw": I32, I64;
+                avx512f: I8, I16;
+                avx512bw: I32, I64;
             },
             Self::mmx_reg | Self::x87_reg => &[],
         }
@@ -137,7 +139,7 @@ pub fn supported_types(
 
 fn x86_64_only(
     arch: InlineAsmArch,
-    _has_feature: impl FnMut(&str) -> bool,
+    _target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
     match arch {
@@ -149,7 +151,7 @@ fn x86_64_only(
 
 fn high_byte(
     arch: InlineAsmArch,
-    _has_feature: impl FnMut(&str) -> bool,
+    _target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
     match arch {
@@ -160,7 +162,7 @@ fn high_byte(
 
 fn rbx_reserved(
     arch: InlineAsmArch,
-    _has_feature: impl FnMut(&str) -> bool,
+    _target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
     match arch {
@@ -174,7 +176,7 @@ fn rbx_reserved(
 
 fn esi_reserved(
     arch: InlineAsmArch,
-    _has_feature: impl FnMut(&str) -> bool,
+    _target_features: &FxHashSet<Symbol>,
     _target: &Target,
 ) -> Result<(), &'static str> {
     match arch {
index afe8bbb352886a214d1b8bb7f3fd3c3d130b6000..3e3a6ac82a439ba80e2be3dd44afa4d6219c1b63 100644 (file)
@@ -36,6 +36,7 @@ pub fn target() -> Target {
             features: "+vfp2".to_string(),
             pre_link_args,
             exe_suffix: ".elf".to_string(),
+            no_default_libraries: false,
             ..Default::default()
         },
     }
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 ca1949b9f75a3668de55bc9b49b68f93a161997d..2c149318730eeacf694c687c963508279b3c0de0 100644 (file)
@@ -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 05d2a373dc6390977b0659d2037b0d34b8450d6c..f2ed5ae26a3c268569cf3174c25ef9d77e04407a 100644 (file)
@@ -6,7 +6,7 @@
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::InferCtxt;
 use rustc_middle::ty::fold::TypeFolder;
-use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::ty::{Region, RegionVid, Term};
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 
@@ -606,7 +606,11 @@ pub fn is_of_param(&self, ty: Ty<'_>) -> bool {
     }
 
     fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
-        matches!(*p.ty().skip_binder().kind(), ty::Projection(proj) if proj == p.skip_binder().projection_ty)
+        if let Term::Ty(ty) = p.term().skip_binder() {
+            matches!(ty.kind(), ty::Projection(proj) if proj == &p.skip_binder().projection_ty)
+        } else {
+            false
+        }
     }
 
     fn evaluate_nested_obligations(
@@ -663,7 +667,7 @@ fn evaluate_nested_obligations(
                     // Additionally, we check if we've seen this predicate before,
                     // to avoid rendering duplicate bounds to the user.
                     if self.is_param_no_infer(p.skip_binder().projection_ty.substs)
-                        && !p.ty().skip_binder().has_infer_types()
+                        && !p.term().skip_binder().has_infer_types()
                         && is_new_pred
                     {
                         debug!(
@@ -752,7 +756,7 @@ fn evaluate_nested_obligations(
                             // when we started out trying to unify
                             // some inference variables. See the comment above
                             // for more infomration
-                            if p.ty().skip_binder().has_infer_types() {
+                            if p.term().skip_binder().has_infer_types() {
                                 if !self.evaluate_nested_obligations(
                                     ty,
                                     v.into_iter(),
@@ -774,7 +778,7 @@ fn evaluate_nested_obligations(
                             // However, we should always make progress (either by generating
                             // subobligations or getting an error) when we started off with
                             // inference variables
-                            if p.ty().skip_binder().has_infer_types() {
+                            if p.term().skip_binder().has_infer_types() {
                                 panic!("Unexpected result when selecting {:?} {:?}", ty, obligation)
                             }
                         }
index 290426aa8278704b7b886fd299317e5c74a21eb6..af3540386f9fc71fdde9b4c9f4f8bce51575db35 100644 (file)
@@ -53,6 +53,7 @@ pub fn add_placeholder_note(err: &mut rustc_errors::DiagnosticBuilder<'_>) {
 /// If there are types that satisfy both impls, invokes `on_overlap`
 /// with a suitably-freshened `ImplHeader` with those types
 /// substituted. Otherwise, invokes `no_overlap`.
+#[instrument(skip(tcx, skip_leak_check, on_overlap, no_overlap), level = "debug")]
 pub fn overlapping_impls<F1, F2, R>(
     tcx: TyCtxt<'_>,
     impl1_def_id: DefId,
@@ -65,12 +66,6 @@ pub fn overlapping_impls<F1, F2, R>(
     F1: FnOnce(OverlapResult<'_>) -> R,
     F2: FnOnce() -> R,
 {
-    debug!(
-        "overlapping_impls(\
-           impl1_def_id={:?}, \
-           impl2_def_id={:?})",
-        impl1_def_id, impl2_def_id,
-    );
     // Before doing expensive operations like entering an inference context, do
     // a quick check via fast_reject to tell if the impl headers could possibly
     // unify.
@@ -85,6 +80,7 @@ pub fn overlapping_impls<F1, F2, R>(
     .any(|(ty1, ty2)| {
         let t1 = fast_reject::simplify_type(tcx, ty1, SimplifyParams::No, StripReferences::No);
         let t2 = fast_reject::simplify_type(tcx, ty2, SimplifyParams::No, StripReferences::No);
+
         if let (Some(t1), Some(t2)) = (t1, t2) {
             // Simplified successfully
             t1 != t2
@@ -444,7 +440,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..96a944017bc2406b375fd18cd5c9273b2da0c279 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 {
@@ -480,7 +479,7 @@ fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorReported>
             // let expressions imply control flow
             ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } =>
                 self.error(node.span, "control flow is not supported in generic constants")?,
-            ExprKind::LlvmInlineAsm { .. } | ExprKind::InlineAsm { .. } => {
+            ExprKind::InlineAsm { .. } => {
                 self.error(node.span, "assembly is not supported in generic constants")?
             }
 
index a9ae0ec53c7e78283275b2e27902533cf217d44c..0760f62685127a26354cb0dadd02f25c927a591d 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))) => {
@@ -1302,7 +1304,7 @@ fn report_projection_error(
 
                 debug!(
                     "report_projection_error normalized_ty={:?} data.ty={:?}",
-                    normalized_ty, data.ty
+                    normalized_ty, data.term,
                 );
 
                 let is_normalized_ty_expected = !matches!(
@@ -1312,16 +1314,17 @@ fn report_projection_error(
                         | ObligationCauseCode::ObjectCastObligation(_)
                         | ObligationCauseCode::OpaqueType
                 );
-
+                // FIXME(associated_const_equality): Handle Consts here
+                let data_ty = data.term.ty().unwrap();
                 if let Err(error) = self.at(&obligation.cause, obligation.param_env).eq_exp(
                     is_normalized_ty_expected,
                     normalized_ty,
-                    data.ty,
+                    data_ty,
                 ) {
                     values = Some(infer::ValuePairs::Types(ExpectedFound::new(
                         is_normalized_ty_expected,
                         normalized_ty,
-                        data.ty,
+                        data_ty,
                     )));
 
                     err_buf = error;
@@ -1801,11 +1804,11 @@ fn maybe_report_ambiguity(
             }
             ty::PredicateKind::Projection(data) => {
                 let self_ty = data.projection_ty.self_ty();
-                let ty = data.ty;
+                let term = data.term;
                 if predicate.references_error() || self.is_tainted_by_errors() {
                     return;
                 }
-                if self_ty.needs_infer() && ty.needs_infer() {
+                if self_ty.needs_infer() && term.needs_infer() {
                     // We do this for the `foo.collect()?` case to produce a suggestion.
                     let mut err = self.emit_inference_failure_err(
                         body_id,
@@ -2182,12 +2185,6 @@ struct FindTypeParam {
 }
 
 impl<'v> Visitor<'v> for FindTypeParam {
-    type Map = rustc_hir::intravisit::ErasedMap<'v>;
-
-    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
-        hir::intravisit::NestedVisitorMap::None
-    }
-
     fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
         // Skip where-clauses, to avoid suggesting indirection for type parameters found there.
     }
@@ -2247,7 +2244,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..da0b691a958e199659175b93866dfc7da200f88f 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),
@@ -2519,12 +2519,6 @@ pub struct ReturnsVisitor<'v> {
 }
 
 impl<'v> Visitor<'v> for ReturnsVisitor<'v> {
-    type Map = hir::intravisit::ErasedMap<'v>;
-
-    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
-        hir::intravisit::NestedVisitorMap::None
-    }
-
     fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
         // Visit every expression to detect `return` paths, either through the function's tail
         // expression or `return` statements. We walk all nodes to find `return` statements, but
@@ -2581,12 +2575,6 @@ struct AwaitsVisitor {
 }
 
 impl<'v> Visitor<'v> for AwaitsVisitor {
-    type Map = hir::intravisit::ErasedMap<'v>;
-
-    fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
-        hir::intravisit::NestedVisitorMap::None
-    }
-
     fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
         if let hir::ExprKind::Yield(_, hir::YieldSource::Await { expr: Some(id) }) = ex.kind {
             self.awaits.push(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..7bfedecbdc7c9b240c4d7a014c8093000f7b2118 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.
@@ -571,7 +571,7 @@ fn object_ty_for_trait<'tcx>(
         // `trait MyTrait: for<'s> OtherTrait<&'s T, Output=bool>`.
         super_trait_ref.map_bound(|super_trait_ref| {
             ty::ExistentialPredicate::Projection(ty::ExistentialProjection {
-                ty: tcx.mk_projection(item.def_id, super_trait_ref.substs),
+                term: tcx.mk_projection(item.def_id, super_trait_ref.substs).into(),
                 item_def_id: item.def_id,
                 substs: super_trait_ref.substs,
             })
@@ -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 51bd505366c778e5b37fcfdbe29d3b802887fe55..f49f53351aac8dc6a129eea5683a3fa095ec2811 100644 (file)
@@ -212,10 +212,9 @@ fn project_and_unify_type<'cx, 'tcx>(
     debug!(?normalized_ty, ?obligations, "project_and_unify_type result");
 
     let infcx = selcx.infcx();
-    match infcx
-        .at(&obligation.cause, obligation.param_env)
-        .eq(normalized_ty, obligation.predicate.ty)
-    {
+    // FIXME(associated_const_equality): Handle consts here as well as types.
+    let obligation_pred_ty = obligation.predicate.term.ty().unwrap();
+    match infcx.at(&obligation.cause, obligation.param_env).eq(normalized_ty, obligation_pred_ty) {
         Ok(InferOk { obligations: inferred_obligations, value: () }) => {
             obligations.extend(inferred_obligations);
             Ok(Ok(Some(obligations)))
@@ -1225,6 +1224,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 +1236,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 +1271,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 +1400,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 +1444,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(..) => {
@@ -1600,7 +1614,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
                 substs: trait_ref.substs,
                 item_def_id: obligation.predicate.item_def_id,
             },
-            ty,
+            term: ty.into(),
         }
     });
 
@@ -1626,7 +1640,7 @@ fn confirm_discriminant_kind_candidate<'cx, 'tcx>(
 
     let predicate = ty::ProjectionPredicate {
         projection_ty: ty::ProjectionTy { substs, item_def_id: discriminant_def_id },
-        ty: self_ty.discriminant_ty(tcx),
+        term: self_ty.discriminant_ty(tcx).into(),
     };
 
     // We get here from `poly_project_and_unify_type` which replaces bound vars
@@ -1640,18 +1654,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),
+        term: metadata_ty.into(),
     };
 
     confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
+        .with_addl_obligations(obligations)
 }
 
 fn confirm_fn_pointer_candidate<'cx, 'tcx>(
@@ -1720,7 +1746,7 @@ fn confirm_callable_candidate<'cx, 'tcx>(
             substs: trait_ref.substs,
             item_def_id: fn_once_output_def_id,
         },
-        ty: ret_type,
+        term: ret_type.into(),
     });
 
     confirm_param_env_candidate(selcx, obligation, predicate, true)
@@ -1776,7 +1802,9 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
         Ok(InferOk { value: _, obligations }) => {
             nested_obligations.extend(obligations);
             assoc_ty_own_obligations(selcx, obligation, &mut nested_obligations);
-            Progress { ty: cache_entry.ty, obligations: nested_obligations }
+            // FIXME(associated_const_equality): Handle consts here as well? Maybe this progress type should just take
+            // a term instead.
+            Progress { ty: cache_entry.term.ty().unwrap(), obligations: nested_obligations }
         }
         Err(e) => {
             let msg = format!(
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 e0098cc92d51569ac0509b08e34024fca73648b1..aea44841b8f128b9345c128c2019b9155d221199 100644 (file)
@@ -62,7 +62,7 @@ pub(crate) fn update<'tcx, T>(
     if let ty::PredicateKind::Projection(predicate) = obligation.predicate.kind().skip_binder() {
         // If the projection predicate (Foo::Bar == X) has X as a non-TyVid,
         // we need to make it into one.
-        if let Some(vid) = predicate.ty.ty_vid() {
+        if let Some(vid) = predicate.term.ty().and_then(|ty| ty.ty_vid()) {
             debug!("relationship: {:?}.output = true", vid);
             engine.relationships().entry(vid).or_default().output = true;
         }
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..669b6023397ee03f7f253601b51c6ac2ddcf534f 100644 (file)
@@ -206,7 +206,9 @@ fn confirm_projection_candidate(
             })?);
 
             if let ty::Projection(..) = placeholder_self_ty.kind() {
-                for predicate in tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates {
+                let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs).predicates;
+                debug!(?predicates, "projection predicates");
+                for predicate in predicates {
                     let normalized = normalize_with_depth_to(
                         self,
                         obligation.param_env,
@@ -997,7 +999,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 +1008,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 ab732f510ff92c73d9c739485ac4f00d1388387b..195a4a4a653e182a20b9e86187064080d11393f2 100644 (file)
@@ -117,9 +117,8 @@ pub fn translate_substs<'a, 'tcx>(
 /// Specialization is determined by the sets of types to which the impls apply;
 /// `impl1` specializes `impl2` if it applies to a subset of the types `impl2` applies
 /// to.
+#[instrument(skip(tcx), level = "debug")]
 pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, DefId)) -> bool {
-    debug!("specializes({:?}, {:?})", impl1_def_id, impl2_def_id);
-
     // The feature gate should prevent introducing new specializations, but not
     // taking advantage of upstream ones.
     let features = tcx.features();
@@ -485,7 +484,7 @@ fn report_conflicting_impls(
     let mut types_without_default_bounds = FxHashSet::default();
     let sized_trait = tcx.lang_items().sized_trait();
 
-    if !substs.is_noop() {
+    if !substs.is_empty() {
         types_without_default_bounds.extend(substs.types());
         w.push('<');
         w.push_str(
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 72ffe9085cbe779069d17b908d36bf2435aa4c60..6a355b567e0916538d82ff32a3a7bcc8e5f89397 100644 (file)
@@ -116,7 +116,10 @@ pub fn predicate_obligations<'a, 'tcx>(
         }
         ty::PredicateKind::Projection(t) => {
             wf.compute_projection(t.projection_ty);
-            wf.compute(t.ty.into());
+            wf.compute(match t.term {
+                ty::Term::Ty(ty) => ty.into(),
+                ty::Term::Const(c) => c.into(),
+            })
         }
         ty::PredicateKind::WellFormed(arg) => {
             wf.compute(arg);
@@ -132,11 +135,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);
             }
         }
@@ -220,7 +222,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
             // projection coming from another associated type. See
             // `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() {
+            if let Some(ty::Projection(projection_ty)) = proj.term.ty().map(|ty| ty.kind()) {
                 if let Some(&impl_item_id) =
                     tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
                 {
@@ -429,7 +431,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() {
@@ -443,16 +445,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 cc07bfc50081646ddad396cc7c70de0c53c7467b..67d0ba39667d31127bb910d1283bace99b87356c 100644 (file)
@@ -226,13 +226,26 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq<RustInterner<'tcx>>>
     for rustc_middle::ty::ProjectionPredicate<'tcx>
 {
     fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::AliasEq<RustInterner<'tcx>> {
+        // FIXME(associated_const_equality): teach chalk about terms for alias eq.
         chalk_ir::AliasEq {
-            ty: self.ty.lower_into(interner),
+            ty: self.term.ty().unwrap().lower_into(interner),
             alias: self.projection_ty.lower_into(interner),
         }
     }
 }
 
+/*
+// FIXME(...): Where do I add this to Chalk? I can't find it in the rustc repo anywhere.
+impl<'tcx> LowerInto<'tcx, chalk_ir::Term<RustInterner<'tcx>>> for rustc_middle::ty::Term<'tcx> {
+  fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Term<RustInterner<'tcx>> {
+    match self {
+      ty::Term::Ty(ty) => ty.lower_into(interner).into(),
+      ty::Term::Const(c) => c.lower_into(interner).into(),
+    }
+  }
+}
+*/
+
 impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
     fn lower_into(self, interner: RustInterner<'tcx>) -> chalk_ir::Ty<RustInterner<'tcx>> {
         let int = |i| chalk_ir::TyKind::Scalar(chalk_ir::Scalar::Int(i));
@@ -651,7 +664,8 @@ fn lower_into(
                                 .mk_substs_trait(self_ty, predicate.substs)
                                 .lower_into(interner),
                         }),
-                        ty: predicate.ty.lower_into(interner),
+                        // FIXME(associated_const_equality): teach chalk about terms for alias eq.
+                        ty: predicate.term.ty().unwrap().lower_into(interner),
                     }),
                 ),
                 ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new(
@@ -787,7 +801,7 @@ fn lower_into(
             trait_bound: trait_ref.lower_into(interner),
             associated_ty_id: chalk_ir::AssocTypeId(self.projection_ty.item_def_id),
             parameters: own_substs.iter().map(|arg| arg.lower_into(interner)).collect(),
-            value: self.ty.lower_into(interner),
+            value: self.term.ty().unwrap().lower_into(interner),
         }
     }
 }
@@ -806,7 +820,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 +850,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 +866,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 +1084,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 => {
index a4d844e2eb8ccb4478a4a16f506b4e9a0633e7e9..09bfdabf4737357871a7fad22d2bfdd7f6f8577b 100644 (file)
@@ -85,7 +85,7 @@
                         chalk_ir::VariableKind::Lifetime,
                         chalk_ir::UniverseIndex { counter: ui.index() },
                     ),
-                    CanonicalVarKind::Const(_ui) => unimplemented!(),
+                    CanonicalVarKind::Const(_ui, _ty) => unimplemented!(),
                     CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(),
                 }),
             ),
                     chalk_ir::VariableKind::Lifetime => CanonicalVarKind::Region(
                         ty::UniverseIndex::from_usize(var.skip_kind().counter),
                     ),
-                    chalk_ir::VariableKind::Const(_) => CanonicalVarKind::Const(
-                        ty::UniverseIndex::from_usize(var.skip_kind().counter),
-                    ),
+                    // FIXME(compiler-errors): We don't currently have a way of turning
+                    // a Chalk ty back into a rustc ty, right?
+                    chalk_ir::VariableKind::Const(_) => todo!(),
                 };
                 CanonicalVarInfo { kind }
             })
index b1d47f6c29a21b81f8c9d4a2083b018e64f10e7f..781a639b09ebd0646b1e09e64d2ff961f52beebd 100644 (file)
@@ -1,8 +1,7 @@
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, TyCtxt};
 
 pub fn provide(providers: &mut ty::query::Providers) {
     *providers = ty::query::Providers {
@@ -53,8 +52,7 @@ fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
 
 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_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_) => {
@@ -125,115 +123,14 @@ fn associated_item_from_impl_item_ref(
         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
     };
 
-    let trait_item_def_id = impl_item_base_id(tcx, parent_def_id, impl_item_ref);
-
     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,
+        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,
     }
 }
-
-fn impl_item_base_id<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    parent_def_id: LocalDefId,
-    impl_item: &hir::ImplItemRef,
-) -> Option<DefId> {
-    let impl_trait_ref = tcx.impl_trait_ref(parent_def_id)?;
-
-    // If the trait reference itself is erroneous (so the compilation is going
-    // to fail), skip checking the items here -- the `impl_item` table in `tcx`
-    // isn't populated for such impls.
-    if impl_trait_ref.references_error() {
-        return None;
-    }
-
-    // Locate trait items
-    let associated_items = tcx.associated_items(impl_trait_ref.def_id);
-
-    // Match item against trait
-    let mut items = associated_items.filter_by_name(tcx, impl_item.ident, impl_trait_ref.def_id);
-
-    let mut trait_item = items.next()?;
-
-    let is_compatible = |ty: &&ty::AssocItem| match (ty.kind, &impl_item.kind) {
-        (ty::AssocKind::Const, hir::AssocItemKind::Const) => true,
-        (ty::AssocKind::Fn, hir::AssocItemKind::Fn { .. }) => true,
-        (ty::AssocKind::Type, hir::AssocItemKind::Type) => 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(&trait_item);
-
-    if !compatible_kind {
-        if let Some(ty_trait_item) = items.find(is_compatible) {
-            compatible_kind = true;
-            trait_item = ty_trait_item;
-        }
-    }
-
-    if compatible_kind {
-        Some(trait_item.def_id)
-    } else {
-        report_mismatch_error(tcx, trait_item.def_id, impl_trait_ref, impl_item);
-        None
-    }
-}
-
-#[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::ImplItemRef,
-) {
-    let mut err = match impl_item.kind {
-        hir::AssocItemKind::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 `{}`",
-                impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-
-        hir::AssocItemKind::Fn { .. } => {
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0324,
-                "item `{}` is an associated method, which doesn't match its trait `{}`",
-                impl_item.ident,
-                impl_trait_ref.print_only_trait_path()
-            )
-        }
-
-        hir::AssocItemKind::Type => {
-            struct_span_err!(
-                tcx.sess,
-                impl_item.span,
-                E0325,
-                "item `{}` is an associated type, which doesn't match its trait `{}`",
-                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();
-}
index e0aea786b837a26fb9edb33811d1bbef8cdc92f9..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>,
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 8f50e3e0fe1ca984883046c497e0687460d0439e..fef83190468196c32ee0257fb33c36aadd889724 100644 (file)
@@ -157,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));
 
@@ -279,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,
@@ -334,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
@@ -343,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 => (),
@@ -436,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);
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..b532c41642c6e88b814b41cc79e804ed0afad937 100644 (file)
@@ -93,62 +93,100 @@ 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 { term }) => {
+                            let span = match term {
+                                hir::Term::Ty(ty) => ty.span,
+                                hir::Term::Const(c) => self.tcx().hir().span(c.hir_id),
+                            };
+                            sess.source_map().span_to_snippet(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 8226ffbccc4316a53244c4facc3f6243cd0915ee..d9b3f51b5bd245834b86f14a69a7e6fde24e4051 100644 (file)
@@ -6,7 +6,7 @@
 mod generics;
 
 use crate::bounds::Bounds;
-use crate::collect::PlaceholderHirTyCollector;
+use crate::collect::HirPlaceholderCollector;
 use crate::errors::{
     AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits,
     TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified,
@@ -123,7 +123,7 @@ struct ConvertedBinding<'a, 'tcx> {
 
 #[derive(Debug)]
 enum ConvertedBindingKind<'a, 'tcx> {
-    Equality(Ty<'tcx>),
+    Equality(ty::Term<'tcx>),
     Constraint(&'a [hir::GenericBound<'a>]),
 }
 
@@ -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;
@@ -601,10 +601,17 @@ fn create_assoc_bindings_for_generic_args<'a>(
             .iter()
             .map(|binding| {
                 let kind = match binding.kind {
-                    hir::TypeBindingKind::Equality { ty } => {
-                        ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty))
-                    }
-                    hir::TypeBindingKind::Constraint { bounds } => {
+                    hir::TypeBindingKind::Equality { ref term } => match term {
+                        hir::Term::Ty(ref ty) => {
+                            ConvertedBindingKind::Equality(self.ast_ty_to_ty(ty).into())
+                        }
+                        hir::Term::Const(ref c) => {
+                            let local_did = self.tcx().hir().local_def_id(c.hir_id);
+                            let c = Const::from_anon_const(self.tcx(), local_did);
+                            ConvertedBindingKind::Equality(c.into())
+                        }
+                    },
+                    hir::TypeBindingKind::Constraint { ref bounds } => {
                         ConvertedBindingKind::Constraint(bounds)
                     }
                 };
@@ -669,6 +676,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 +773,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 +830,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 +853,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,
@@ -859,6 +874,17 @@ fn trait_defines_associated_type_named(&self, trait_def_id: DefId, assoc_name: I
             .find_by_name_and_kind(self.tcx(), assoc_name, ty::AssocKind::Type, trait_def_id)
             .is_some()
     }
+    fn trait_defines_associated_named(&self, trait_def_id: DefId, assoc_name: Ident) -> bool {
+        self.tcx()
+            .associated_items(trait_def_id)
+            .find_by_name_and_kinds(
+                self.tcx(),
+                assoc_name,
+                &[ty::AssocKind::Type, ty::AssocKind::Const],
+                trait_def_id,
+            )
+            .is_some()
+    }
 
     // Sets `implicitly_sized` to true on `Bounds` if necessary
     pub(crate) fn add_implicitly_sized<'hir>(
@@ -1110,9 +1136,18 @@ fn add_predicates_for_ast_type_binding(
             .associated_items(candidate.def_id())
             .filter_by_name_unhygienic(assoc_ident.name)
             .find(|i| {
-                i.kind == ty::AssocKind::Type && i.ident.normalize_to_macros_2_0() == assoc_ident
+                (i.kind == ty::AssocKind::Type || i.kind == ty::AssocKind::Const)
+                    && i.ident.normalize_to_macros_2_0() == assoc_ident
             })
             .expect("missing associated type");
+        // FIXME(associated_const_equality): need to handle assoc_consts here as well.
+        if assoc_ty.kind == ty::AssocKind::Const {
+            tcx.sess
+                .struct_span_err(path_span, &format!("associated const equality is incomplete"))
+                .span_label(path_span, "cannot yet relate associated const")
+                .emit();
+            return Err(ErrorReported);
+        }
 
         if !assoc_ty.vis.is_accessible_from(def_scope, tcx) {
             tcx.sess
@@ -1207,18 +1242,15 @@ fn add_predicates_for_ast_type_binding(
         }
 
         match binding.kind {
-            ConvertedBindingKind::Equality(ty) => {
+            ConvertedBindingKind::Equality(term) => {
                 // "Desugar" a constraint like `T: Iterator<Item = u32>` this to
                 // the "projection predicate" for:
                 //
                 // `<T as Iterator>::Item = u32`
                 bounds.projection_bounds.push((
-                    projection_ty.map_bound(|projection_ty| {
-                        debug!(
-                            "add_predicates_for_ast_type_binding: projection_ty {:?}, substs: {:?}",
-                            projection_ty, projection_ty.substs
-                        );
-                        ty::ProjectionPredicate { projection_ty, ty }
+                    projection_ty.map_bound(|projection_ty| ty::ProjectionPredicate {
+                        projection_ty,
+                        term: term,
                     }),
                     binding.span,
                 ));
@@ -1369,8 +1401,10 @@ trait here instead: `trait NewTrait: {} {{}}`",
                         let pred = bound_predicate.rebind(pred);
                         // 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());
+                        let references_self = match pred.skip_binder().term {
+                            ty::Term::Ty(ty) => ty.walk().any(|arg| arg == dummy_self.into()),
+                            ty::Term::Const(c) => c.ty.walk().any(|arg| arg == dummy_self.into()),
+                        };
 
                         // If the projection output contains `Self`, force the user to
                         // elaborate it explicitly to avoid a lot of complexity.
@@ -1593,7 +1627,7 @@ fn one_bound_for_assoc_type<I>(
         I: Iterator<Item = ty::PolyTraitRef<'tcx>>,
     {
         let mut matching_candidates = all_candidates()
-            .filter(|r| self.trait_defines_associated_type_named(r.def_id(), assoc_name));
+            .filter(|r| self.trait_defines_associated_named(r.def_id(), assoc_name));
 
         let bound = match matching_candidates.next() {
             Some(bound) => bound,
@@ -1727,7 +1761,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 +1820,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 +1940,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 +1966,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 +2251,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",
@@ -2469,7 +2504,7 @@ pub fn ty_of_fn(
         debug!(?bound_vars);
 
         // We proactively collect all the inferred type params to emit a single error per fn def.
-        let mut visitor = PlaceholderHirTyCollector::default();
+        let mut visitor = HirPlaceholderCollector::default();
         for ty in decl.inputs {
             visitor.visit_ty(ty);
         }
index 8bc3a48e5b506d4d406f02062893c2cff081b2b7..6a28bb16a20acf2945f940d3f376d957529c3adf 100644 (file)
@@ -48,14 +48,19 @@ impl<'tcx> Bounds<'tcx> {
     /// where-clauses). Because some of our bounds listings (e.g.,
     /// regions) don't include the self-type, you must supply the
     /// self-type here (the `param_ty` parameter).
-    pub fn predicates(
-        &self,
+    pub fn predicates<'out, 's>(
+        &'s self,
         tcx: TyCtxt<'tcx>,
         param_ty: Ty<'tcx>,
-    ) -> Vec<(ty::Predicate<'tcx>, Span)> {
+        // the output must live shorter than the duration of the borrow of self and 'tcx.
+    ) -> impl Iterator<Item = (ty::Predicate<'tcx>, Span)> + 'out
+    where
+        'tcx: 'out,
+        's: 'out,
+    {
         // If it could be sized, and is, add the `Sized` predicate.
         let sized_predicate = self.implicitly_sized.and_then(|span| {
-            tcx.lang_items().sized_trait().map(|sized| {
+            tcx.lang_items().sized_trait().map(move |sized| {
                 let trait_ref = ty::Binder::dummy(ty::TraitRef {
                     def_id: sized,
                     substs: tcx.mk_substs_trait(param_ty, &[]),
@@ -64,25 +69,22 @@ pub fn predicates(
             })
         });
 
-        sized_predicate
-            .into_iter()
-            .chain(self.region_bounds.iter().map(|&(region_bound, span)| {
-                (
-                    region_bound
-                        .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
-                        .to_predicate(tcx),
-                    span,
-                )
-            }))
-            .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| {
+        let region_preds = self.region_bounds.iter().map(move |&(region_bound, span)| {
+            let pred = region_bound
+                .map_bound(|region_bound| ty::OutlivesPredicate(param_ty, region_bound))
+                .to_predicate(tcx);
+            (pred, span)
+        });
+        let trait_bounds =
+            self.trait_bounds.iter().map(move |&(bound_trait_ref, span, constness)| {
                 let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx);
                 (predicate, span)
-            }))
-            .chain(
-                self.projection_bounds
-                    .iter()
-                    .map(|&(projection, span)| (projection.to_predicate(tcx), span)),
-            )
-            .collect()
+            });
+        let projection_bounds = self
+            .projection_bounds
+            .iter()
+            .map(move |&(projection, span)| (projection.to_predicate(tcx), span));
+
+        sized_predicate.into_iter().chain(region_preds).chain(trait_bounds).chain(projection_bounds)
     }
 }
index dcf42e1aefebc7457e176f1baa41cb09d01b7e39..eb49cc0233d835600a1937a35db002b98780a90d 100644 (file)
@@ -12,6 +12,7 @@
 use rustc_hir::{def::Res, ItemKind, Node, PathSegment};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::layout::MAX_SIMD_LANES;
 use rustc_middle::ty::subst::GenericArgKind;
@@ -462,17 +463,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,26 +500,23 @@ 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)
             }
         }
     }
 
     impl<'tcx> Visitor<'tcx> for ProhibitOpaqueVisitor<'tcx> {
-        type Map = rustc_middle::hir::map::Map<'tcx>;
+        type NestedFilter = nested_filter::OnlyBodies;
 
-        fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap<Self::Map> {
-            hir::intravisit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+        fn nested_visit_map(&mut self) -> Self::Map {
+            self.tcx.hir()
         }
 
         fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
@@ -626,6 +621,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 +629,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 +649,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 +670,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());
+            }
+        }
     });
 }
 
@@ -979,6 +978,10 @@ fn check_impl_items_against_trait<'tcx>(
     if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {
         // Check for missing items from trait
         let mut missing_items = Vec::new();
+
+        let mut must_implement_one_of: Option<&[Ident]> =
+            trait_def.must_implement_one_of.as_deref();
+
         for &trait_item_id in tcx.associated_item_def_ids(impl_trait_ref.def_id) {
             let is_implemented = ancestors
                 .leaf_def(tcx, trait_item_id)
@@ -987,12 +990,37 @@ fn check_impl_items_against_trait<'tcx>(
             if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
                 missing_items.push(tcx.associated_item(trait_item_id));
             }
+
+            if let Some(required_items) = &must_implement_one_of {
+                // true if this item is specifically implemented in this impl
+                let is_implemented_here = ancestors
+                    .leaf_def(tcx, trait_item_id)
+                    .map_or(false, |node_item| !node_item.defining_node.is_from_trait());
+
+                if is_implemented_here {
+                    let trait_item = tcx.associated_item(trait_item_id);
+                    if required_items.contains(&trait_item.ident) {
+                        must_implement_one_of = None;
+                    }
+                }
+            }
         }
 
         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);
         }
+
+        if let Some(missing_items) = must_implement_one_of {
+            let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span);
+            let attr_span = tcx
+                .get_attrs(impl_trait_ref.def_id)
+                .iter()
+                .find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
+                .map(|attr| attr.span);
+
+            missing_items_must_implement_one_of_err(tcx, impl_span, missing_items, attr_span);
+        }
     }
 }
 
@@ -1173,7 +1201,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);
                         }
                     }
@@ -1310,7 +1338,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),
@@ -1377,7 +1405,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);
@@ -1436,8 +1464,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()
@@ -1475,10 +1503,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 c87ab0d410cd9c61dd108dc6ad3012e360becd79..e88099afa03539ce855f6e40d2320a40c968677c 100644 (file)
@@ -279,7 +279,8 @@ fn deduce_sig_from_projection(
             return None;
         };
 
-        let ret_param_ty = projection.skip_binder().ty;
+        // Since this is a return parameter type it is safe to unwrap.
+        let ret_param_ty = projection.skip_binder().term.ty().unwrap();
         let ret_param_ty = self.resolve_vars_if_possible(ret_param_ty);
         debug!("deduce_sig_from_projection: ret_param_ty={:?}", ret_param_ty);
 
@@ -706,9 +707,10 @@ fn deduce_future_output_from_projection(
         // Extract the type from the projection. Note that there can
         // be no bound variables in this type because the "self type"
         // does not have any regions in it.
-        let output_ty = self.resolve_vars_if_possible(predicate.ty);
+        let output_ty = self.resolve_vars_if_possible(predicate.term);
         debug!("deduce_future_output_from_projection: output_ty={:?}", output_ty);
-        Some(output_ty)
+        // This is a projection on a Fn trait so will always be a type.
+        Some(output_ty.ty().unwrap())
     }
 
     /// Converts the types that the user supplied, in case that doing
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..94648d5702c89f81fffb3529510f7d34688e09d6 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 {
@@ -873,13 +881,6 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
                                     }
                                 }
                             }
-                            type Map = intravisit::ErasedMap<'v>;
-                            fn nested_visit_map(
-                                &mut self,
-                            ) -> intravisit::NestedVisitorMap<Self::Map>
-                            {
-                                intravisit::NestedVisitorMap::None
-                            }
                         }
                         let mut visitor = Visitor(None, impl_def_id);
                         for ty in input_tys {
@@ -1352,7 +1353,7 @@ pub fn check_type_bounds<'tcx>(
                             item_def_id: trait_ty.def_id,
                             substs: rebased_substs,
                         },
-                        ty: impl_ty_value,
+                        term: impl_ty_value.into(),
                     },
                     bound_vars,
                 )
index b7e276b69656f84d397f0c74e6d0f67f618868f8..241dcbc64a676bb35fe307dec5c4ceee2f73784c 100644 (file)
@@ -13,7 +13,7 @@
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut};
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{BytePos, Span};
 
 use super::method::probe;
@@ -24,16 +24,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub fn emit_coerce_suggestions(
         &self,
         err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
+        expr: &hir::Expr<'tcx>,
         expr_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
         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;
         }
@@ -110,7 +109,7 @@ pub fn demand_eqtype_with_origin(
 
     pub fn demand_coerce(
         &self,
-        expr: &hir::Expr<'_>,
+        expr: &hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -130,7 +129,7 @@ pub fn demand_coerce(
     /// will be permitted if the diverges flag is currently "always".
     pub fn demand_coerce_diag(
         &self,
-        expr: &hir::Expr<'_>,
+        expr: &hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -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(
@@ -356,31 +338,40 @@ fn suggest_compatible_variants(
                 })
                 .collect();
 
-            if let [variant] = &compatible_variants[..] {
-                // Just a single matching variant.
-                err.multipart_suggestion(
-                    &format!("try wrapping the expression in `{}`", variant),
-                    vec![
-                        (expr.span.shrink_to_lo(), format!("{}(", variant)),
-                        (expr.span.shrink_to_hi(), ")".to_string()),
-                    ],
-                    Applicability::MaybeIncorrect,
-                );
-            } else if compatible_variants.len() > 1 {
-                // More than one matching variant.
-                err.multipart_suggestions(
-                    &format!(
-                        "try wrapping the expression in a variant of `{}`",
-                        self.tcx.def_path_str(expected_adt.did)
-                    ),
-                    compatible_variants.into_iter().map(|variant| {
+            let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+                Some(ident) => format!("{}: ", ident),
+                None => format!(""),
+            };
+
+            match &compatible_variants[..] {
+                [] => { /* No variants to format */ }
+                [variant] => {
+                    // Just a single matching variant.
+                    err.multipart_suggestion_verbose(
+                        &format!("try wrapping the expression in `{}`", variant),
                         vec![
-                            (expr.span.shrink_to_lo(), format!("{}(", variant)),
+                            (expr.span.shrink_to_lo(), format!("{}{}(", prefix, variant)),
                             (expr.span.shrink_to_hi(), ")".to_string()),
-                        ]
-                    }),
-                    Applicability::MaybeIncorrect,
-                );
+                        ],
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                _ => {
+                    // More than one matching variant.
+                    err.multipart_suggestions(
+                        &format!(
+                            "try wrapping the expression in a variant of `{}`",
+                            self.tcx.def_path_str(expected_adt.did)
+                        ),
+                        compatible_variants.into_iter().map(|variant| {
+                            vec![
+                                (expr.span.shrink_to_lo(), format!("{}{}(", prefix, variant)),
+                                (expr.span.shrink_to_hi(), ")".to_string()),
+                            ]
+                        }),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
             }
         }
     }
@@ -501,33 +492,45 @@ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, St
         }
     }
 
-    crate fn is_hir_id_from_struct_pattern_shorthand_field(
+    crate fn maybe_get_struct_pattern_shorthand_field(
         &self,
-        hir_id: hir::HirId,
-        sp: Span,
-    ) -> bool {
-        let sm = self.sess().source_map();
-        let parent_id = self.tcx.hir().get_parent_node(hir_id);
-        if let Some(parent) = self.tcx.hir().find(parent_id) {
-            // Account for fields
-            if let Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) = parent
-            {
-                if let Ok(src) = sm.span_to_snippet(sp) {
-                    for field in *fields {
-                        if field.ident.as_str() == src && field.is_shorthand {
-                            return true;
-                        }
+        expr: &hir::Expr<'_>,
+    ) -> Option<Symbol> {
+        let hir = self.tcx.hir();
+        let local = match expr {
+            hir::Expr {
+                kind:
+                    hir::ExprKind::Path(hir::QPath::Resolved(
+                        None,
+                        hir::Path {
+                            res: hir::def::Res::Local(_),
+                            segments: [hir::PathSegment { ident, .. }],
+                            ..
+                        },
+                    )),
+                ..
+            } => Some(ident),
+            _ => None,
+        }?;
+
+        match hir.find(hir.get_parent_node(expr.hir_id))? {
+            Node::Expr(hir::Expr { kind: hir::ExprKind::Struct(_, fields, ..), .. }) => {
+                for field in *fields {
+                    if field.ident.name == local.name && field.is_shorthand {
+                        return Some(local.name);
                     }
                 }
             }
+            _ => {}
         }
-        false
+
+        None
     }
 
     /// If the given `HirId` corresponds to a block with a trailing expression, return that expression
-    crate fn maybe_get_block_expr(&self, hir_id: hir::HirId) -> Option<&'tcx hir::Expr<'tcx>> {
-        match self.tcx.hir().find(hir_id)? {
-            Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, ..), .. }) => block.expr,
+    crate fn maybe_get_block_expr(&self, expr: &hir::Expr<'tcx>) -> Option<&'tcx hir::Expr<'tcx>> {
+        match expr {
+            hir::Expr { kind: hir::ExprKind::Block(block, ..), .. } => block.expr,
             _ => None,
         }
     }
@@ -565,7 +568,7 @@ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, St
     /// `&mut`!".
     pub fn check_ref(
         &self,
-        expr: &hir::Expr<'_>,
+        expr: &hir::Expr<'tcx>,
         checked_ty: Ty<'tcx>,
         expected: Ty<'tcx>,
     ) -> Option<(Span, &'static str, String, Applicability, bool /* verbose */)> {
@@ -583,9 +586,6 @@ pub fn check_ref(
             s.strip_prefix(old).map(|stripped| new.to_string() + stripped)
         };
 
-        let is_struct_pat_shorthand_field =
-            self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp);
-
         // `ExprKind::DropTemps` is semantically irrelevant for these suggestions.
         let expr = expr.peel_drop_temps();
 
@@ -679,11 +679,12 @@ pub fn check_ref(
                                 false,
                             ));
                         }
-                        let field_name = if is_struct_pat_shorthand_field {
-                            format!("{}: ", sugg_expr)
-                        } else {
-                            String::new()
+
+                        let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+                            Some(ident) => format!("{}: ", ident),
+                            None => format!(""),
                         };
+
                         if let Some(hir::Node::Expr(hir::Expr {
                             kind: hir::ExprKind::Assign(left_expr, ..),
                             ..
@@ -713,14 +714,14 @@ pub fn check_ref(
                             hir::Mutability::Mut => (
                                 sp,
                                 "consider mutably borrowing here",
-                                format!("{}&mut {}", field_name, sugg_expr),
+                                format!("{}&mut {}", prefix, sugg_expr),
                                 Applicability::MachineApplicable,
                                 false,
                             ),
                             hir::Mutability::Not => (
                                 sp,
                                 "consider borrowing here",
-                                format!("{}&{}", field_name, sugg_expr),
+                                format!("{}&{}", prefix, sugg_expr),
                                 Applicability::MachineApplicable,
                                 false,
                             ),
@@ -857,36 +858,40 @@ 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`.
-                            if let Ok(code) = sm.span_to_snippet(expr.span) {
-                                let message = if checked_ty.is_region_ptr() {
-                                    "consider dereferencing the borrow"
-                                } else {
-                                    "consider dereferencing the type"
-                                };
-                                let (span, suggestion) = if is_struct_pat_shorthand_field {
-                                    (expr.span, format!("{}: *{}", code, code))
-                                } else if self.is_else_if_block(expr) {
-                                    // Don't suggest nonsense like `else *if`
-                                    return None;
-                                } else if let Some(expr) = self.maybe_get_block_expr(expr.hir_id) {
-                                    (expr.span.shrink_to_lo(), "*".to_string())
-                                } else {
-                                    (expr.span.shrink_to_lo(), "*".to_string())
-                                };
-                                return Some((
-                                    span,
-                                    message,
-                                    suggestion,
-                                    Applicability::MachineApplicable,
-                                    true,
-                                ));
-                            }
+                        }
+
+                        // 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()
+                        {
+                            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"
+                            };
+                            let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+                                Some(ident) => format!("{}: ", ident),
+                                None => format!(""),
+                            };
+                            let (span, suggestion) = if self.is_else_if_block(expr) {
+                                // Don't suggest nonsense like `else *if`
+                                return None;
+                            } else if let Some(expr) = self.maybe_get_block_expr(expr) {
+                                // prefix should be empty here..
+                                (expr.span.shrink_to_lo(), "*".to_string())
+                            } else {
+                                (expr.span.shrink_to_lo(), format!("{}*", prefix))
+                            };
+                            return Some((
+                                span,
+                                message,
+                                suggestion,
+                                Applicability::MachineApplicable,
+                                true,
+                            ));
                         }
                     }
                 }
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 621938c9b783d2b81f0f01e051017e1aa0acd4ab..f6abeff60cd9468427320a917d0e696abc18ea9f 100644 (file)
@@ -282,12 +282,6 @@ fn check_expr_kind(
             }
             ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]),
             ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
-            ExprKind::LlvmInlineAsm(asm) => {
-                for expr in asm.outputs_exprs.iter().chain(asm.inputs_exprs.iter()) {
-                    self.check_expr(expr);
-                }
-                tcx.mk_unit()
-            }
             ExprKind::Break(destination, ref expr_opt) => {
                 self.check_expr_break(destination, expr_opt.as_deref(), expr)
             }
@@ -742,7 +736,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 +745,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 +1220,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);
@@ -1376,7 +1370,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 +1451,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 +1471,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 +1658,7 @@ fn report_unknown_field(
                     "{} `{}::{}` has no field named `{}`",
                     kind_name,
                     actual,
-                    variant.ident,
+                    variant.name,
                     field.ident
                 ),
                 _ => struct_span_err!(
@@ -1680,15 +1673,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 +1692,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 +1735,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 +1770,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 +1790,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 +1829,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);
@@ -1913,10 +1909,15 @@ fn suggest_await_on_field_access(
             _ => return,
         };
         let mut add_label = true;
-        if let ty::Adt(def, _) = output_ty.kind() {
+        if let ty::Adt(def, _) = output_ty.skip_binder().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 +2076,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 +2263,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 +2272,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 1aca2911533ad0d8af297a55205011aca1bffe71..f01b8267817483bc86473d63d053a04c0c44b88e 100644 (file)
@@ -182,7 +182,7 @@ pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>)
         // `foo.bar::<u32>(...)` -- the `Self` type here will be the
         // type of `foo` (possibly adjusted), but we don't want to
         // include that. We want just the `[_, u32]` part.
-        if !method.substs.is_noop() {
+        if !method.substs.is_empty() {
             let method_generics = self.tcx.generics_of(method.def_id);
             if !method_generics.params.is_empty() {
                 let user_type_annotation = self.infcx.probe(|_| {
@@ -211,7 +211,7 @@ pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>)
     }
 
     pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) {
-        if !substs.is_noop() {
+        if !substs.is_empty() {
             debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag());
 
             self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs);
@@ -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);
@@ -541,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 e796fe58170d2e2bddaa87b7fdd111b248455c34..4d88feb65d17d4200f2955d6969009f8b25dcf2c 100644 (file)
@@ -846,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), .. }) => {
@@ -862,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))
     }
 
@@ -1036,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..be4c9ec99b9c68a093f24882b520ec5c4f1c75df 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};
@@ -208,7 +208,7 @@ fn suggest_fn_call(
     pub fn suggest_deref_ref_or_into(
         &self,
         err: &mut DiagnosticBuilder<'_>,
-        expr: &hir::Expr<'_>,
+        expr: &hir::Expr<'tcx>,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
@@ -231,7 +231,7 @@ pub fn suggest_deref_ref_or_into(
             }
         } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
             let is_struct_pat_shorthand_field =
-                self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span);
+                self.maybe_get_struct_pattern_shorthand_field(expr).is_some();
             let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
             if !methods.is_empty() {
                 if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
@@ -608,6 +608,21 @@ 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"
+                            )
+                        })
+                    })
+                    .skip_binder(),
+                hir::IsAsync::NotAsync => ty,
+            };
             if self.can_coerce(found, ty) {
                 err.multipart_suggestion(
                     "you might have meant to return this value",
index 839bd56b396ef1911b30a34635101bfa22c2130e..e30871e4347c14f99ecacc2f3b11bd9ded5878df 100644 (file)
@@ -1,6 +1,6 @@
 use crate::check::{FnCtxt, LocalTy, UserType};
 use rustc_hir as hir;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::PatKind;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::Ty;
@@ -98,12 +98,6 @@ fn declare(&mut self, decl: Declaration<'tcx>) {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     // Add explicitly-declared locals.
     fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) {
         self.declare(local.into());
index d54b1d62ee913b635a9c57b951e99d9647f839a8..fb6e11dbfb738499e5175276faabe7f2b6894c87 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::HirIdSet;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
 use rustc_middle::middle::region::{self, YieldData};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -266,12 +266,6 @@ pub fn resolve_interior<'a, 'tcx>(
 // librustc_middle/middle/region.rs since `expr_count` is compared against the results
 // there.
 impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) {
         let Arm { guard, pat, body, .. } = arm;
         self.visit_pat(pat);
@@ -439,12 +433,6 @@ struct ArmPatCollector<'a> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) {
         intravisit::walk_pat(self, pat);
         if let PatKind::Binding(_, id, ..) = pat.kind {
index 6314f2aba4efe2b4c166fa6595b7fe6be015eed0..4c612ed5be51a06db1c12823db92c6ddf8850a61 100644 (file)
@@ -453,7 +453,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         sym::simd_scatter => (3, vec![param(0), param(1), param(2)], tcx.mk_unit()),
         sym::simd_insert => (2, vec![param(0), tcx.types.u32, param(1)], param(0)),
         sym::simd_extract => (2, vec![param(0), tcx.types.u32], param(1)),
-        sym::simd_cast => (2, vec![param(0)], param(1)),
+        sym::simd_cast | sym::simd_as => (2, vec![param(0)], param(1)),
         sym::simd_bitmask => (2, vec![param(0)], param(1)),
         sym::simd_select | sym::simd_select_bitmask => {
             (2, vec![param(0), param(1), param(1)], param(1))
index dabfe92190b33ade90375e7742bca4c22da47513..27c39934ba8e9f66448ff6a3e81adc075e149dff 100644 (file)
@@ -149,7 +149,7 @@ fn adjust_self_ty(
         // time writing the results into the various typeck results.
         let mut autoderef =
             self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span);
-        let (_, n) = match autoderef.nth(pick.autoderefs) {
+        let (ty, n) = match autoderef.nth(pick.autoderefs) {
             Some(n) => n,
             None => {
                 return self.tcx.ty_error_with_message(
@@ -161,14 +161,15 @@ fn adjust_self_ty(
         assert_eq!(n, pick.autoderefs);
 
         let mut adjustments = self.adjust_steps(&autoderef);
+        let mut target = self.structurally_resolved_type(autoderef.span(), ty);
 
-        let mut target =
-            self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
-
-        match &pick.autoref_or_ptr_adjustment {
+        match pick.autoref_or_ptr_adjustment {
             Some(probe::AutorefOrPtrAdjustment::Autoref { mutbl, unsize }) => {
                 let region = self.next_region_var(infer::Autoref(self.span));
-                target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl: *mutbl, ty: target });
+                // Type we're wrapping in a reference, used later for unsizing
+                let base_ty = target;
+
+                target = self.tcx.mk_ref(region, ty::TypeAndMut { mutbl, ty: target });
                 let mutbl = match mutbl {
                     hir::Mutability::Not => AutoBorrowMutability::Not,
                     hir::Mutability::Mut => AutoBorrowMutability::Mut {
@@ -182,10 +183,18 @@ fn adjust_self_ty(
                     target,
                 });
 
-                if let Some(unsize_target) = unsize {
+                if unsize {
+                    let unsized_ty = if let ty::Array(elem_ty, _) = base_ty.kind() {
+                        self.tcx.mk_slice(elem_ty)
+                    } else {
+                        bug!(
+                            "AutorefOrPtrAdjustment's unsize flag should only be set for array ty, found {}",
+                            base_ty
+                        )
+                    };
                     target = self
                         .tcx
-                        .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsize_target });
+                        .mk_ref(region, ty::TypeAndMut { mutbl: mutbl.into(), ty: unsized_ty });
                     adjustments
                         .push(Adjustment { kind: Adjust::Pointer(PointerCast::Unsize), target });
                 }
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..86f3568d2e37aed310c10dbd2fb2e512e491bfd3 100644 (file)
@@ -167,26 +167,26 @@ enum ProbeResult {
 /// T`, we could convert it to `*const T`, then autoref to `&*const T`. However, currently we do
 /// (at most) one of these. Either the receiver has type `T` and we convert it to `&T` (or with
 /// `mut`), or it has type `*mut T` and we convert it to `*const T`.
-#[derive(Debug, PartialEq, Clone)]
-pub enum AutorefOrPtrAdjustment<'tcx> {
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub enum AutorefOrPtrAdjustment {
     /// Receiver has type `T`, add `&` or `&mut` (it `T` is `mut`), and maybe also "unsize" it.
     /// Unsizing is used to convert a `[T; N]` to `[T]`, which only makes sense when autorefing.
     Autoref {
         mutbl: hir::Mutability,
 
-        /// Indicates that the source expression should be "unsized" to a target type. This should
-        /// probably eventually go away in favor of just coercing method receivers.
-        unsize: Option<Ty<'tcx>>,
+        /// Indicates that the source expression should be "unsized" to a target type.
+        /// This is special-cased for just arrays unsizing to slices.
+        unsize: bool,
     },
     /// Receiver has type `*mut T`, convert to `*const T`
     ToConstPtr,
 }
 
-impl<'tcx> AutorefOrPtrAdjustment<'tcx> {
-    fn get_unsize(&self) -> Option<Ty<'tcx>> {
+impl AutorefOrPtrAdjustment {
+    fn get_unsize(&self) -> bool {
         match self {
             AutorefOrPtrAdjustment::Autoref { mutbl: _, unsize } => *unsize,
-            AutorefOrPtrAdjustment::ToConstPtr => None,
+            AutorefOrPtrAdjustment::ToConstPtr => false,
         }
     }
 }
@@ -204,7 +204,7 @@ pub struct Pick<'tcx> {
 
     /// Indicates that we want to add an autoref (and maybe also unsize it), or if the receiver is
     /// `*mut T`, convert it to `*const T`.
-    pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment<'tcx>>,
+    pub autoref_or_ptr_adjustment: Option<AutorefOrPtrAdjustment>,
     pub self_ty: Ty<'tcx>,
 }
 
@@ -1202,7 +1202,7 @@ fn pick_by_value_method(
                     pick.autoderefs += 1;
                     pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
                         mutbl,
-                        unsize: pick.autoref_or_ptr_adjustment.and_then(|a| a.get_unsize()),
+                        unsize: pick.autoref_or_ptr_adjustment.map_or(false, |a| a.get_unsize()),
                     })
                 }
 
@@ -1227,10 +1227,8 @@ fn pick_autorefd_method(
         self.pick_method(autoref_ty, unstable_candidates).map(|r| {
             r.map(|mut pick| {
                 pick.autoderefs = step.autoderefs;
-                pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
-                    mutbl,
-                    unsize: step.unsize.then_some(self_ty),
-                });
+                pick.autoref_or_ptr_adjustment =
+                    Some(AutorefOrPtrAdjustment::Autoref { mutbl, unsize: step.unsize });
                 pick
             })
         })
@@ -1915,7 +1913,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 1a6fcbc57bff20614c938fa84cb2a62fcc5fefc3..96ab800afaffed0f4738907e902c1ee78a19e42e 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) {
@@ -805,10 +789,10 @@ fn report_function<T: std::fmt::Display>(
                                     item_def_id: projection_ty.item_def_id,
                                 };
 
-                                let ty = pred.skip_binder().ty;
+                                let term = pred.skip_binder().term;
 
-                                let obligation = format!("{} = {}", projection_ty, ty);
-                                let quiet = format!("{} = {}", quiet_projection_ty, ty);
+                                let obligation = format!("{} = {}", projection_ty, term);
+                                let quiet = format!("{} = {}", quiet_projection_ty, term);
 
                                 bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
                                 Some((obligation, projection_ty.self_ty()))
@@ -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,
                     ) {
@@ -1290,7 +1274,7 @@ fn suggest_await_before_method(
         span: Span,
     ) {
         let output_ty = match self.infcx.get_impl_future_output_ty(ty) {
-            Some(output_ty) => self.resolve_vars_if_possible(output_ty),
+            Some(output_ty) => self.resolve_vars_if_possible(output_ty).skip_binder(),
             _ => return,
         };
         let method_exists = self.method_exists(item_name, output_ty, call.hir_id, true);
@@ -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 d576154ff9073b1952fca17ebcd53108c9104d9a..34caabe44d6d9a02e42a0c09ee4475c96f024184 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,
@@ -641,6 +637,31 @@ fn missing_items_err(
     err.emit();
 }
 
+fn missing_items_must_implement_one_of_err(
+    tcx: TyCtxt<'_>,
+    impl_span: Span,
+    missing_items: &[Ident],
+    annotation_span: Option<Span>,
+) {
+    let missing_items_msg =
+        missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
+
+    let mut err = struct_span_err!(
+        tcx.sess,
+        impl_span,
+        E0046,
+        "not all trait items implemented, missing one of: `{}`",
+        missing_items_msg
+    );
+    err.span_label(impl_span, format!("missing one of `{}` in implementation", missing_items_msg));
+
+    if let Some(annotation_span) = annotation_span {
+        err.span_note(annotation_span, "required because of this annotation");
+    }
+
+    err.emit();
+}
+
 /// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
 fn bounds_from_generic_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -695,7 +716,11 @@ fn bounds_from_generic_predicates<'tcx>(
         // insert the associated types where they correspond, but for now let's be "lazy" and
         // propose this instead of the following valid resugaring:
         // `T: Trait, Trait::Assoc = K` → `T: Trait<Assoc = K>`
-        where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.item_def_id), p.ty));
+        where_clauses.push(format!(
+            "{} = {}",
+            tcx.def_path_str(p.projection_ty.item_def_id),
+            p.term,
+        ));
     }
     let where_clauses = if where_clauses.is_empty() {
         String::new()
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..4e50fbf56b2d27bbddfd3e7d7a7bc18f80eec61c 100644 (file)
@@ -80,7 +80,7 @@
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::PatKind;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{self, InferCtxt, RegionObligation, RegionckMode};
@@ -406,12 +406,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RegionCtxt<'a, 'tcx> {
     // hierarchy, and in particular the relationships between free
     // regions, until regionck, as described in #3238.
 
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_fn(
         &mut self,
         fk: intravisit::FnKind<'tcx>,
@@ -859,15 +853,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..becae6c9dc920ad7ee67dcdcf406cebc18326b36 100644 (file)
 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;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_infer::infer::UpvarRegion;
 use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
 use rustc_middle::mir::FakeReadCause;
@@ -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>) {
@@ -141,12 +140,6 @@ struct InferBorrowKindVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for InferBorrowKindVisitor<'a, 'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         match expr.kind {
             hir::ExprKind::Closure(cc, _, body_id, _, _) => {
@@ -207,8 +200,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 +223,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 +244,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 +352,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 +377,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 +516,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 +536,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 +594,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 +625,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 +636,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 +962,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 +997,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 +1107,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 +1491,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 +1500,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 +1527,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 +1643,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 +1676,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 +1687,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 +1722,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 +1754,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 +1795,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 +1836,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 +1862,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 +1895,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 +1923,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 +1982,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 +2003,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 +2092,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 +2113,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 +2144,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 +2154,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 +2237,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..606a2d6a24e59fa891f000672feba5abdeb42695 100644 (file)
 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_middle::hir::map as hir_map;
+use rustc_infer::infer::region_constraints::GenericKind;
+use rustc_infer::infer::{self, RegionckMode};
+use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts, Subst};
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
@@ -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);
 
@@ -1759,10 +1747,10 @@ fn visit_foreign_item(&self, foreign_item: &'tcx hir::ForeignItem<'tcx>) {
 }
 
 impl<'tcx> Visitor<'tcx> for CheckTypeWellFormedVisitor<'tcx> {
-    type Map = hir_map::Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
-        hir_visit::NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     #[instrument(skip(self, i), level = "debug")]
index fdc8b6b5e64519d57642ad6549ec858d880fcc89..f50f3c39c8882d8b0af418b8e8ac53c9aceda419 100644 (file)
@@ -8,7 +8,7 @@
 use rustc_errors::ErrorReported;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc_infer::infer::InferCtxt;
 use rustc_middle::hir::place::Place as HirPlace;
@@ -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);
     }
 
@@ -253,12 +253,6 @@ fn fix_index_builtin_expr(&mut self, e: &hir::Expr<'_>) {
 // traffic in node-ids or update typeck results in the type context etc.
 
 impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_expr(&mut self, e: &'tcx hir::Expr<'tcx>) {
         self.fix_scalar_builtin_expr(e);
         self.fix_index_builtin_expr(e);
@@ -750,7 +744,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 d4d4baa3f71da9c0ee1527eccf3df983451bace6..cf519a9ab32747be49555c008f9f7893c10aba2d 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;
 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::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::weak_lang_items;
 use rustc_hir::{GenericParamKind, HirId, Node};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::mono::Linkage;
 use rustc_middle::ty::query::Providers;
@@ -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,
@@ -114,14 +112,9 @@ pub struct ItemCtxt<'tcx> {
 ///////////////////////////////////////////////////////////////////////////
 
 #[derive(Default)]
-crate struct PlaceholderHirTyCollector(crate Vec<Span>);
+crate struct HirPlaceholderCollector(crate Vec<Span>);
 
-impl<'v> Visitor<'v> for PlaceholderHirTyCollector {
-    type Map = intravisit::ErasedMap<'v>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
+impl<'v> Visitor<'v> for HirPlaceholderCollector {
     fn visit_ty(&mut self, t: &'v hir::Ty<'v>) {
         if let hir::TyKind::Infer = t.kind {
             self.0.push(t.span);
@@ -138,6 +131,12 @@ fn visit_generic_arg(&mut self, generic_arg: &'v hir::GenericArg<'v>) {
             _ => {}
         }
     }
+    fn visit_array_length(&mut self, length: &'v hir::ArrayLen) {
+        if let &hir::ArrayLen::Infer(_, span) = length {
+            self.0.push(span);
+        }
+        intravisit::walk_array_len(self, length)
+    }
 }
 
 struct CollectItemTypesVisitor<'tcx> {
@@ -182,7 +181,7 @@ struct CollectItemTypesVisitor<'tcx> {
         sugg.push((span, format!(", {}", type_name)));
     }
 
-    let mut err = bad_placeholder(tcx, "type", placeholder_types, kind);
+    let mut err = bad_placeholder(tcx, placeholder_types, kind);
 
     // Suggest, but only if it is not a function in const or static
     if suggest {
@@ -240,7 +239,7 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
         _ => return,
     };
 
-    let mut visitor = PlaceholderHirTyCollector::default();
+    let mut visitor = HirPlaceholderCollector::default();
     visitor.visit_item(item);
 
     placeholder_type_error(
@@ -255,10 +254,10 @@ fn reject_placeholder_type_signatures_in_item<'tcx>(
 }
 
 impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
@@ -318,7 +317,6 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
 
 fn bad_placeholder<'tcx>(
     tcx: TyCtxt<'tcx>,
-    placeholder_kind: &'static str,
     mut spans: Vec<Span>,
     kind: &'static str,
 ) -> rustc_errors::DiagnosticBuilder<'tcx> {
@@ -329,8 +327,7 @@ fn bad_placeholder<'tcx>(
         tcx.sess,
         spans.clone(),
         E0121,
-        "the {} placeholder `_` is not allowed within types on item signatures for {}",
-        placeholder_kind,
+        "the placeholder `_` is not allowed within types on item signatures for {}",
         kind
     );
     for span in spans {
@@ -388,7 +385,7 @@ fn allow_ty_infer(&self) -> bool {
     }
 
     fn ty_infer(&self, _: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
-        self.tcx().ty_error_with_message(span, "bad_placeholder_type")
+        self.tcx().ty_error_with_message(span, "bad placeholder type")
     }
 
     fn ct_infer(
@@ -397,13 +394,11 @@ fn ct_infer(
         _: Option<&ty::GenericParamDef>,
         span: Span,
     ) -> &'tcx Const<'tcx> {
-        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,
             _ => r,
         });
-        self.tcx().const_error(ty)
+        self.tcx().const_error_with_message(ty, span, "bad placeholder constant")
     }
 
     fn projected_ty_from_poly_trait_ref(
@@ -436,7 +431,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)
@@ -570,13 +565,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
@@ -667,7 +661,11 @@ fn type_parameter_bounds_in_generics(
             .params
             .iter()
             .filter_map(|param| match param.kind {
-                GenericParamKind::Type { .. } if param.hir_id == param_id => Some(&param.bounds),
+                GenericParamKind::Type { .. } | GenericParamKind::Const { .. }
+                    if param.hir_id == param_id =>
+                {
+                    Some(&param.bounds)
+                }
                 _ => None,
             })
             .flat_map(|bounds| bounds.iter())
@@ -747,7 +745,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                 match item.kind {
                     hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.def_id),
                     hir::ForeignItemKind::Static(..) => {
-                        let mut visitor = PlaceholderHirTyCollector::default();
+                        let mut visitor = HirPlaceholderCollector::default();
                         visitor.visit_foreign_item(item);
                         placeholder_type_error(
                             tcx,
@@ -830,7 +828,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
                 hir::ItemKind::Const(ty, ..) | hir::ItemKind::Static(ty, ..) => {
                     // (#75889): Account for `const C: dyn Fn() -> _ = "";`
                     if let hir::TyKind::TraitObject(..) = ty.kind {
-                        let mut visitor = PlaceholderHirTyCollector::default();
+                        let mut visitor = HirPlaceholderCollector::default();
                         visitor.visit_item(it);
                         placeholder_type_error(
                             tcx,
@@ -866,7 +864,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
         hir::TraitItemKind::Const(..) => {
             tcx.ensure().type_of(trait_item_id.def_id);
             // Account for `const C: _;`.
-            let mut visitor = PlaceholderHirTyCollector::default();
+            let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
             placeholder_type_error(tcx, None, &[], visitor.0, false, None, "constant");
         }
@@ -875,7 +873,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             tcx.ensure().item_bounds(trait_item_id.def_id);
             tcx.ensure().type_of(trait_item_id.def_id);
             // Account for `type T = _;`.
-            let mut visitor = PlaceholderHirTyCollector::default();
+            let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
             placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
         }
@@ -884,7 +882,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
             tcx.ensure().item_bounds(trait_item_id.def_id);
             // #74612: Visit and try to find bad placeholders
             // even if there is no concrete type.
-            let mut visitor = PlaceholderHirTyCollector::default();
+            let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_trait_item(trait_item);
 
             placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
@@ -906,7 +904,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
         }
         hir::ImplItemKind::TyAlias(_) => {
             // Account for `type T = _;`
-            let mut visitor = PlaceholderHirTyCollector::default();
+            let mut visitor = HirPlaceholderCollector::default();
             visitor.visit_impl_item(impl_item);
 
             placeholder_type_error(tcx, None, &[], visitor.0, false, None, "associated type");
@@ -995,7 +993,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 {
@@ -1003,7 +1001,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,
@@ -1198,9 +1196,11 @@ fn super_predicates_that_define_assoc_type(
 fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
     let item = tcx.hir().expect_item(def_id.expect_local());
 
-    let (is_auto, unsafety) = match item.kind {
-        hir::ItemKind::Trait(is_auto, unsafety, ..) => (is_auto == hir::IsAuto::Yes, unsafety),
-        hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal),
+    let (is_auto, unsafety, items) = match item.kind {
+        hir::ItemKind::Trait(is_auto, unsafety, .., items) => {
+            (is_auto == hir::IsAuto::Yes, unsafety, items)
+        }
+        hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal, &[][..]),
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
@@ -1227,6 +1227,103 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
         ty::trait_def::TraitSpecializationKind::None
     };
     let def_path_hash = tcx.def_path_hash(def_id);
+
+    let must_implement_one_of = tcx
+        .get_attrs(def_id)
+        .iter()
+        .find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
+        // Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]`
+        // and that they are all identifiers
+        .and_then(|attr| match attr.meta_item_list() {
+            Some(items) if items.len() < 2 => {
+                tcx.sess
+                    .struct_span_err(
+                        attr.span,
+                        "the `#[rustc_must_implement_one_of]` attribute must be \
+                        used with at least 2 args",
+                    )
+                    .emit();
+
+                None
+            }
+            Some(items) => items
+                .into_iter()
+                .map(|item| item.ident().ok_or(item.span()))
+                .collect::<Result<Box<[_]>, _>>()
+                .map_err(|span| {
+                    tcx.sess
+                        .struct_span_err(span, "must be a name of an associated function")
+                        .emit();
+                })
+                .ok()
+                .zip(Some(attr.span)),
+            // Error is reported by `rustc_attr!`
+            None => None,
+        })
+        // Check that all arguments of `#[rustc_must_implement_one_of]` reference
+        // functions in the trait with default implementations
+        .and_then(|(list, attr_span)| {
+            let errors = list.iter().filter_map(|ident| {
+                let item = items.iter().find(|item| item.ident == *ident);
+
+                match item {
+                    Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
+                        if !item.defaultness.has_value() {
+                            tcx.sess
+                                .struct_span_err(
+                                    item.span,
+                                    "This function doesn't have a default implementation",
+                                )
+                                .span_note(attr_span, "required by this annotation")
+                                .emit();
+
+                            return Some(());
+                        }
+
+                        return None;
+                    }
+                    Some(item) => tcx
+                        .sess
+                        .struct_span_err(item.span, "Not a function")
+                        .span_note(attr_span, "required by this annotation")
+                        .note(
+                            "All `#[rustc_must_implement_one_of]` arguments \
+                            must be associated function names",
+                        )
+                        .emit(),
+                    None => tcx
+                        .sess
+                        .struct_span_err(ident.span, "Function not found in this trait")
+                        .emit(),
+                }
+
+                Some(())
+            });
+
+            (errors.count() == 0).then_some(list)
+        })
+        // Check for duplicates
+        .and_then(|list| {
+            let mut set: FxHashMap<Symbol, Span> = FxHashMap::default();
+            let mut no_dups = true;
+
+            for ident in &*list {
+                if let Some(dup) = set.insert(ident.name, ident.span) {
+                    tcx.sess
+                        .struct_span_err(vec![dup, ident.span], "Functions names are duplicated")
+                        .note(
+                            "All `#[rustc_must_implement_one_of]` arguments \
+                            must be unique",
+                        )
+                        .emit();
+
+                    no_dups = false;
+                }
+            }
+
+            no_dups.then_some(list)
+        });
+
     ty::TraitDef::new(
         def_id,
         unsafety,
@@ -1236,6 +1333,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TraitDef {
         skip_array_during_method_dispatch,
         spec_kind,
         def_path_hash,
+        must_implement_one_of,
     )
 }
 
@@ -1247,12 +1345,6 @@ struct LateBoundRegionsDetector<'tcx> {
     }
 
     impl<'tcx> Visitor<'tcx> for LateBoundRegionsDetector<'tcx> {
-        type Map = intravisit::ErasedMap<'tcx>;
-
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-
         fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
             if self.has_late_bound_regions.is_some() {
                 return;
@@ -1360,12 +1452,6 @@ struct AnonConstInParamTyDetector {
 }
 
 impl<'v> Visitor<'v> for AnonConstInParamTyDetector {
-    type Map = intravisit::ErasedMap<'v>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
         if let GenericParamKind::Const { ty, default: _ } = p.kind {
             let prev = self.in_param_ty;
@@ -1397,13 +1483,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) {
@@ -1513,11 +1598,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,
         },
@@ -1739,10 +1824,14 @@ fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
 /// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to
 /// use inference to provide suggestions for the appropriate type if possible.
 fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
+    debug!(?ty);
     use hir::TyKind::*;
     match &ty.kind {
         Infer => true,
-        Slice(ty) | Array(ty, _) => is_suggestable_infer_ty(ty),
+        Slice(ty) => is_suggestable_infer_ty(ty),
+        Array(ty, length) => {
+            is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _))
+        }
         Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
         Ptr(mut_ty) | Rptr(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
         OpaqueDef(_, generic_args) => are_suggestable_generic_args(generic_args),
@@ -1794,9 +1883,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
                     });
                     let fn_sig = ty::Binder::dummy(fn_sig);
 
-                    let mut visitor = PlaceholderHirTyCollector::default();
+                    let mut visitor = HirPlaceholderCollector::default();
                     visitor.visit_ty(ty);
-                    let mut diag = bad_placeholder(tcx, "type", visitor.0, "return type");
+                    let mut diag = bad_placeholder(tcx, visitor.0, "return type");
                     let ret_ty = fn_sig.skip_binder().output();
                     if !ret_ty.references_error() {
                         if !ret_ty.is_closure() {
@@ -1862,7 +1951,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(
@@ -2280,7 +2369,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),
         );
     }
 
@@ -2302,12 +2391,6 @@ struct ConstCollector<'tcx> {
     }
 
     impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> {
-        type Map = Map<'tcx>;
-
-        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-            intravisit::NestedVisitorMap::None
-        }
-
         fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
             let def_id = self.tcx.hir().local_def_id(c.hir_id);
             let ct = ty::Const::from_anon_const(self.tcx, def_id);
@@ -2432,8 +2515,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);
             }
@@ -2455,7 +2537,7 @@ fn predicates_from_bound<'tcx>(
 ) -> Vec<(ty::Predicate<'tcx>, Span)> {
     let mut bounds = Bounds::default();
     astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
-    bounds.predicates(astconv.tcx(), param_ty)
+    bounds.predicates(astconv.tcx(), param_ty).collect()
 }
 
 fn compute_sig_of_foreign_fn_decl<'tcx>(
@@ -3120,8 +3202,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);
     }
@@ -3232,7 +3313,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 26cad8fb18058a537409508f29b074f928b7824d..87a67c4a4e060ed147802f1cacd9c298bdbfc667 100644 (file)
@@ -67,11 +67,7 @@ fn opaque_type_bounds<'tcx>(
         let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
         <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, ast_bounds, None, span);
-        let bounds = bounds.predicates(tcx, item_ty);
-
-        debug!("opaque_type_bounds({}) = {:?}", tcx.def_path_str(opaque_def_id), bounds);
-
-        tcx.arena.alloc_slice(&bounds)
+        tcx.arena.alloc_from_iter(bounds.predicates(tcx, item_ty))
     })
 }
 
index ae8d262fcf17654cab28a52d20e1a848ff03e557..63020b7f90f0abe51bd7537e7e3ddbfc3ed95d62 100644 (file)
@@ -5,8 +5,8 @@
 use rustc_hir::intravisit;
 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::hir::nested_filter;
+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;
 /// 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
-    // for const or type.
     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 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");
-                        });
+    match tcx.hir().get(hir_id) {
+        Node::AnonConst(_) => (),
+        _ => return None,
+    };
 
-                    return generics
-                        .params
-                        .iter()
-                        .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Const { .. }))
-                        .nth(arg_index)
-                        .map(|param| param.def_id);
-                }
+    let parent_node_id = tcx.hir().get_parent_node(hir_id);
+    let parent_node = tcx.hir().get(parent_node_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 +275,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 +319,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 +429,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());
@@ -509,7 +478,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),
@@ -627,10 +596,10 @@ fn check(&mut self, def_id: LocalDefId) {
     }
 
     impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> {
-        type Map = Map<'tcx>;
+        type NestedFilter = nested_filter::All;
 
-        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-            intravisit::NestedVisitorMap::All(self.tcx.hir())
+        fn nested_visit_map(&mut self) -> Self::Map {
+            self.tcx.hir()
         }
         fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
             if let hir::ExprKind::Closure(..) = ex.kind {
@@ -781,7 +750,7 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
             err.emit();
         }
         None => {
-            let mut diag = bad_placeholder(tcx, "type", vec![span], kind);
+            let mut diag = bad_placeholder(tcx, vec![span], kind);
 
             if !ty.references_error() {
                 let mut mk_nameable = MakeNameable::new(tcx);
index 88877ad78525a95ad7e24cee0411fafb15beff32..a0c8fc822dffd88769c78094b71dda48211d0125 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.term, false));
             } else {
                 continue;
             }
index 1ae0ff3036471d75391f4872ab8ed7ef599b1f16..db1c80ae433b20de2a320f81fa66aaa720cb0826 100644 (file)
@@ -17,7 +17,6 @@
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
 use rustc_target::abi::VariantIdx;
-use std::iter;
 
 use crate::mem_categorization as mc;
 
@@ -360,17 +359,6 @@ pub fn walk_expr(&mut self, expr: &hir::Expr<'_>) {
                 }
             }
 
-            hir::ExprKind::LlvmInlineAsm(ia) => {
-                for (o, output) in iter::zip(&ia.inner.outputs, ia.outputs_exprs) {
-                    if o.is_indirect {
-                        self.consume_expr(output);
-                    } else {
-                        self.mutate_expr(output);
-                    }
-                }
-                self.consume_exprs(ia.inputs_exprs);
-            }
-
             hir::ExprKind::Continue(..)
             | hir::ExprKind::Lit(..)
             | hir::ExprKind::ConstBlock(..)
@@ -796,14 +784,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 a49eda6572de2cb3cf3248d6a5e317a3ab8ee893..7d1aedc86008b7b60bfe90703b02a9f75afc3180 100644 (file)
@@ -1,6 +1,6 @@
 use crate::collect::ItemCtxt;
 use rustc_hir as hir;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::HirId;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::TraitEngine;
@@ -64,10 +64,6 @@ struct HirWfCheck<'tcx> {
     }
 
     impl<'tcx> Visitor<'tcx> for HirWfCheck<'tcx> {
-        type Map = intravisit::ErasedMap<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
         fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
             self.tcx.infer_ctxt().enter(|infcx| {
                 let mut fulfill = traits::FulfillmentContext::new();
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..d87e670a8fb5a7bf912ea64031a9b1a5d70e4944 100644 (file)
@@ -199,22 +199,22 @@ fn unconstrained_parent_impl_substs<'tcx>(
     for (predicate, _) in impl_generic_predicates.predicates.iter() {
         if let ty::PredicateKind::Projection(proj) = predicate.kind().skip_binder() {
             let projection_ty = proj.projection_ty;
-            let projected_ty = proj.ty;
+            let projected_ty = proj.term;
 
             let unbound_trait_ref = projection_ty.trait_ref(tcx);
             if Some(unbound_trait_ref) == impl_trait_ref {
                 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 440ce04e61a27abf231ff328a3803d5cbafe436c..2c2d2be8bb5141e9eac2f9c9073b64164243074b 100644 (file)
@@ -378,7 +378,6 @@ fn cat_expr_adjusted_with<F>(
             | hir::ExprKind::Struct(..)
             | hir::ExprKind::Repeat(..)
             | hir::ExprKind::InlineAsm(..)
-            | hir::ExprKind::LlvmInlineAsm(..)
             | hir::ExprKind::Box(..)
             | hir::ExprKind::Err => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
         }
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..7c504a0d89c59aa98b6348a0d7aa55a48bd9390d 100644 (file)
@@ -308,11 +308,14 @@ fn add_constraints_from_ty(
                 }
 
                 for projection in data.projection_bounds() {
-                    self.add_constraints_from_ty(
-                        current,
-                        projection.skip_binder().ty,
-                        self.invariant,
-                    );
+                    match projection.skip_binder().term {
+                        ty::Term::Ty(ty) => {
+                            self.add_constraints_from_ty(current, ty, self.invariant);
+                        }
+                        ty::Term::Const(c) => {
+                            self.add_constraints_from_const(current, c, self.invariant)
+                        }
+                    }
                 }
             }
 
@@ -405,8 +408,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 199c05dc5df3e4e4471f2dcda41f772eb002e59b..794b9356e7c28df02b1bc3f1dce5df8b776fee9a 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.
@@ -31,7 +34,7 @@
 // An empty map is represented either by the absence of a root node or by a
 // root node that is an empty leaf.
 
-/// A map based on a [B-Tree].
+/// An ordered map based on a [B-Tree].
 ///
 /// B-Trees represent a fundamental compromise between cache-efficiency and actually minimizing
 /// the amount of work performed in a search. In theory, a binary search tree (BST) is the optimal
 /// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
 /// behavior.
 ///
+/// Iterators obtained from functions such as [`BTreeMap::iter`], [`BTreeMap::values`], or
+/// [`BTreeMap::keys`] produce their items in order by key, and take worst-case logarithmic and
+/// amortized constant time per item returned.
+///
 /// [B-Tree]: https://en.wikipedia.org/wiki/B-tree
 /// [`Cell`]: core::cell::Cell
 /// [`RefCell`]: core::cell::RefCell
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 394c21bf51cd26f6395119e9b3558ad0ade51baf..31df4e98ed746884fca583ba22b16855cd476406 100644 (file)
@@ -15,7 +15,7 @@
 
 // FIXME(conventions): implement bounded iterators
 
-/// A set based on a B-Tree.
+/// An ordered set based on a B-Tree.
 ///
 /// See [`BTreeMap`]'s documentation for a detailed discussion of this collection's performance
 /// benefits and drawbacks.
@@ -27,6 +27,9 @@
 /// incorrect results, aborts, memory leaks, or non-termination) but will not be undefined
 /// behavior.
 ///
+/// Iterators returned by [`BTreeSet::iter`] produce their items in order, and take worst-case
+/// logarithmic and amortized constant time per item returned.
+///
 /// [`Ord`]: core::cmp::Ord
 /// [`Cell`]: core::cell::Cell
 /// [`RefCell`]: core::cell::RefCell
index 1ea135a2aed82aaa12d71598a977e7737eda0277..628a5b155673c9cc1cb9f4ce72799b2bc926e9ea 100644 (file)
@@ -14,7 +14,7 @@
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod btree_map {
-    //! A map based on a B-Tree.
+    //! An ordered map based on a B-Tree.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::btree::map::*;
 }
@@ -22,7 +22,7 @@ pub mod btree_map {
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod btree_set {
-    //! A set based on a B-Tree.
+    //! An ordered set based on a B-Tree.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::btree::set::*;
 }
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 7e663fab16af544dbbffdbe8e9c17a41560715db..1cbc2b65f4dbdad1910c8c5b74d178516f0c5a15 100644 (file)
 #![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)]
index 189da9f06392add94c1ac45a83e982a28715d4f1..d3e9e65c3fe57b493001b6c77c9afc99287ff126 100644 (file)
@@ -37,6 +37,7 @@
 #[cfg(not(test))]
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "vec_macro"]
 #[allow_internal_unstable(box_syntax, liballoc_internals)]
 macro_rules! vec {
     () => (
index 3806bc546ee7b522f90104c77ffd8b03b6a1b12c..8fa0242ca9a9f05d699384422bb097c6aa078608 100644 (file)
@@ -108,7 +108,7 @@ impl<T, A: Allocator> RawVec<T, A> {
     //   to round up a request of less than 8 bytes to at least 8 bytes.
     // - 4 if elements are moderate-sized (<= 1 KiB).
     // - 1 otherwise, to avoid wasting too much space for very short Vecs.
-    const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 {
+    pub(crate) const MIN_NON_ZERO_CAP: usize = if mem::size_of::<T>() == 1 {
         8
     } else if mem::size_of::<T>() <= 1024 {
         4
index 8853577371ad6d7dd62e1d65bba4c851eea5bbc6..a5c4140e313872c0363ecd0814534d47d5fe0f03 100644 (file)
@@ -375,7 +375,10 @@ pub fn sort_by_key<K, F>(&mut self, mut f: F)
 
     /// Sorts the slice with a key extraction function.
     ///
-    /// During sorting, the key function is called only once per element.
+    /// During sorting, the key function is called at most once per element, by using
+    /// temporary storage to remember the results of key evaluation.
+    /// The order of calls to the key function is unspecified and may change in future versions
+    /// of the standard library.
     ///
     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* + *n* \* log(*n*))
     /// worst-case, where the key function is *O*(*m*).
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 78f989e730d2474e41b9f7ab80135cdbfb026275..bd3262b51d4807b1363a88b3b66d7519b050ea90 100644 (file)
@@ -1372,9 +1372,12 @@ fn assert_failed(index: usize, len: usize) -> ! {
     ///
     /// Note: Because this shifts over the remaining elements, it has a
     /// worst-case performance of *O*(*n*). If you don't need the order of elements
-    /// to be preserved, use [`swap_remove`] instead.
+    /// to be preserved, use [`swap_remove`] instead. If you'd like to remove
+    /// elements from the beginning of the `Vec`, consider using
+    /// [`VecDeque::pop_front`] instead.
     ///
     /// [`swap_remove`]: Vec::swap_remove
+    /// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front
     ///
     /// # Panics
     ///
@@ -1735,6 +1738,11 @@ pub fn push(&mut self, value: T) {
     /// Removes the last element from a vector and returns it, or [`None`] if it
     /// is empty.
     ///
+    /// If you'd like to pop the first element, consider using
+    /// [`VecDeque::pop_front`] instead.
+    ///
+    /// [`VecDeque::pop_front`]: crate::collections::VecDeque::pop_front
+    ///
     /// # Examples
     ///
     /// ```
@@ -2043,8 +2051,6 @@ pub fn leak<'a>(self) -> &'a mut [T]
     /// # Examples
     ///
     /// ```
-    /// #![feature(vec_spare_capacity)]
-    ///
     /// // Allocate vector big enough for 10 elements.
     /// let mut v = Vec::with_capacity(10);
     ///
@@ -2061,7 +2067,7 @@ pub fn leak<'a>(self) -> &'a mut [T]
     ///
     /// assert_eq!(&v, &[0, 1, 2]);
     /// ```
-    #[unstable(feature = "vec_spare_capacity", issue = "75017")]
+    #[stable(feature = "vec_spare_capacity", since = "1.60.0")]
     #[inline]
     pub fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<T>] {
         // Note:
index 948cf044197c2320398c54a2c9d9809dd9e80f56..f915ebb86e5a5f945ed6e7f83cb3ec7d0f90dafe 100644 (file)
@@ -1,5 +1,8 @@
+use core::cmp;
 use core::iter::TrustedLen;
-use core::ptr::{self};
+use core::ptr;
+
+use crate::raw_vec::RawVec;
 
 use super::{SpecExtend, Vec};
 
@@ -24,8 +27,11 @@ impl<T, I> SpecFromIterNested<T, I> for Vec<T>
             None => return Vec::new(),
             Some(element) => {
                 let (lower, _) = iterator.size_hint();
-                let mut vector = Vec::with_capacity(lower.saturating_add(1));
+                let initial_capacity =
+                    cmp::max(RawVec::<T>::MIN_NON_ZERO_CAP, lower.saturating_add(1));
+                let mut vector = Vec::with_capacity(initial_capacity);
                 unsafe {
+                    // SAFETY: We requested capacity at least 1
                     ptr::write(vector.as_mut_ptr(), element);
                     vector.set_len(1);
                 }
index eec24a5c3f7e69ea3ca90574ba44c82609c78842..dcf51e3142a617924590b0f19b8739439c7fe10b 100644 (file)
 #![feature(iter_advance_by)]
 #![feature(slice_group_by)]
 #![feature(slice_partition_dedup)]
-#![feature(vec_spare_capacity)]
 #![feature(string_remove_matches)]
 #![feature(const_btree_new)]
 #![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 deed9901cc9e4595919ba893927d7c34820616a8..f89cf812e970a0aa38a1da1d9af7a191ad560d17 100644 (file)
@@ -661,20 +661,37 @@ fn clone_from(&mut self, other: &Self) {
 ///
 /// ## Derivable
 ///
-/// This trait can be used with `#[derive]`. When `derive`d on structs, it will produce a
-/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering based on the top-to-bottom declaration order of the struct's members.
-/// When `derive`d on enums, variants are ordered by their top-to-bottom discriminant order.
-/// This means variants at the top are less than variants at the bottom.
-/// Here's an example:
+/// This trait can be used with `#[derive]`.
+///
+/// When `derive`d on structs, it will produce a
+/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering
+/// based on the top-to-bottom declaration order of the struct's members.
+///
+/// When `derive`d on enums, variants are ordered by their discriminants.
+/// By default, the discriminant is smallest for variants at the top, and
+/// largest for variants at the bottom. Here's an example:
 ///
 /// ```
-/// #[derive(PartialEq, PartialOrd)]
-/// enum Size {
-///     Small,
-///     Large,
+/// #[derive(PartialEq, Eq, PartialOrd, Ord)]
+/// enum E {
+///     Top,
+///     Bottom,
 /// }
 ///
-/// assert!(Size::Small < Size::Large);
+/// assert!(E::Top < E::Bottom);
+/// ```
+///
+/// However, manually setting the discriminants can override this default
+/// behavior:
+///
+/// ```
+/// #[derive(PartialEq, Eq, PartialOrd, Ord)]
+/// enum E {
+///     Top = 2,
+///     Bottom = 1,
+/// }
+///
+/// assert!(E::Bottom < E::Top);
 /// ```
 ///
 /// ## Lexicographical comparison
@@ -895,9 +912,38 @@ fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
 ///
 /// ## Derivable
 ///
-/// This trait can be used with `#[derive]`. When `derive`d on structs, it will produce a
-/// lexicographic ordering based on the top-to-bottom declaration order of the struct's members.
-/// When `derive`d on enums, variants are ordered by their top-to-bottom discriminant order.
+/// This trait can be used with `#[derive]`.
+///
+/// When `derive`d on structs, it will produce a
+/// [lexicographic](https://en.wikipedia.org/wiki/Lexicographic_order) ordering
+/// based on the top-to-bottom declaration order of the struct's members.
+///
+/// When `derive`d on enums, variants are ordered by their discriminants.
+/// By default, the discriminant is smallest for variants at the top, and
+/// largest for variants at the bottom. Here's an example:
+///
+/// ```
+/// #[derive(PartialEq, PartialOrd)]
+/// enum E {
+///     Top,
+///     Bottom,
+/// }
+///
+/// assert!(E::Top < E::Bottom);
+/// ```
+///
+/// However, manually setting the discriminants can override this default
+/// behavior:
+///
+/// ```
+/// #[derive(PartialEq, PartialOrd)]
+/// enum E {
+///     Top = 2,
+///     Bottom = 1,
+/// }
+///
+/// assert!(E::Bottom < E::Top);
+/// ```
 ///
 /// ## How can I implement `PartialOrd`?
 ///
@@ -970,8 +1016,8 @@ fn partial_cmp(&self, other: &Ordering) -> Option<Ordering> {
 /// # Examples
 ///
 /// ```
-/// let x : u32 = 0;
-/// let y : u32 = 1;
+/// let x: u32 = 0;
+/// let y: u32 = 1;
 ///
 /// assert_eq!(x < y, true);
 /// assert_eq!(x.lt(&y), true);
index d40f69f8b35743d3bd5c662d86401b83a35fecef..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);
 /// ```
@@ -481,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)
@@ -492,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)
@@ -511,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()
@@ -567,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;
 
@@ -581,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 560dd25ecff4218961f07cb6a953d414f40a1940..2877e66eca8850949df0f832ac8873dc2c4b2ad2 100644 (file)
@@ -12,7 +12,7 @@
 #[stable(feature = "future_readiness_fns", since = "1.48.0")]
 #[must_use = "futures do nothing unless you `.await` or poll them"]
 pub struct Pending<T> {
-    _data: marker::PhantomData<T>,
+    _data: marker::PhantomData<fn() -> T>,
 }
 
 /// Creates a future which never resolves, representing a computation that never
@@ -43,9 +43,6 @@ fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<T> {
     }
 }
 
-#[stable(feature = "future_readiness_fns", since = "1.48.0")]
-impl<T> Unpin for Pending<T> {}
-
 #[stable(feature = "future_readiness_fns", since = "1.48.0")]
 impl<T> Debug for Pending<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
index 3ff84cc9672eb757a3e85d74f2e30d82ce43d617..53de8b42c059f219b586be1a9a6daf0a906db6c5 100644 (file)
@@ -602,7 +602,7 @@ fn hash_one<T: Hash>(&self, x: T) -> u64
 /// [`HashSet`]: ../../std/collections/struct.HashSet.html
 /// [zero-sized]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts
 #[stable(since = "1.7.0", feature = "build_hasher")]
-pub struct BuildHasherDefault<H>(marker::PhantomData<H>);
+pub struct BuildHasherDefault<H>(marker::PhantomData<fn() -> H>);
 
 #[stable(since = "1.9.0", feature = "core_impl_debug")]
 impl<H> fmt::Debug for BuildHasherDefault<H> {
index 4ecc3b0c7f8e1ad4b174dd261adf93b6ed801eff..9781dc320edde90ab9911d40709d5ec1bb8f0f53 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];
@@ -1893,7 +1893,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     pub fn nontemporal_store<T>(ptr: *mut T, val: T);
 
     /// See documentation of `<*const T>::offset_from` for details.
-    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
+    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
     pub fn ptr_offset_from<T>(ptr: *const T, base: *const T) -> isize;
 
     /// See documentation of `<*const T>::guaranteed_eq` for details.
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 7abe01d17c90bd46668d87fcb437f8d35b113a25..98734c527f2b9c35874027386cb9c1008276a7e3 100644 (file)
@@ -22,17 +22,17 @@ pub const fn empty<T>() -> Empty<T> {
     Empty(marker::PhantomData)
 }
 
+// Newtype for use in `PhantomData` to avoid
+// > error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]`
+// in `const fn empty<T>()` above.
+struct FnReturning<T>(fn() -> T);
+
 /// An iterator that yields nothing.
 ///
 /// This `struct` is created by the [`empty()`] function. See its documentation for more.
 #[must_use = "iterators are lazy and do nothing unless consumed"]
 #[stable(feature = "iter_empty", since = "1.2.0")]
-pub struct Empty<T>(marker::PhantomData<T>);
-
-#[stable(feature = "iter_empty_send_sync", since = "1.42.0")]
-unsafe impl<T> Send for Empty<T> {}
-#[stable(feature = "iter_empty_send_sync", since = "1.42.0")]
-unsafe impl<T> Sync for Empty<T> {}
+pub struct Empty<T>(marker::PhantomData<FnReturning<T>>);
 
 #[stable(feature = "core_impl_debug", since = "1.9.0")]
 impl<T> fmt::Debug for Empty<T> {
index 26c97b8ed785dd992f2a316147060b9628b51c07..fc14620a2df84b752686aa0daa4d47318079489b 100644 (file)
@@ -124,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());
@@ -215,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 2049adafa2fed9a02ad6f950dddba51eeb81f89b..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`.
@@ -1270,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));
@@ -1604,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();
@@ -2700,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(),
@@ -2738,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 4bd94e3ce39152e166af71825d4fb3901b109079..d8ac816fb15a0309648809330f6452d5fa894ac8 100644 (file)
 #![feature(intrinsics)]
 #![feature(lang_items)]
 #![feature(link_llvm_intrinsics)]
-#![feature(llvm_asm)]
 #![feature(min_specialization)]
 #![feature(mixed_integer_ops)]
 #![feature(must_not_suspend)]
index d8f6c85e428cdf054e78afcdfa0f6cd1c7d66630..488bb875c352685a7213d2ae0d739ebe0b603c85 100644 (file)
@@ -31,6 +31,7 @@ macro_rules! panic {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "assert_eq_macro")]
 #[allow_internal_unstable(core_panic)]
 macro_rules! assert_eq {
     ($left:expr, $right:expr $(,)?) => ({
@@ -80,6 +81,7 @@ macro_rules! assert_eq {
 /// ```
 #[macro_export]
 #[stable(feature = "assert_ne", since = "1.13.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "assert_ne_macro")]
 #[allow_internal_unstable(core_panic)]
 macro_rules! assert_ne {
     ($left:expr, $right:expr $(,)?) => ({
@@ -236,6 +238,7 @@ macro_rules! debug_assert {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "debug_assert_eq_macro")]
 macro_rules! debug_assert_eq {
     ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_eq!($($arg)*); })
 }
@@ -261,6 +264,7 @@ macro_rules! debug_assert_eq {
 /// ```
 #[macro_export]
 #[stable(feature = "assert_ne", since = "1.13.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "debug_assert_ne_macro")]
 macro_rules! debug_assert_ne {
     ($($arg:tt)*) => (if $crate::cfg!(debug_assertions) { $crate::assert_ne!($($arg)*); })
 }
@@ -320,6 +324,7 @@ macro_rules! debug_assert_ne {
 /// ```
 #[macro_export]
 #[stable(feature = "matches_macro", since = "1.42.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "matches_macro")]
 macro_rules! matches {
     ($expression:expr, $(|)? $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => {
         match $expression {
@@ -475,6 +480,7 @@ macro_rules! r#try {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "write_macro")]
 macro_rules! write {
     ($dst:expr, $($arg:tt)*) => ($dst.write_fmt($crate::format_args!($($arg)*)))
 }
@@ -525,6 +531,7 @@ macro_rules! write {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "writeln_macro")]
 #[allow_internal_unstable(format_args_nl)]
 macro_rules! writeln {
     ($dst:expr $(,)?) => (
@@ -589,6 +596,7 @@ macro_rules! writeln {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "unreachable_macro")]
 #[allow_internal_unstable(core_panic)]
 macro_rules! unreachable {
     () => ({
@@ -675,6 +683,7 @@ macro_rules! unreachable {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "unimplemented_macro")]
 #[allow_internal_unstable(core_panic)]
 macro_rules! unimplemented {
     () => ($crate::panicking::panic("not implemented"));
@@ -737,6 +746,7 @@ macro_rules! unimplemented {
 /// ```
 #[macro_export]
 #[stable(feature = "todo_macro", since = "1.40.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "todo_macro")]
 #[allow_internal_unstable(core_panic)]
 macro_rules! todo {
     () => ($crate::panicking::panic("not yet implemented"));
@@ -786,6 +796,7 @@ pub(crate) mod builtin {
     #[stable(feature = "compile_error_macro", since = "1.20.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "compile_error_macro")]
     macro_rules! compile_error {
         ($msg:expr $(,)?) => {{ /* compiler built-in */ }};
     }
@@ -835,6 +846,7 @@ macro_rules! compile_error {
     /// assert_eq!(s, format!("hello {}", "world"));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "format_args_macro")]
     #[allow_internal_unsafe]
     #[allow_internal_unstable(fmt_internals)]
     #[rustc_builtin_macro]
@@ -905,6 +917,7 @@ macro_rules! format_args_nl {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "env_macro")]
     macro_rules! env {
         ($name:expr $(,)?) => {{ /* compiler built-in */ }};
         ($name:expr, $error_msg:expr $(,)?) => {{ /* compiler built-in */ }};
@@ -930,6 +943,7 @@ macro_rules! env {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "option_env_macro")]
     macro_rules! option_env {
         ($name:expr $(,)?) => {{ /* compiler built-in */ }};
     }
@@ -1015,6 +1029,7 @@ macro_rules! concat_bytes {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "concat_macro")]
     macro_rules! concat {
         ($($e:expr),* $(,)?) => {{ /* compiler built-in */ }};
     }
@@ -1040,6 +1055,7 @@ macro_rules! concat {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "line_macro")]
     macro_rules! line {
         () => {
             /* compiler built-in */
@@ -1079,6 +1095,7 @@ macro_rules! line {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "column_macro")]
     macro_rules! column {
         () => {
             /* compiler built-in */
@@ -1104,6 +1121,7 @@ macro_rules! column {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "file_macro")]
     macro_rules! file {
         () => {
             /* compiler built-in */
@@ -1128,6 +1146,7 @@ macro_rules! file {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "stringify_macro")]
     macro_rules! stringify {
         ($($t:tt)*) => {
             /* compiler built-in */
@@ -1169,6 +1188,7 @@ macro_rules! stringify {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "include_str_macro")]
     macro_rules! include_str {
         ($file:expr $(,)?) => {{ /* compiler built-in */ }};
     }
@@ -1208,6 +1228,7 @@ macro_rules! include_str {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "include_bytes_macro")]
     macro_rules! include_bytes {
         ($file:expr $(,)?) => {{ /* compiler built-in */ }};
     }
@@ -1232,6 +1253,7 @@ macro_rules! include_bytes {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "module_path_macro")]
     macro_rules! module_path {
         () => {
             /* compiler built-in */
@@ -1265,6 +1287,7 @@ macro_rules! module_path {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "cfg_macro")]
     macro_rules! cfg {
         ($($cfg:tt)*) => {
             /* compiler built-in */
@@ -1315,6 +1338,7 @@ macro_rules! cfg {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_builtin_macro]
     #[macro_export]
+    #[cfg_attr(not(test), rustc_diagnostic_item = "include_macro")]
     macro_rules! include {
         ($file:expr $(,)?) => {{ /* compiler built-in */ }};
     }
@@ -1373,32 +1397,6 @@ macro_rules! assert {
         ($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }};
     }
 
-    /// LLVM-style inline assembly.
-    ///
-    /// Read the [unstable book] for the usage.
-    ///
-    /// [unstable book]: ../unstable-book/library-features/llvm-asm.html
-    #[unstable(
-        feature = "llvm_asm",
-        issue = "70173",
-        reason = "prefer using the new asm! syntax instead"
-    )]
-    #[rustc_deprecated(
-        since = "1.56",
-        reason = "will be removed from the compiler, use asm! instead"
-    )]
-    #[rustc_builtin_macro]
-    #[macro_export]
-    macro_rules! llvm_asm {
-        ("assembly template"
-                        : $("output"(operand),)*
-                        : $("input"(operand),)*
-                        : $("clobbers",)*
-                        : $("options",)*) => {
-            /* compiler built-in */
-        };
-    }
-
     /// Prints passed tokens into the standard output.
     #[unstable(
         feature = "log_syntax",
index 3b0e4a31db1c8ce894f05b0fb770915efc23dd0d..e38c0412a0afe444d14eb4826c1a8582998083f0 100644 (file)
@@ -1,8 +1,9 @@
 use crate::any::type_name;
 use crate::fmt;
 use crate::intrinsics;
-use crate::mem::ManuallyDrop;
+use crate::mem::{self, ManuallyDrop};
 use crate::ptr;
+use crate::slice;
 
 /// A wrapper type to construct uninitialized instances of `T`.
 ///
@@ -330,7 +331,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 +663,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 +683,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 +692,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 +727,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`.
@@ -1040,7 +1039,7 @@ pub const fn slice_as_mut_ptr(this: &mut [MaybeUninit<T>]) -> *mut T {
     /// ```
     ///
     /// ```
-    /// #![feature(maybe_uninit_write_slice, vec_spare_capacity)]
+    /// #![feature(maybe_uninit_write_slice)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut vec = Vec::with_capacity(32);
@@ -1100,7 +1099,7 @@ pub fn write_slice<'a>(this: &'a mut [MaybeUninit<T>], src: &[T]) -> &'a mut [T]
     /// ```
     ///
     /// ```
-    /// #![feature(maybe_uninit_write_slice, vec_spare_capacity)]
+    /// #![feature(maybe_uninit_write_slice)]
     /// use std::mem::MaybeUninit;
     ///
     /// let mut vec = Vec::with_capacity(32);
@@ -1162,4 +1161,126 @@ fn drop(&mut self) {
         // SAFETY: Valid elements have just been written into `this` so it is initialized
         unsafe { MaybeUninit::slice_assume_init_mut(this) }
     }
+
+    /// Returns the contents of this `MaybeUninit` as a slice of potentially uninitialized bytes.
+    ///
+    /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+    /// contain padding bytes which are left uninitialized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_as_bytes, maybe_uninit_slice)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let val = 0x12345678i32;
+    /// let uninit = MaybeUninit::new(val);
+    /// let uninit_bytes = uninit.as_bytes();
+    /// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(uninit_bytes) };
+    /// assert_eq!(bytes, val.to_ne_bytes());
+    /// ```
+    #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+    pub fn as_bytes(&self) -> &[MaybeUninit<u8>] {
+        // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+        unsafe {
+            slice::from_raw_parts(self.as_ptr() as *const MaybeUninit<u8>, mem::size_of::<T>())
+        }
+    }
+
+    /// Returns the contents of this `MaybeUninit` as a mutable slice of potentially uninitialized
+    /// bytes.
+    ///
+    /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+    /// contain padding bytes which are left uninitialized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_as_bytes)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let val = 0x12345678i32;
+    /// let mut uninit = MaybeUninit::new(val);
+    /// let uninit_bytes = uninit.as_bytes_mut();
+    /// if cfg!(target_endian = "little") {
+    ///     uninit_bytes[0].write(0xcd);
+    /// } else {
+    ///     uninit_bytes[3].write(0xcd);
+    /// }
+    /// let val2 = unsafe { uninit.assume_init() };
+    /// assert_eq!(val2, 0x123456cd);
+    /// ```
+    #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+    pub fn as_bytes_mut(&mut self) -> &mut [MaybeUninit<u8>] {
+        // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+        unsafe {
+            slice::from_raw_parts_mut(
+                self.as_mut_ptr() as *mut MaybeUninit<u8>,
+                mem::size_of::<T>(),
+            )
+        }
+    }
+
+    /// Returns the contents of this slice of `MaybeUninit` as a slice of potentially uninitialized
+    /// bytes.
+    ///
+    /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+    /// contain padding bytes which are left uninitialized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let uninit = [MaybeUninit::new(0x1234u16), MaybeUninit::new(0x5678u16)];
+    /// let uninit_bytes = MaybeUninit::slice_as_bytes(&uninit);
+    /// let bytes = unsafe { MaybeUninit::slice_assume_init_ref(&uninit_bytes) };
+    /// let val1 = u16::from_ne_bytes(bytes[0..2].try_into().unwrap());
+    /// let val2 = u16::from_ne_bytes(bytes[2..4].try_into().unwrap());
+    /// assert_eq!(&[val1, val2], &[0x1234u16, 0x5678u16]);
+    /// ```
+    #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+    pub fn slice_as_bytes(this: &[MaybeUninit<T>]) -> &[MaybeUninit<u8>] {
+        // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+        unsafe {
+            slice::from_raw_parts(
+                this.as_ptr() as *const MaybeUninit<u8>,
+                this.len() * mem::size_of::<T>(),
+            )
+        }
+    }
+
+    /// Returns the contents of this mutable slice of `MaybeUninit` as a mutable slice of
+    /// potentially uninitialized bytes.
+    ///
+    /// Note that even if the contents of a `MaybeUninit` have been initialized, the value may still
+    /// contain padding bytes which are left uninitialized.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_as_bytes, maybe_uninit_write_slice, maybe_uninit_slice)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut uninit = [MaybeUninit::<u16>::uninit(), MaybeUninit::<u16>::uninit()];
+    /// let uninit_bytes = MaybeUninit::slice_as_bytes_mut(&mut uninit);
+    /// MaybeUninit::write_slice(uninit_bytes, &[0x12, 0x34, 0x56, 0x78]);
+    /// let vals = unsafe { MaybeUninit::slice_assume_init_ref(&uninit) };
+    /// if cfg!(target_endian = "little") {
+    ///     assert_eq!(vals, &[0x3412u16, 0x7856u16]);
+    /// } else {
+    ///     assert_eq!(vals, &[0x1234u16, 0x5678u16]);
+    /// }
+    /// ```
+    #[unstable(feature = "maybe_uninit_as_bytes", issue = "93092")]
+    pub fn slice_as_bytes_mut(this: &mut [MaybeUninit<T>]) -> &mut [MaybeUninit<u8>] {
+        // SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
+        unsafe {
+            slice::from_raw_parts_mut(
+                this.as_mut_ptr() as *mut MaybeUninit<u8>,
+                this.len() * mem::size_of::<T>(),
+            )
+        }
+    }
 }
index 8a06a0988829b646d871433c1986291875abfe55..de85fdd6ed2462dcd48c83e7d90144ff34089f34 100644 (file)
 )]
 #![macro_use]
 
-use crate::intrinsics;
-
 /// Arithmetic operations required by bignums.
 pub trait FullOps: Sized {
-    /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
-    /// where `W` is the number of bits in `Self`.
-    fn full_add(self, other: Self, carry: bool) -> (bool /* carry */, Self);
-
-    /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + carry`,
-    /// where `W` is the number of bits in `Self`.
-    fn full_mul(self, other: Self, carry: Self) -> (Self /* carry */, Self);
-
     /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`,
     /// where `W` is the number of bits in `Self`.
     fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /* carry */, Self);
@@ -45,22 +35,6 @@ macro_rules! impl_full_ops {
     ($($ty:ty: add($addfn:path), mul/div($bigty:ident);)*) => (
         $(
             impl FullOps for $ty {
-                fn full_add(self, other: $ty, carry: bool) -> (bool, $ty) {
-                    // This cannot overflow; the output is between `0` and `2 * 2^nbits - 1`.
-                    // FIXME: will LLVM optimize this into ADC or similar?
-                    let (v, carry1) = intrinsics::add_with_overflow(self, other);
-                    let (v, carry2) = intrinsics::add_with_overflow(v, if carry {1} else {0});
-                    (carry1 || carry2, v)
-                }
-
-                fn full_mul(self, other: $ty, carry: $ty) -> ($ty, $ty) {
-                    // This cannot overflow;
-                    // the output is between `0` and `2^nbits * (2^nbits - 1)`.
-                    // FIXME: will LLVM optimize this into ADC or similar?
-                    let v = (self as $bigty) * (other as $bigty) + (carry as $bigty);
-                    ((v >> <$ty>::BITS) as $ty, v as $ty)
-                }
-
                 fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) {
                     // This cannot overflow;
                     // the output is between `0` and `2^nbits * (2^nbits - 1)`.
@@ -158,36 +132,26 @@ 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;
+                    _ => 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;
-                }
-                i + 1
             }
 
             /// Adds `other` to itself and returns its own mutable reference.
             pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name {
                 use crate::cmp;
                 use crate::iter;
-                use crate::num::bignum::FullOps;
 
                 let mut sz = cmp::max(self.size, other.size);
                 let mut carry = false;
                 for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
-                    let (c, v) = (*a).full_add(*b, carry);
+                    let (v, c) = (*a).carrying_add(*b, carry);
                     *a = v;
                     carry = c;
                 }
@@ -200,13 +164,11 @@ pub fn add<'a>(&'a mut self, other: &$name) -> &'a mut $name {
             }
 
             pub fn add_small(&mut self, other: $ty) -> &mut $name {
-                use crate::num::bignum::FullOps;
-
-                let (mut carry, v) = self.base[0].full_add(other, false);
+                let (v, mut carry) = self.base[0].carrying_add(other, false);
                 self.base[0] = v;
                 let mut i = 1;
                 while carry {
-                    let (c, v) = self.base[i].full_add(0, carry);
+                    let (v, c) = self.base[i].carrying_add(0, carry);
                     self.base[i] = v;
                     carry = c;
                     i += 1;
@@ -221,12 +183,11 @@ pub fn add_small(&mut self, other: $ty) -> &mut $name {
             pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name {
                 use crate::cmp;
                 use crate::iter;
-                use crate::num::bignum::FullOps;
 
                 let sz = cmp::max(self.size, other.size);
                 let mut noborrow = true;
                 for (a, b) in iter::zip(&mut self.base[..sz], &other.base[..sz]) {
-                    let (c, v) = (*a).full_add(!*b, noborrow);
+                    let (v, c) = (*a).carrying_add(!*b, noborrow);
                     *a = v;
                     noborrow = c;
                 }
@@ -238,12 +199,10 @@ pub fn sub<'a>(&'a mut self, other: &$name) -> &'a mut $name {
             /// Multiplies itself by a digit-sized `other` and returns its own
             /// mutable reference.
             pub fn mul_small(&mut self, other: $ty) -> &mut $name {
-                use crate::num::bignum::FullOps;
-
                 let mut sz = self.size;
                 let mut carry = 0;
                 for a in &mut self.base[..sz] {
-                    let (c, v) = (*a).full_mul(other, carry);
+                    let (v, c) = (*a).carrying_mul(other, carry);
                     *a = v;
                     carry = c;
                 }
index 85ceede5b9e3a1b227888b4fa1044d7a01111f67..0b8ed0cc174b42a4a5dcc792087255b52e09fb51 100644 (file)
@@ -675,7 +675,7 @@ pub fn to_radians(self) -> f32 {
     /// Returns the maximum of the two numbers.
     ///
     /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
-    /// This matches the behavior of libm’s fmin.
+    /// This matches the behavior of libm’s fmax.
     ///
     /// ```
     /// let x = 1.0f32;
index 4049c95b130f2a6bdc771a61ed13739ba240e647..5a3cd2a4b92600286983480dd0ea0f9b9ed6544d 100644 (file)
@@ -691,7 +691,7 @@ pub fn to_radians(self) -> f64 {
     /// Returns the maximum of the two numbers.
     ///
     /// Follows the IEEE-754 2008 semantics for maxNum, except for handling of signaling NaNs.
-    /// This matches the behavior of libm’s fmin.
+    /// This matches the behavior of libm’s fmax.
     ///
     /// ```
     /// let x = 1.0_f64;
index a8455fb355b3ce16eba03d21fd70b7cd100c56da..cc26c04a5d42a1e1faf113a5495d91f0212288c8 100644 (file)
-mod unchecked {
-    // 0 < val <= u8::MAX
-    #[inline]
-    pub const fn u8(val: u8) -> u32 {
-        let val = val as u32;
-
-        // For better performance, avoid branches by assembling the solution
-        // in the bits above the low 8 bits.
-
-        // Adding c1 to val gives 10 in the top bits for val < 10, 11 for val >= 10
-        const C1: u32 = 0b11_00000000 - 10; // 758
-        // Adding c2 to val gives 01 in the top bits for val < 100, 10 for val >= 100
-        const C2: u32 = 0b10_00000000 - 100; // 412
-
-        // Value of top bits:
-        //            +c1  +c2  1&2
-        //     0..=9   10   01   00 = 0
-        //   10..=99   11   01   01 = 1
-        // 100..=255   11   10   10 = 2
-        ((val + C1) & (val + C2)) >> 8
-    }
+/// These functions compute the integer logarithm of their type, assuming
+/// that someone has already checked that the the value is strictly positive.
+
+// 0 < val <= u8::MAX
+#[inline]
+pub const fn u8(val: u8) -> u32 {
+    let val = val as u32;
+
+    // For better performance, avoid branches by assembling the solution
+    // in the bits above the low 8 bits.
+
+    // Adding c1 to val gives 10 in the top bits for val < 10, 11 for val >= 10
+    const C1: u32 = 0b11_00000000 - 10; // 758
+    // Adding c2 to val gives 01 in the top bits for val < 100, 10 for val >= 100
+    const C2: u32 = 0b10_00000000 - 100; // 412
+
+    // Value of top bits:
+    //            +c1  +c2  1&2
+    //     0..=9   10   01   00 = 0
+    //   10..=99   11   01   01 = 1
+    // 100..=255   11   10   10 = 2
+    ((val + C1) & (val + C2)) >> 8
+}
 
-    // 0 < val < 100_000
-    #[inline]
-    const fn less_than_5(val: u32) -> u32 {
-        // Similar to u8, when adding one of these constants to val,
-        // we get two possible bit patterns above the low 17 bits,
-        // depending on whether val is below or above the threshold.
-        const C1: u32 = 0b011_00000000000000000 - 10; // 393206
-        const C2: u32 = 0b100_00000000000000000 - 100; // 524188
-        const C3: u32 = 0b111_00000000000000000 - 1000; // 916504
-        const C4: u32 = 0b100_00000000000000000 - 10000; // 514288
-
-        // Value of top bits:
-        //                +c1  +c2  1&2  +c3  +c4  3&4   ^
-        //         0..=9  010  011  010  110  011  010  000 = 0
-        //       10..=99  011  011  011  110  011  010  001 = 1
-        //     100..=999  011  100  000  110  011  010  010 = 2
-        //   1000..=9999  011  100  000  111  011  011  011 = 3
-        // 10000..=99999  011  100  000  111  100  100  100 = 4
-        (((val + C1) & (val + C2)) ^ ((val + C3) & (val + C4))) >> 17
-    }
+// 0 < val < 100_000
+#[inline]
+const fn less_than_5(val: u32) -> u32 {
+    // Similar to u8, when adding one of these constants to val,
+    // we get two possible bit patterns above the low 17 bits,
+    // depending on whether val is below or above the threshold.
+    const C1: u32 = 0b011_00000000000000000 - 10; // 393206
+    const C2: u32 = 0b100_00000000000000000 - 100; // 524188
+    const C3: u32 = 0b111_00000000000000000 - 1000; // 916504
+    const C4: u32 = 0b100_00000000000000000 - 10000; // 514288
+
+    // Value of top bits:
+    //                +c1  +c2  1&2  +c3  +c4  3&4   ^
+    //         0..=9  010  011  010  110  011  010  000 = 0
+    //       10..=99  011  011  011  110  011  010  001 = 1
+    //     100..=999  011  100  000  110  011  010  010 = 2
+    //   1000..=9999  011  100  000  111  011  011  011 = 3
+    // 10000..=99999  011  100  000  111  100  100  100 = 4
+    (((val + C1) & (val + C2)) ^ ((val + C3) & (val + C4))) >> 17
+}
 
-    // 0 < val <= u16::MAX
-    #[inline]
-    pub const fn u16(val: u16) -> u32 {
-        less_than_5(val as u32)
-    }
+// 0 < val <= u16::MAX
+#[inline]
+pub const fn u16(val: u16) -> u32 {
+    less_than_5(val as u32)
+}
 
-    // 0 < val <= u32::MAX
-    #[inline]
-    pub const fn u32(mut val: u32) -> u32 {
-        let mut log = 0;
-        if val >= 100_000 {
-            val /= 100_000;
-            log += 5;
-        }
-        log + less_than_5(val)
+// 0 < val <= u32::MAX
+#[inline]
+pub const fn u32(mut val: u32) -> u32 {
+    let mut log = 0;
+    if val >= 100_000 {
+        val /= 100_000;
+        log += 5;
     }
+    log + less_than_5(val)
+}
 
-    // 0 < val <= u64::MAX
-    #[inline]
-    pub const fn u64(mut val: u64) -> u32 {
-        let mut log = 0;
-        if val >= 10_000_000_000 {
-            val /= 10_000_000_000;
-            log += 10;
-        }
-        if val >= 100_000 {
-            val /= 100_000;
-            log += 5;
-        }
-        log + less_than_5(val as u32)
+// 0 < val <= u64::MAX
+#[inline]
+pub const fn u64(mut val: u64) -> u32 {
+    let mut log = 0;
+    if val >= 10_000_000_000 {
+        val /= 10_000_000_000;
+        log += 10;
     }
-
-    // 0 < val <= u128::MAX
-    #[inline]
-    pub const fn u128(mut val: u128) -> u32 {
-        let mut log = 0;
-        if val >= 100_000_000_000_000_000_000_000_000_000_000 {
-            val /= 100_000_000_000_000_000_000_000_000_000_000;
-            log += 32;
-            return log + u32(val as u32);
-        }
-        if val >= 10_000_000_000_000_000 {
-            val /= 10_000_000_000_000_000;
-            log += 16;
-        }
-        log + u64(val as u64)
+    if val >= 100_000 {
+        val /= 100_000;
+        log += 5;
     }
+    log + less_than_5(val as u32)
+}
 
-    // 0 < val <= i8::MAX
-    #[inline]
-    pub const fn i8(val: i8) -> u32 {
-        u8(val as u8)
+// 0 < val <= u128::MAX
+#[inline]
+pub const fn u128(mut val: u128) -> u32 {
+    let mut log = 0;
+    if val >= 100_000_000_000_000_000_000_000_000_000_000 {
+        val /= 100_000_000_000_000_000_000_000_000_000_000;
+        log += 32;
+        return log + u32(val as u32);
     }
-
-    // 0 < val <= i16::MAX
-    #[inline]
-    pub const fn i16(val: i16) -> u32 {
-        u16(val as u16)
+    if val >= 10_000_000_000_000_000 {
+        val /= 10_000_000_000_000_000;
+        log += 16;
     }
+    log + u64(val as u64)
+}
 
-    // 0 < val <= i32::MAX
-    #[inline]
-    pub const fn i32(val: i32) -> u32 {
-        u32(val as u32)
-    }
+#[cfg(target_pointer_width = "16")]
+#[inline]
+pub const fn usize(val: usize) -> u32 {
+    u16(val as _)
+}
 
-    // 0 < val <= i64::MAX
-    #[inline]
-    pub const fn i64(val: i64) -> u32 {
-        u64(val as u64)
-    }
+#[cfg(target_pointer_width = "32")]
+#[inline]
+pub const fn usize(val: usize) -> u32 {
+    u32(val as _)
+}
 
-    // 0 < val <= i128::MAX
-    #[inline]
-    pub const fn i128(val: i128) -> u32 {
-        u128(val as u128)
-    }
+#[cfg(target_pointer_width = "64")]
+#[inline]
+pub const fn usize(val: usize) -> u32 {
+    u64(val as _)
+}
+
+// 0 < val <= i8::MAX
+#[inline]
+pub const fn i8(val: i8) -> u32 {
+    u8(val as u8)
 }
 
-macro_rules! impl_checked {
-    ($T:ident) => {
-        #[inline]
-        pub const fn $T(val: $T) -> Option<u32> {
-            if val > 0 { Some(unchecked::$T(val)) } else { None }
-        }
-    };
+// 0 < val <= i16::MAX
+#[inline]
+pub const fn i16(val: i16) -> u32 {
+    u16(val as u16)
 }
 
-impl_checked! { u8 }
-impl_checked! { u16 }
-impl_checked! { u32 }
-impl_checked! { u64 }
-impl_checked! { u128 }
-impl_checked! { i8 }
-impl_checked! { i16 }
-impl_checked! { i32 }
-impl_checked! { i64 }
-impl_checked! { i128 }
+// 0 < val <= i32::MAX
+#[inline]
+pub const fn i32(val: i32) -> u32 {
+    u32(val as u32)
+}
+
+// 0 < val <= i64::MAX
+#[inline]
+pub const fn i64(val: i64) -> u32 {
+    u64(val as u64)
+}
+
+// 0 < val <= i128::MAX
+#[inline]
+pub const fn i128(val: i128) -> u32 {
+    u128(val as u128)
+}
index 6f7c5a6d119945fe5acc75bf55d09b2a90b0e694..79436c8e8ede485c5fc93fadd00c1cd6a6e8ffb0 100644 (file)
@@ -2362,7 +2362,11 @@ pub const fn checked_log2(self) -> Option<u32> {
                       without modifying the original"]
         #[inline]
         pub const fn checked_log10(self) -> Option<u32> {
-            int_log10::$ActualT(self as $ActualT)
+            if self > 0 {
+                Some(int_log10::$ActualT(self as $ActualT))
+            } else {
+                None
+            }
         }
 
         /// Computes the absolute value of `self`.
index e3eab07b9df6d7e63ee64cbad51a79c36acd4f3e..721c030b410aec548ecbd15e73630e8bd65ba6f5 100644 (file)
@@ -264,7 +264,7 @@ impl isize {
 
 #[lang = "u8"]
 impl u8 {
-    uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
+    uint_impl! { u8, u8, i8, NonZeroU8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
     "[0x12]", "", "" }
     widening_impl! { u8, u16, 8, unsigned }
 
@@ -813,21 +813,21 @@ pub fn escape_ascii(&self) -> ascii::EscapeDefault {
 
 #[lang = "u16"]
 impl u16 {
-    uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+    uint_impl! { u16, u16, i16, NonZeroU16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
     widening_impl! { u16, u32, 16, unsigned }
 }
 
 #[lang = "u32"]
 impl u32 {
-    uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
+    uint_impl! { u32, u32, i32, NonZeroU32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
     "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
     widening_impl! { u32, u64, 32, unsigned }
 }
 
 #[lang = "u64"]
 impl u64 {
-    uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
+    uint_impl! { u64, u64, i64, NonZeroU64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
@@ -837,7 +837,7 @@ impl u64 {
 
 #[lang = "u128"]
 impl u128 {
-    uint_impl! { u128, u128, i128, 128, 340282366920938463463374607431768211455, 16,
+    uint_impl! { u128, u128, i128, NonZeroU128, 128, 340282366920938463463374607431768211455, 16,
     "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
     "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
     "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
@@ -850,7 +850,7 @@ impl u128 {
 #[cfg(target_pointer_width = "16")]
 #[lang = "usize"]
 impl usize {
-    uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+    uint_impl! { usize, u16, isize, NonZeroUsize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
     widening_impl! { usize, u32, 16, unsigned }
@@ -858,7 +858,7 @@ impl usize {
 #[cfg(target_pointer_width = "32")]
 #[lang = "usize"]
 impl usize {
-    uint_impl! { usize, u32, isize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
+    uint_impl! { usize, u32, isize, NonZeroUsize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
     "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
     widening_impl! { usize, u64, 32, unsigned }
@@ -867,7 +867,7 @@ impl usize {
 #[cfg(target_pointer_width = "64")]
 #[lang = "usize"]
 impl usize {
-    uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
+    uint_impl! { usize, u64, isize, NonZeroUsize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
index 8f895c33a63280f6e376426ae889f79ab9e7fc1d..e21ae48917953530440f1e08086ff558e080b827 100644 (file)
@@ -302,7 +302,7 @@ fn rem(self, other: $Ty) -> $Int {
 
 // A bunch of methods for unsigned nonzero types only.
 macro_rules! nonzero_unsigned_operations {
-    ( $( $Ty: ident($Int: ty); )+ ) => {
+    ( $( $Ty: ident($Int: ident); )+ ) => {
         $(
             impl $Ty {
                 /// Add an unsigned integer to a non-zero value.
@@ -442,6 +442,56 @@ pub const fn checked_next_power_of_two(self) -> Option<$Ty> {
                         None
                     }
                 }
+
+                /// Returns the base 2 logarithm of the number, rounded down.
+                ///
+                /// This is the same operation as
+                #[doc = concat!("[`", stringify!($Int), "::log2`],")]
+                /// except that it has no failure cases to worry about
+                /// since this value can never be zero.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(int_log)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().log2(), 2);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().log2(), 3);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().log2(), 3);")]
+                /// ```
+                #[unstable(feature = "int_log", issue = "70887")]
+                #[must_use = "this returns the result of the operation, \
+                              without modifying the original"]
+                #[inline]
+                pub const fn log2(self) -> u32 {
+                    <$Int>::BITS - 1 - self.leading_zeros()
+                }
+
+                /// Returns the base 10 logarithm of the number, rounded down.
+                ///
+                /// This is the same operation as
+                #[doc = concat!("[`", stringify!($Int), "::log10`],")]
+                /// except that it has no failure cases to worry about
+                /// since this value can never be zero.
+                ///
+                /// # Examples
+                ///
+                /// ```
+                /// #![feature(int_log)]
+                #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+                ///
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().log10(), 1);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().log10(), 2);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().log10(), 2);")]
+                /// ```
+                #[unstable(feature = "int_log", issue = "70887")]
+                #[must_use = "this returns the result of the operation, \
+                              without modifying the original"]
+                #[inline]
+                pub const fn log10(self) -> u32 {
+                    super::int_log10::$Int(self.0)
+                }
             }
         )+
     }
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 1dd8b0a18ab1bd5e81a9f16b872161994d758914..0bb654977764d48c7df40eefa5730247d8580a8c 100644 (file)
@@ -1,5 +1,6 @@
 macro_rules! uint_impl {
-    ($SelfT:ty, $ActualT:ident, $SignedT:ident, $BITS:expr, $MaxV:expr,
+    ($SelfT:ty, $ActualT:ident, $SignedT:ident, $NonZeroT:ident,
+        $BITS:expr, $MaxV:expr,
         $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
         $reversed:expr, $le_bytes:expr, $be_bytes:expr,
         $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
@@ -839,12 +840,10 @@ pub const fn checked_log(self, base: Self) -> Option<u32> {
                       without modifying the original"]
         #[inline]
         pub const fn checked_log2(self) -> Option<u32> {
-            if self <= 0 {
-                None
+            if let Some(x) = <$NonZeroT>::new(self) {
+                Some(x.log2())
             } else {
-                // SAFETY: We just checked that this number is positive
-                let log = (Self::BITS - 1) - unsafe { intrinsics::ctlz_nonzero(self) as u32 };
-                Some(log)
+                None
             }
         }
 
@@ -863,7 +862,11 @@ pub const fn checked_log2(self) -> Option<u32> {
                       without modifying the original"]
         #[inline]
         pub const fn checked_log10(self) -> Option<u32> {
-            int_log10::$ActualT(self as $ActualT)
+            if let Some(x) = <$NonZeroT>::new(self) {
+                Some(x.log10())
+            } else {
+                None
+            }
         }
 
         /// Checked negation. Computes `-self`, returning `None` unless `self ==
index 1ec119a71e42c84cbc356e1cf4b6f82d24887d1a..611f4ab38ab334d713b677b6d3a4fc75277bf4be 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));
 //! ```
@@ -551,6 +551,29 @@ pub const fn is_some(&self) -> bool {
         matches!(*self, Some(_))
     }
 
+    /// Returns `true` if the option is a [`Some`] wrapping a value matching the predicate.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(is_some_with)]
+    ///
+    /// let x: Option<u32> = Some(2);
+    /// assert_eq!(x.is_some_with(|&x| x > 1), true);
+    ///
+    /// let x: Option<u32> = Some(0);
+    /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+    ///
+    /// let x: Option<u32> = None;
+    /// assert_eq!(x.is_some_with(|&x| x > 1), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "is_some_with", issue = "93050")]
+    pub fn is_some_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+        matches!(self, Some(x) if f(x))
+    }
+
     /// Returns `true` if the option is a [`None`] value.
     ///
     /// # Examples
index 0fb8846288bee7835f415a159ff0c369dbd017a8..d91289fad2009ea64c65b8c68df3de8b9f80d4b0 100644 (file)
@@ -56,8 +56,8 @@
 #[doc(no_inline)]
 pub use crate::{
     assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
-    format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, module_path,
-    option_env, stringify, trace_macros,
+    format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
+    stringify, trace_macros,
 };
 
 #[unstable(
index 7b826f921ca87b1eef0a8a7a8a3683e3b944baec..485a5965f4cf740c4b17084c83141645dbef53a3 100644 (file)
@@ -439,7 +439,7 @@ pub const fn wrapping_offset(self, count: isize) -> *const T
     /// }
     /// ```
     #[stable(feature = "ptr_offset_from", since = "1.47.0")]
-    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
+    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
     #[inline]
     pub const unsafe fn offset_from(self, origin: *const T) -> isize
     where
index 6c50d4052976f01e8672a943e56562eddffe75ef..1412e836ebfc28b94759befa73195ea0c0c52965 100644 (file)
@@ -617,7 +617,7 @@ pub const fn guaranteed_eq(self, other: *mut T) -> bool
     /// }
     /// ```
     #[stable(feature = "ptr_offset_from", since = "1.47.0")]
-    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "41079")]
+    #[rustc_const_unstable(feature = "const_ptr_offset_from", issue = "92980")]
     #[inline(always)]
     pub const unsafe fn offset_from(self, origin: *const T) -> isize
     where
index 575fd2b42d2132d72c9c91f7323542056a9145ea..fbd6d419236ae110240b9eb4b91ebfd113d3d0dd 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));
 //! ```
@@ -542,6 +542,29 @@ pub const fn is_ok(&self) -> bool {
         matches!(*self, Ok(_))
     }
 
+    /// Returns `true` if the result is [`Ok`] wrapping a value matching the predicate.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(is_some_with)]
+    ///
+    /// let x: Result<u32, &str> = Ok(2);
+    /// assert_eq!(x.is_ok_with(|&x| x > 1), true);
+    ///
+    /// let x: Result<u32, &str> = Ok(0);
+    /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+    ///
+    /// let x: Result<u32, &str> = Err("hey");
+    /// assert_eq!(x.is_ok_with(|&x| x > 1), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "is_some_with", issue = "93050")]
+    pub fn is_ok_with(&self, f: impl FnOnce(&T) -> bool) -> bool {
+        matches!(self, Ok(x) if f(x))
+    }
+
     /// Returns `true` if the result is [`Err`].
     ///
     /// # Examples
@@ -563,6 +586,30 @@ pub const fn is_err(&self) -> bool {
         !self.is_ok()
     }
 
+    /// Returns `true` if the result is [`Err`] wrapping a value matching the predicate.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(is_some_with)]
+    /// use std::io::{Error, ErrorKind};
+    ///
+    /// let x: Result<u32, Error> = Err(Error::new(ErrorKind::NotFound, "!"));
+    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), true);
+    ///
+    /// let x: Result<u32, Error> = Err(Error::new(ErrorKind::PermissionDenied, "!"));
+    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+    ///
+    /// let x: Result<u32, Error> = Ok(123);
+    /// assert_eq!(x.is_err_with(|x| x.kind() == ErrorKind::NotFound), false);
+    /// ```
+    #[must_use]
+    #[inline]
+    #[unstable(feature = "is_some_with", issue = "93050")]
+    pub fn is_err_with(&self, f: impl FnOnce(&E) -> bool) -> bool {
+        matches!(self, Err(x) if f(x))
+    }
+
     /////////////////////////////////////////////////////////////////////////
     // Adapter for each variant
     /////////////////////////////////////////////////////////////////////////
index 27243d8ca703060aea8362fd75fc301a02150200..792016902aebe925b42f2e11bd7682f9c59263c3 100644 (file)
 /// loads and stores of `u8`.
 #[cfg(target_has_atomic_load_store = "8")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "AtomicBool"]
 #[repr(C, align(1))]
 pub struct AtomicBool {
     v: UnsafeCell<u8>,
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 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 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 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 ea0c230fa42db7438021169ccac9a0dfe6d366d2..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() {
@@ -606,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]
@@ -632,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]
@@ -810,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 9c1b79d696697f7ecc94af9b2096e8621c1404af..d859bff1a45fa0f348d049adfe84097abc5d49ac 100644 (file)
@@ -373,38 +373,61 @@ impl CString {
     /// the position of the nul byte.
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
-        trait SpecIntoVec {
-            fn into_vec(self) -> Vec<u8>;
+        trait SpecNewImpl {
+            fn spec_new_impl(self) -> Result<CString, NulError>;
         }
-        impl<T: Into<Vec<u8>>> SpecIntoVec for T {
-            default fn into_vec(self) -> Vec<u8> {
-                self.into()
+
+        impl<T: Into<Vec<u8>>> SpecNewImpl for T {
+            default fn spec_new_impl(self) -> Result<CString, NulError> {
+                let bytes: Vec<u8> = self.into();
+                match memchr::memchr(0, &bytes) {
+                    Some(i) => Err(NulError(i, bytes)),
+                    None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
+                }
             }
         }
-        // Specialization for avoiding reallocation.
-        impl SpecIntoVec for &'_ [u8] {
-            fn into_vec(self) -> Vec<u8> {
-                let mut v = Vec::with_capacity(self.len() + 1);
-                v.extend(self);
-                v
+
+        // Specialization for avoiding reallocation
+        #[inline(always)] // Without that it is not inlined into specializations
+        fn spec_new_impl_bytes(bytes: &[u8]) -> Result<CString, NulError> {
+            // We cannot have such large slice that we would overflow here
+            // but using `checked_add` allows LLVM to assume that capacity never overflows
+            // and generate twice shorter code.
+            // `saturating_add` doesn't help for some reason.
+            let capacity = bytes.len().checked_add(1).unwrap();
+
+            // Allocate before validation to avoid duplication of allocation code.
+            // We still need to allocate and copy memory even if we get an error.
+            let mut buffer = Vec::with_capacity(capacity);
+            buffer.extend(bytes);
+
+            // Check memory of self instead of new buffer.
+            // This allows better optimizations if lto enabled.
+            match memchr::memchr(0, bytes) {
+                Some(i) => Err(NulError(i, buffer)),
+                None => Ok(unsafe { CString::from_vec_unchecked(buffer) }),
             }
         }
-        impl SpecIntoVec for &'_ str {
-            fn into_vec(self) -> Vec<u8> {
-                let mut v = Vec::with_capacity(self.len() + 1);
-                v.extend(self.as_bytes());
-                v
+
+        impl SpecNewImpl for &'_ [u8] {
+            fn spec_new_impl(self) -> Result<CString, NulError> {
+                spec_new_impl_bytes(self)
             }
         }
 
-        Self::_new(SpecIntoVec::into_vec(t))
-    }
+        impl SpecNewImpl for &'_ str {
+            fn spec_new_impl(self) -> Result<CString, NulError> {
+                spec_new_impl_bytes(self.as_bytes())
+            }
+        }
 
-    fn _new(bytes: Vec<u8>) -> Result<CString, NulError> {
-        match memchr::memchr(0, &bytes) {
-            Some(i) => Err(NulError(i, bytes)),
-            None => Ok(unsafe { CString::from_vec_unchecked(bytes) }),
+        impl SpecNewImpl for &'_ mut [u8] {
+            fn spec_new_impl(self) -> Result<CString, NulError> {
+                spec_new_impl_bytes(self)
+            }
         }
+
+        t.spec_new_impl()
     }
 
     /// Creates a C-compatible string by consuming a byte vector,
index dae85027b6c2926d97de5179f08047107dae2494..5537ec18d34a93afe5206397d1f8d54fd747691d 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(())
     /// }
     /// ```
@@ -1049,7 +1050,7 @@ pub fn is_file(&self) -> bool {
     ///
     /// fn main() -> std::io::Result<()> {
     ///     let link_path = Path::new("link");
-    ///     symlink("/origin_does_not_exists/", link_path)?;
+    ///     symlink("/origin_does_not_exist/", link_path)?;
     ///
     ///     let metadata = fs::symlink_metadata(link_path)?;
     ///
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 d5f9d20c426e28b22ba47f535d1d9ba12c9ba6d2..17fe0011569b0a586741f51b716de90433ccd3ae 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(intra_doc_pointers)]
 #![feature(lang_items)]
 #![feature(linkage)]
-#![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)]
 #![feature(unboxed_closures)]
 #![feature(unwrap_infallible)]
 #![feature(vec_into_raw_parts)]
-#![feature(vec_spare_capacity)]
 // NB: the above list is sorted to minimize merge conflicts.
 #![default_lib_allocator]
 
@@ -572,8 +569,8 @@ pub mod task {
 #[allow(deprecated)]
 pub use core::{
     assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args,
-    env, file, format_args, format_args_nl, include, include_bytes, include_str, line, llvm_asm,
-    log_syntax, module_path, option_env, stringify, trace_macros,
+    env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax,
+    module_path, option_env, stringify, trace_macros,
 };
 
 #[unstable(
index 5dc75d32ec885788d9ac3c82b1074a293aae1a5c..23cbfaeef485ab0711b0f85b12d2bb4fc317f204 100644 (file)
@@ -57,6 +57,7 @@ macro_rules! panic {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "print_macro")]
 #[allow_internal_unstable(print_internals)]
 macro_rules! print {
     ($($arg:tt)*) => ($crate::io::_print($crate::format_args!($($arg)*)));
@@ -90,6 +91,7 @@ macro_rules! print {
 /// ```
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "println_macro")]
 #[allow_internal_unstable(print_internals, format_args_nl)]
 macro_rules! println {
     () => ($crate::print!("\n"));
@@ -121,6 +123,7 @@ macro_rules! println {
 /// ```
 #[macro_export]
 #[stable(feature = "eprint", since = "1.19.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "eprint_macro")]
 #[allow_internal_unstable(print_internals)]
 macro_rules! eprint {
     ($($arg:tt)*) => ($crate::io::_eprint($crate::format_args!($($arg)*)));
@@ -149,6 +152,7 @@ macro_rules! eprint {
 /// ```
 #[macro_export]
 #[stable(feature = "eprint", since = "1.19.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "eprintln_macro")]
 #[allow_internal_unstable(print_internals, format_args_nl)]
 macro_rules! eprintln {
     () => ($crate::eprint!("\n"));
@@ -282,6 +286,7 @@ macro_rules! eprintln {
 /// [`debug!`]: https://docs.rs/log/*/log/macro.debug.html
 /// [`log`]: https://crates.io/crates/log
 #[macro_export]
+#[cfg_attr(not(test), rustc_diagnostic_item = "dbg_macro")]
 #[stable(feature = "dbg_macro", since = "1.32.0")]
 macro_rules! dbg {
     // NOTE: We cannot use `concat!` to make a static string as a format argument
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 7d401cff591c19d83e9a8c0b4eb5e8e0ff5c70f2..f509403fe2e43be99525793dd8cd2c93296b5d75 100644 (file)
@@ -2806,7 +2806,7 @@ pub fn is_dir(&self) -> bool {
     /// use std::os::unix::fs::symlink;
     ///
     /// let link_path = Path::new("link");
-    /// symlink("/origin_does_not_exists/", link_path).unwrap();
+    /// symlink("/origin_does_not_exist/", link_path).unwrap();
     /// assert_eq!(link_path.is_symlink(), true);
     /// assert_eq!(link_path.exists(), false);
     /// ```
index b52bcdfca9e07152062fe44b3db98f7f6293c546..53124daa3a683a0fafa0f17766462d428b3b9f90 100644 (file)
@@ -40,9 +40,8 @@
 #[doc(no_inline)]
 pub use core::prelude::v1::{
     assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
-    format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, module_path,
-    option_env, stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq,
-    PartialOrd,
+    format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
+    stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
 };
 
 #[unstable(
index 1d2f6e976800b88b67e603630e803adc3a997fd0..1be3ed757ba295c97ebf613d2ff38563e1c3f4f8 100644 (file)
@@ -142,6 +142,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// [`std::thread::LocalKey`]: crate::thread::LocalKey
 #[macro_export]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(test), rustc_diagnostic_item = "thread_local_macro")]
 #[allow_internal_unstable(thread_local_internals)]
 macro_rules! thread_local {
     // empty (base case for the recursion)
index ae4b65871ecb15d8ee39c2fbf9a80ac4ee5b5ae4..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),
@@ -1261,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()
     }
 }
 
@@ -1400,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()
     }
 
@@ -1416,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
     }
 }
 
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 2adc17a5442614dbe34626fdd9b32de7c07b8086..11c98f6eb9c4ba48b2362ad4960343b312d056b8 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 2adc17a5442614dbe34626fdd9b32de7c07b8086
+Subproject commit 11c98f6eb9c4ba48b2362ad4960343b312d056b8
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 7c36bb264c45ee0b5ca049a409759d8d88b90d58..6d7ab15326c5fc194fd94670d26c5e692cb27d7a 100644 (file)
@@ -863,7 +863,7 @@ class RustBuild(object):
         >>> rb.get_toml("key2")
         'value2'
 
-        If the key does not exists, the result is None:
+        If the key does not exist, the result is None:
 
         >>> rb.get_toml("key3") is None
         True
index 7bffc1c15206b67b4d59436673051d870ec08a63..06ca3ce21b395a2990329a8273c20b8fa91b2058 100644 (file)
@@ -55,8 +55,8 @@ class ProgramOutOfDate(unittest.TestCase):
     def tearDown(self):
         rmtree(self.container)
 
-    def test_stamp_path_does_not_exists(self):
-        """Return True when the stamp file does not exists"""
+    def test_stamp_path_does_not_exist(self):
+        """Return True when the stamp file does not exist"""
         if os.path.exists(self.rustc_stamp_path):
             os.unlink(self.rustc_stamp_path)
         self.assertTrue(self.build.program_out_of_date(self.rustc_stamp_path, self.key))
index 043b38ecece7da5cb58ab42914468bf0543c123a..e17de0ba49ebc464d949bc3ca2a8495647b4b525 100644 (file)
@@ -227,8 +227,10 @@ fn copy_self_contained_objects(
             target_deps.push((target, DependencyType::TargetSelfContained));
         }
 
-        let libunwind_path = copy_llvm_libunwind(builder, target, &libdir_self_contained);
-        target_deps.push((libunwind_path, DependencyType::TargetSelfContained));
+        if !target.starts_with("s390x") {
+            let libunwind_path = copy_llvm_libunwind(builder, target, &libdir_self_contained);
+            target_deps.push((libunwind_path, DependencyType::TargetSelfContained));
+        }
     } else if target.ends_with("-wasi") {
         let srcdir = builder
             .wasi_root(target)
index 7d9b3da48ecb0578e12720eddb115844ecea3b66..a46a4e63714c2fe8be4a4a726a08eed119de76ca 100644 (file)
@@ -1483,11 +1483,10 @@ fn filter(contents: &str, marker: &str) -> String {
             };
             prepare("rustc");
             prepare("cargo");
-            prepare("rust-docs");
             prepare("rust-std");
             prepare("rust-analysis");
             prepare("clippy");
-            for tool in &["rust-demangler", "rls", "rust-analyzer", "miri"] {
+            for tool in &["rust-docs", "rust-demangler", "rls", "rust-analyzer", "miri"] {
                 if built_tools.contains(tool) {
                     prepare(tool);
                 }
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 ac5d5822bfbd53d23cf34877e1343c6210c6b131..a70cdc4b519e664e9a50fbca8fc3b6cc8649931d 100644 (file)
@@ -496,6 +496,7 @@ jobs:
                 --enable-full-tools
                 --enable-sanitizers
                 --enable-profiler
+                --disable-docs
                 --set rust.jemalloc
                 --set llvm.ninja=false
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
index d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3c..f17df27fc14696912c48b8b7a7a8fa49e648088d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit d3740fb7aad0ea4a80ae20f64dee3a8cfc0c5c3c
+Subproject commit f17df27fc14696912c48b8b7a7a8fa49e648088d
index c05c452b36358821bf4122f9c418674edd1d713d..66d097d3d80e8f88c288c6879c7c2b909ecf8ad4 160000 (submodule)
@@ -1 +1 @@
-Subproject commit c05c452b36358821bf4122f9c418674edd1d713d
+Subproject commit 66d097d3d80e8f88c288c6879c7c2b909ecf8ad4
index f8ba2f12df60ee19b96de24ae5b73af3de8a446b..4dee6eb63d728ffb9e7a2ed443e9ada9275c69d2 160000 (submodule)
@@ -1 +1 @@
-Subproject commit f8ba2f12df60ee19b96de24ae5b73af3de8a446b
+Subproject commit 4dee6eb63d728ffb9e7a2ed443e9ada9275c69d2
index 875464457c4104686faf667f47848aa7b0f0a744..78dd6a4684cf8d6b72275fab6d0429ea40b66338 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 875464457c4104686faf667f47848aa7b0f0a744
+Subproject commit 78dd6a4684cf8d6b72275fab6d0429ea40b66338
index 69a0304d41d8c958445603e9e1f65897a1238490..53f7108aca36777e6dfdd5df9c072f7228bc4745 100644 (file)
@@ -13,6 +13,7 @@
 - [JSON Output](json.md)
 - [Tests](tests/index.md)
 - [Platform Support](platform-support.md)
+    - [Template for target-specific documentation](platform-support/TEMPLATE.md)
     - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
     - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
     - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
index 7f482f0f2b1a084fd0c1501a4dac6f8906ffcb35..11925ab9785889e15dc6696b8c02c1322ad3b3e8 100644 (file)
@@ -170,6 +170,12 @@ The valid types of print values are:
   include a diagnostic note that indicates the linker flags to use when
   linking the resulting static library. The note starts with the text
   `native-static-libs:` to make it easier to fetch the output.
+- `link-args` — This flag does not disable the `--emit` step. When linking,
+  this flag causes `rustc` to print the full linker invocation in a
+  human-readable form. This can be useful when debugging linker options. The
+  exact format of this debugging output is not a stable guarantee, other than
+  that it will include the linker executable and the text of each command-line
+  argument passed to the linker.
 
 [conditional compilation]: ../reference/conditional-compilation.html
 
diff --git a/src/doc/rustc/src/platform-support/TEMPLATE.md b/src/doc/rustc/src/platform-support/TEMPLATE.md
new file mode 100644 (file)
index 0000000..e64783f
--- /dev/null
@@ -0,0 +1,52 @@
+# `target-name-here`
+
+**Tier: 3**
+
+One-sentence description of the target (e.g. CPU, OS)
+
+## Target maintainers
+
+- Some Person, `email@example.org`, https://github.com/...
+
+## Requirements
+
+Does the target support host tools, or only cross-compilation? Does the target
+support std, or alloc (either with a default allocator, or if the user supplies
+an allocator)?
+
+Document the expectations of binaries built for the target. Do they assume
+specific minimum features beyond the baseline of the CPU/environment/etc? What
+version of the OS or environment do they expect?
+
+Are there notable `#[target_feature(...)]` or `-C target-feature=` values that
+programs may wish to use?
+
+What calling convention does `extern "C"` use on the target?
+
+What format do binaries use by default? ELF, PE, something else?
+
+## Building the target
+
+If Rust doesn't build the target by default, how can users build it? Can users
+just add it to the `target` list in `config.toml`?
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+## Testing
+
+Does the target support running binaries, or do binaries have varying
+expectations that prevent having a standard way to run them? If users can run
+binaries, can they do so in some common emulator, or do they need native
+hardware? Does the target support running the Rust testsuite?
+
+## Cross-compilation toolchains and C code
+
+Does the target support C code? If so, what toolchain target should users use
+to build compatible C code? (This may match the target triple, or it may be a
+toolchain for a different target triple, potentially with specific options or
+caveats.)
index cc02b294b44697f7f1fd6d28b61821433ccdecbf..53d0470fa8135c491b119abeaa858c96405e7953 100644 (file)
@@ -62,13 +62,22 @@ not preclude an existing target's maintainers using issues (on the Rust
 repository or otherwise) to track requirements that have not yet been met, as
 appropriate; however, before officially proposing the introduction or promotion
 of a target, it should meet all of the necessary requirements. A target
-proposal is encouraged to quote the corresponding requirements verbatim as part
-of explaining how the target meets those requirements.
+proposal must quote the corresponding requirements verbatim and respond to them
+as part of explaining how the target meets those requirements. (For the
+requirements that simply state that the target or the target developers must
+not do something, it suffices to acknowledge the requirement.)
 
 For a list of all supported targets and their corresponding tiers ("tier 3",
 "tier 2", "tier 2 with host tools", "tier 1", or "tier 1 with host tools"), see
 [platform support](platform-support.md).
 
+Several parts of this policy require providing target-specific documentation.
+Such documentation should typically appear in a subdirectory of the
+platform-support section of this rustc manual, with a link from the target's
+entry in [platform support](platform-support.md). Use
+[TEMPLATE.md](platform-support/TEMPLATE.md) as a base, and see other
+documentation in that directory for examples.
+
 Note that a target must have already received approval for the next lower tier,
 and spent a reasonable amount of time at that tier, before making a proposal
 for promotion to the next higher tier; this is true even if a target meets the
@@ -139,17 +148,19 @@ approved by the appropriate team for that shared code before acceptance.
     or binary. In other words, the introduction of the target must not cause a
     user installing or running a version of Rust or the Rust tools to be
     subject to any new license requirements.
-  - If the target supports building host tools (such as `rustc` or `cargo`),
-    those host tools must not depend on proprietary (non-FOSS) libraries, other
-    than ordinary runtime libraries supplied by the platform and commonly used
-    by other binaries built for the target. For instance, `rustc` built for the
-    target may depend on a common proprietary C runtime library or console
-    output library, but must not depend on a proprietary code generation
-    library or code optimization library. Rust's license permits such
-    combinations, but the Rust project has no interest in maintaining such
-    combinations within the scope of Rust itself, even at tier 3.
-  - Targets should not require proprietary (non-FOSS) components to link a
-    functional binary or library.
+  - Compiling, linking, and emitting functional binaries, libraries, or other
+    code for the target (whether hosted on the target itself or cross-compiling
+    from another target) must not depend on proprietary (non-FOSS) libraries.
+    Host tools built for the target itself may depend on the ordinary runtime
+    libraries supplied by the platform and commonly used by other applications
+    built for the target, but those libraries must not be required for code
+    generation for the target; cross-compilation to the target must not require
+    such libraries at all. For instance, `rustc` built for the target may
+    depend on a common proprietary C runtime library or console output library,
+    but must not depend on a proprietary code generation library or code
+    optimization library. Rust's license permits such combinations, but the
+    Rust project has no interest in maintaining such combinations within the
+    scope of Rust itself, even at tier 3.
   - "onerous" here is an intentionally subjective term. At a minimum, "onerous"
     legal/licensing terms include but are *not* limited to: non-disclosure
     requirements, non-compete requirements, contributor license agreements
@@ -184,9 +195,9 @@ approved by the appropriate team for that shared code before acceptance.
   target not implementing those portions.
 - The target must provide documentation for the Rust community explaining how
   to build for the target, using cross-compilation if possible. If the target
-  supports running tests (even if they do not pass), the documentation must
-  explain how to run tests for the target, using emulation if possible or
-  dedicated hardware if necessary.
+  supports running binaries, or running tests (even if they do not pass), the
+  documentation must explain how to run such binaries or tests for the target,
+  using emulation if possible or dedicated hardware if necessary.
 - Tier 3 targets must not impose burden on the authors of pull requests, or
   other developers in the community, to maintain the target. In particular,
   do not post comments (automated or manual) on a PR that derail or suggest a
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
diff --git a/src/doc/unstable-book/src/library-features/llvm-asm.md b/src/doc/unstable-book/src/library-features/llvm-asm.md
deleted file mode 100644 (file)
index 0941249..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-# `llvm_asm`
-
-The tracking issue for this feature is: [#70173]
-
-[#70173]: https://github.com/rust-lang/rust/issues/70173
-
-------------------------
-
-For extremely low-level manipulations and performance reasons, one
-might wish to control the CPU directly. Rust supports using inline
-assembly to do this via the `llvm_asm!` macro.
-
-```rust,ignore (pseudo-code)
-llvm_asm!(assembly template
-   : output operands
-   : input operands
-   : clobbers
-   : options
-   );
-```
-
-Any use of `llvm_asm` is feature gated (requires `#![feature(llvm_asm)]` on the
-crate to allow) and of course requires an `unsafe` block.
-
-> **Note**: the examples here are given in x86/x86-64 assembly, but
-> all platforms are supported.
-
-## Assembly template
-
-The `assembly template` is the only required parameter and must be a
-literal string (i.e. `""`)
-
-```rust
-#![feature(llvm_asm)]
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn foo() {
-    unsafe {
-        llvm_asm!("NOP");
-    }
-}
-
-// Other platforms:
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-fn foo() { /* ... */ }
-
-fn main() {
-    // ...
-    foo();
-    // ...
-}
-```
-
-(The `feature(llvm_asm)` and `#[cfg]`s are omitted from now on.)
-
-Output operands, input operands, clobbers and options are all optional
-but you must add the right number of `:` if you skip them:
-
-```rust
-# #![feature(llvm_asm)]
-# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-# fn main() { unsafe {
-llvm_asm!("xor %eax, %eax"
-    :
-    :
-    : "eax"
-   );
-# } }
-# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-# fn main() {}
-```
-
-Whitespace also doesn't matter:
-
-```rust
-# #![feature(llvm_asm)]
-# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-# fn main() { unsafe {
-llvm_asm!("xor %eax, %eax" ::: "eax");
-# } }
-# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-# fn main() {}
-```
-
-## Operands
-
-Input and output operands follow the same format: `:
-"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
-expressions must be mutable place, or not yet assigned:
-
-```rust
-# #![feature(llvm_asm)]
-# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn add(a: i32, b: i32) -> i32 {
-    let c: i32;
-    unsafe {
-        llvm_asm!("add $2, $0"
-             : "=r"(c)
-             : "0"(a), "r"(b)
-             );
-    }
-    c
-}
-# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-# fn add(a: i32, b: i32) -> i32 { a + b }
-
-fn main() {
-    assert_eq!(add(3, 14159), 14162)
-}
-```
-
-If you would like to use real operands in this position, however,
-you are required to put curly braces `{}` around the register that
-you want, and you are required to put the specific size of the
-operand. This is useful for very low level programming, where
-which register you use is important:
-
-```rust
-# #![feature(llvm_asm)]
-# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-# unsafe fn read_byte_in(port: u16) -> u8 {
-let result: u8;
-llvm_asm!("in %dx, %al" : "={al}"(result) : "{dx}"(port));
-result
-# }
-```
-
-## Clobbers
-
-Some instructions modify registers which might otherwise have held
-different values so we use the clobbers list to indicate to the
-compiler not to assume any values loaded into those registers will
-stay valid.
-
-```rust
-# #![feature(llvm_asm)]
-# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-# fn main() { unsafe {
-// Put the value 0x200 in eax:
-llvm_asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
-# } }
-# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-# fn main() {}
-```
-
-Input and output registers need not be listed since that information
-is already communicated by the given constraints. Otherwise, any other
-registers used either implicitly or explicitly should be listed.
-
-If the assembly changes the condition code register `cc` should be
-specified as one of the clobbers. Similarly, if the assembly modifies
-memory, `memory` should also be specified.
-
-## Options
-
-The last section, `options` is specific to Rust. The format is comma
-separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to
-specify some extra info about the inline assembly:
-
-Current valid options are:
-
-1. `volatile` - specifying this is analogous to
-   `__asm__ __volatile__ (...)` in gcc/clang.
-2. `alignstack` - certain instructions expect the stack to be
-   aligned a certain way (i.e. SSE) and specifying this indicates to
-   the compiler to insert its usual stack alignment code
-3. `intel` - use intel syntax instead of the default AT&T.
-
-```rust
-# #![feature(llvm_asm)]
-# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-# fn main() {
-let result: i32;
-unsafe {
-   llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")
-}
-println!("eax is currently {}", result);
-# }
-# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-# fn main() {}
-```
-
-## More Information
-
-The current implementation of the `llvm_asm!` macro is a direct binding to [LLVM's
-inline assembler expressions][llvm-docs], so be sure to check out [their
-documentation as well][llvm-docs] for more information about clobbers,
-constraints, etc.
-
-[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions
index 7ed317c778fceaa638975276e22e51153afe6c6a..de1717b3f3f9a983ecc145ffb19f71c6f807c1b1 100644 (file)
@@ -83,7 +83,9 @@ def check_type(ty):
                         check_type(arg["const"]["type"])
                 for binding in args["angle_bracketed"]["bindings"]:
                     if "equality" in binding["binding"]:
-                        check_type(binding["binding"]["equality"])
+                        term = binding["binding"]["equality"]
+                        if "type" in term: check_type(term["type"])
+                        elif "const" in term: check_type(term["const"])
                     elif "constraint" in binding["binding"]:
                         for bound in binding["binding"]["constraint"]:
                             check_generic_bound(bound)
index 48a341ffe083710770023c465dfe4b5d03a2b40c..6bb235b2c8347cddbd461e9d6316b92b8dfb7291 100644 (file)
@@ -401,7 +401,7 @@ def get_tree_count(tree, path):
     return len(tree.findall(path))
 
 
-def check_snapshot(snapshot_name, tree):
+def check_snapshot(snapshot_name, tree, normalize_to_text):
     assert rust_test_path.endswith('.rs')
     snapshot_path = '{}.{}.{}'.format(rust_test_path[:-3], snapshot_name, 'html')
     try:
@@ -413,7 +413,10 @@ def check_snapshot(snapshot_name, tree):
         else:
             raise FailedCheck('No saved snapshot value')
 
-    actual_str = ET.tostring(tree).decode('utf-8')
+    if not normalize_to_text:
+        actual_str = ET.tostring(tree).decode('utf-8')
+    else:
+        actual_str = flatten(tree)
 
     if expected_str != actual_str:
         if bless:
@@ -494,11 +497,16 @@ def check_command(c, cache):
                 [snapshot_name, html_path, pattern] = c.args
                 tree = cache.get_tree(html_path)
                 xpath = normalize_xpath(pattern)
+                normalize_to_text = False
+                if xpath.endswith('/text()'):
+                    xpath = xpath[:-7]
+                    normalize_to_text = True
+
                 subtrees = tree.findall(xpath)
                 if len(subtrees) == 1:
                     [subtree] = subtrees
                     try:
-                        check_snapshot(snapshot_name, subtree)
+                        check_snapshot(snapshot_name, subtree, normalize_to_text)
                         ret = True
                     except FailedCheck as err:
                         cerr = str(err)
index a3cb982f277a08860d4d4c8dc08dcd5b117510b7..67d167e86df7f66e3749137e13fe465d673d9943 100644 (file)
@@ -8,9 +8,11 @@ path = "lib.rs"
 
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
+askama = { version = "0.11", default-features = false, features = ["config"] }
+atty = "0.2"
 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 +22,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"
diff --git a/src/librustdoc/askama.toml b/src/librustdoc/askama.toml
new file mode 100644 (file)
index 0000000..0c984f6
--- /dev/null
@@ -0,0 +1,2 @@
+[general]
+dirs = ["html/templates"]
index 09692d27e8fbeb016b655bc54691b42d32f8baf7..18a4d8a475380f328ec17ef2792a5114c1e66231 100644 (file)
@@ -553,8 +553,10 @@ fn param_env_to_generics(
                             if self.is_fn_trait(trait_) && left_name == sym::Output {
                                 ty_to_fn
                                     .entry(*ty.clone())
-                                    .and_modify(|e| *e = (e.0.clone(), Some(rhs.clone())))
-                                    .or_insert((None, Some(rhs)));
+                                    .and_modify(|e| {
+                                        *e = (e.0.clone(), Some(rhs.ty().unwrap().clone()))
+                                    })
+                                    .or_insert((None, Some(rhs.ty().unwrap().clone())));
                                 continue;
                             }
 
@@ -570,7 +572,7 @@ fn param_env_to_generics(
                                 GenericArgs::AngleBracketed { ref mut bindings, .. } => {
                                     bindings.push(TypeBinding {
                                         name: left_name,
-                                        kind: TypeBindingKind::Equality { ty: rhs },
+                                        kind: TypeBindingKind::Equality { term: rhs },
                                     });
                                 }
                                 GenericArgs::Parenthesized { .. } => {
index b91ba5523e0741bf950fbfc341147c135a481d21..a2e612955b3498cecb506dc756b9d2735af0e0e4 100644 (file)
@@ -9,7 +9,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::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!(
index d80e79d164a78e3e8d2e3c0d3028cf5e5af1020d..e759baa045892d3bbe1a6e97f42bc6a5fe6e3b42 100644 (file)
@@ -272,9 +272,10 @@ fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
                 bounds: wrp.bounds.iter().filter_map(|x| x.clean(cx)).collect(),
             },
 
-            hir::WherePredicate::EqPredicate(ref wrp) => {
-                WherePredicate::EqPredicate { lhs: wrp.lhs_ty.clean(cx), rhs: wrp.rhs_ty.clean(cx) }
-            }
+            hir::WherePredicate::EqPredicate(ref wrp) => WherePredicate::EqPredicate {
+                lhs: wrp.lhs_ty.clean(cx),
+                rhs: wrp.rhs_ty.clean(cx).into(),
+            },
         }
     }
 }
@@ -352,10 +353,31 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Option<WherePredicate> {
     }
 }
 
+impl<'tcx> Clean<Term> for ty::Term<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Term {
+        match self {
+            ty::Term::Ty(ty) => Term::Type(ty.clean(cx)),
+            ty::Term::Const(c) => Term::Constant(c.clean(cx)),
+        }
+    }
+}
+
+impl<'tcx> Clean<Term> for hir::Term<'tcx> {
+    fn clean(&self, cx: &mut DocContext<'_>) -> Term {
+        match self {
+            hir::Term::Ty(ty) => Term::Type(ty.clean(cx)),
+            hir::Term::Const(c) => {
+                let def_id = cx.tcx.hir().local_def_id(c.hir_id);
+                Term::Constant(ty::Const::from_anon_const(cx.tcx, def_id).clean(cx))
+            }
+        }
+    }
+}
+
 impl<'tcx> Clean<WherePredicate> for ty::ProjectionPredicate<'tcx> {
     fn clean(&self, cx: &mut DocContext<'_>) -> WherePredicate {
-        let ty::ProjectionPredicate { projection_ty, ty } = self;
-        WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: ty.clean(cx) }
+        let ty::ProjectionPredicate { projection_ty, term } = self;
+        WherePredicate::EqPredicate { lhs: projection_ty.clean(cx), rhs: term.clean(cx) }
     }
 }
 
@@ -613,7 +635,7 @@ fn clean_ty_generics(
 
             if let Some(param_idx) = param_idx {
                 if let Some(b) = impl_trait.get_mut(&param_idx.into()) {
-                    let p = p.clean(cx)?;
+                    let p: WherePredicate = p.clean(cx)?;
 
                     b.extend(
                         p.get_bounds()
@@ -624,11 +646,16 @@ fn clean_ty_generics(
                     );
 
                     let proj = projection
-                        .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().ty));
+                        .map(|p| (p.skip_binder().projection_ty.clean(cx), p.skip_binder().term));
                     if let Some(((_, trait_did, name), rhs)) =
                         proj.as_ref().and_then(|(lhs, rhs)| Some((lhs.projection()?, rhs)))
                     {
-                        impl_trait_proj.entry(param_idx).or_default().push((trait_did, name, rhs));
+                        // FIXME(...): Remove this unwrap()
+                        impl_trait_proj.entry(param_idx).or_default().push((
+                            trait_did,
+                            name,
+                            rhs.ty().unwrap(),
+                        ));
                     }
 
                     return None;
@@ -647,7 +674,7 @@ fn clean_ty_generics(
             if let Some(proj) = impl_trait_proj.remove(&idx) {
                 for (trait_did, name, rhs) in proj {
                     let rhs = rhs.clean(cx);
-                    simplify::merge_bounds(cx, &mut bounds, trait_did, name, &rhs);
+                    simplify::merge_bounds(cx, &mut bounds, trait_did, name, &Term::Type(rhs));
                 }
             }
         } else {
@@ -1004,7 +1031,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 --
@@ -1495,7 +1522,9 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
                 for pb in obj.projection_bounds() {
                     bindings.push(TypeBinding {
                         name: cx.tcx.associated_item(pb.item_def_id()).ident.name,
-                        kind: TypeBindingKind::Equality { ty: pb.skip_binder().ty.clean(cx) },
+                        kind: TypeBindingKind::Equality {
+                            term: pb.skip_binder().term.clean(cx).into(),
+                        },
                     });
                 }
 
@@ -1566,7 +1595,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
                                                 .ident
                                                 .name,
                                             kind: TypeBindingKind::Equality {
-                                                ty: proj.ty.clean(cx),
+                                                term: proj.term.clean(cx),
                                             },
                                         })
                                     } else {
@@ -1618,7 +1647,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)
     }
 }
 
@@ -1689,7 +1718,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 }
     }
@@ -2114,10 +2143,10 @@ fn clean(&self, cx: &mut DocContext<'_>) -> TypeBinding {
 impl Clean<TypeBindingKind> for hir::TypeBindingKind<'_> {
     fn clean(&self, cx: &mut DocContext<'_>) -> TypeBindingKind {
         match *self {
-            hir::TypeBindingKind::Equality { ref ty } => {
-                TypeBindingKind::Equality { ty: ty.clean(cx) }
+            hir::TypeBindingKind::Equality { ref term } => {
+                TypeBindingKind::Equality { term: term.clean(cx) }
             }
-            hir::TypeBindingKind::Constraint { bounds } => TypeBindingKind::Constraint {
+            hir::TypeBindingKind::Constraint { ref bounds } => TypeBindingKind::Constraint {
                 bounds: bounds.iter().filter_map(|b| b.clean(cx)).collect(),
             },
         }
index 4c81e75e8d6304b49b8055d90f75fcb0a7c98c4a..0bad153280822f971d101f4aad49b5e651e6ffd3 100644 (file)
@@ -92,7 +92,7 @@
     bounds: &mut Vec<clean::GenericBound>,
     trait_did: DefId,
     name: Symbol,
-    rhs: &clean::Type,
+    rhs: &clean::Term,
 ) -> bool {
     !bounds.iter_mut().any(|b| {
         let trait_ref = match *b {
             PP::AngleBracketed { ref mut bindings, .. } => {
                 bindings.push(clean::TypeBinding {
                     name,
-                    kind: clean::TypeBindingKind::Equality { ty: rhs.clone() },
+                    kind: clean::TypeBindingKind::Equality { term: rhs.clone() },
                 });
             }
             PP::Parenthesized { ref mut output, .. } => match output {
-                Some(o) => assert_eq!(o.as_ref(), rhs),
+                Some(o) => assert_eq!(&clean::Term::Type(o.as_ref().clone()), rhs),
                 None => {
-                    if *rhs != clean::Type::Tuple(Vec::new()) {
-                        *output = Some(Box::new(rhs.clone()));
+                    if *rhs != clean::Term::Type(clean::Type::Tuple(Vec::new())) {
+                        *output = Some(Box::new(rhs.ty().unwrap().clone()));
                     }
                 }
             },
index 491f7b2fa69014ca1f112b5b464a642f0f3bd298..fac1a0817e03300dc94d5c2b2df4e31dc1738ce8 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;
@@ -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(),
@@ -1213,7 +1212,7 @@ impl Lifetime {
 crate enum WherePredicate {
     BoundPredicate { ty: Type, bounds: Vec<GenericBound>, bound_params: Vec<Lifetime> },
     RegionPredicate { lifetime: Lifetime, bounds: Vec<GenericBound> },
-    EqPredicate { lhs: Type, rhs: Type },
+    EqPredicate { lhs: Type, rhs: Term },
 }
 
 impl WherePredicate {
@@ -1309,7 +1308,9 @@ impl FnDecl {
             FnRetTy::Return(Type::ImplTrait(bounds)) => match &bounds[0] {
                 GenericBound::TraitBound(PolyTrait { trait_, .. }, ..) => {
                     let bindings = trait_.bindings().unwrap();
-                    FnRetTy::Return(bindings[0].ty().clone())
+                    let ret_ty = bindings[0].term();
+                    let ty = ret_ty.ty().expect("Unexpected constant return term");
+                    FnRetTy::Return(ty.clone())
                 }
                 _ => panic!("unexpected desugaring of async function"),
             },
@@ -2122,6 +2123,24 @@ impl Path {
     crate kind: ConstantKind,
 }
 
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+crate enum Term {
+    Type(Type),
+    Constant(Constant),
+}
+
+impl Term {
+    crate fn ty(&self) -> Option<&Type> {
+        if let Term::Type(ty) = self { Some(ty) } else { None }
+    }
+}
+
+impl From<Type> for Term {
+    fn from(ty: Type) -> Self {
+        Term::Type(ty)
+    }
+}
+
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 crate enum ConstantKind {
     /// This is the wrapper around `ty::Const` for a non-local constant. Because it doesn't have a
@@ -2284,14 +2303,14 @@ impl Import {
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 crate enum TypeBindingKind {
-    Equality { ty: Type },
+    Equality { term: Term },
     Constraint { bounds: Vec<GenericBound> },
 }
 
 impl TypeBinding {
-    crate fn ty(&self) -> &Type {
+    crate fn term(&self) -> &Term {
         match self.kind {
-            TypeBindingKind::Equality { ref ty } => ty,
+            TypeBindingKind::Equality { ref term } => term,
             _ => panic!("expected equality type binding for parenthesized generic args"),
         }
     }
index f0e9b716081ac7b31a7246060ecbe0f1d96d1ca9..38da9a4635db888d1df7862dff479c193ea4e098 100644 (file)
@@ -17,6 +17,8 @@
 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;
@@ -227,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))
@@ -486,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(
@@ -514,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 22f59d39799c4fbb56353affc95856af16f2ea47..3b926e444034b3752022c8d3741284f54b151e54 100644 (file)
@@ -5,10 +5,10 @@
 use rustc_feature::UnstableFeatures;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, Path};
 use rustc_interface::interface;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
 use rustc_resolve as resolve;
@@ -474,12 +474,12 @@ fn new(tcx: TyCtxt<'tcx>) -> Self {
 }
 
 impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
+    fn nested_visit_map(&mut self) -> Self::Map {
         // We need to recurse into nested closures,
         // since those will fallback to the parent for type checking.
-        NestedVisitorMap::OnlyBodies(self.tcx.hir())
+        self.tcx.hir()
     }
 
     fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
@@ -492,9 +492,9 @@ fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
                 "could not resolve path `{}`",
                 path.segments
                     .iter()
-                    .map(|segment| segment.ident.as_str().to_string())
-                    .collect::<Vec<_>>()
-                    .join("::")
+                    .map(|segment| segment.ident.as_str())
+                    .intersperse("::")
+                    .collect::<String>()
             );
             let mut err = rustc_errors::struct_span_err!(
                 self.tcx.sess,
index ac24543929b663df349edbbb7c9e59bbb8f982dc..024fe6345d295a694b3f2e8b91ac378c4b41795d 100644 (file)
@@ -8,6 +8,7 @@
 use rustc_hir::{HirId, CRATE_HIR_ID};
 use rustc_interface::interface;
 use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{self, CrateType, ErrorOutputType};
 use rustc_session::{lint, DiagnosticOutput, Session};
@@ -1154,10 +1155,10 @@ fn visit_testable<F: FnOnce(&mut Self)>(
 }
 
 impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx> {
-    type Map = Map<'hir>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::All(self.map)
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.map
     }
 
     fn visit_item(&mut self, item: &'hir hir::Item<'_>) {
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..08840626259dc31eabda7e5a2a6678b54a3fd877 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] {
@@ -1421,11 +1442,11 @@ impl clean::TypeBinding {
         display_fn(move |f| {
             f.write_str(self.name.as_str())?;
             match self.kind {
-                clean::TypeBindingKind::Equality { ref ty } => {
+                clean::TypeBindingKind::Equality { ref term } => {
                     if f.alternate() {
-                        write!(f, " = {:#}", ty.print(cx))?;
+                        write!(f, " = {:#}", term.print(cx))?;
                     } else {
-                        write!(f, " = {}", ty.print(cx))?;
+                        write!(f, " = {}", term.print(cx))?;
                     }
                 }
                 clean::TypeBindingKind::Constraint { ref bounds } => {
@@ -1471,6 +1492,18 @@ impl clean::GenericArg {
     }
 }
 
+impl clean::types::Term {
+    crate fn print<'a, 'tcx: 'a>(
+        &'a self,
+        cx: &'a Context<'tcx>,
+    ) -> impl fmt::Display + 'a + Captures<'tcx> {
+        match self {
+            clean::types::Term::Type(ty) => ty.print(cx),
+            _ => todo!(),
+        }
+    }
+}
+
 crate fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display {
     struct WithFormatter<F>(Cell<Option<F>>);
 
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 3fd9c0a1944859b56528f9dad0bf35f2e0c43787..a9a3a0af276b11205f8bf6767fe8bb8570d9c48c 100644 (file)
@@ -923,9 +923,7 @@ fn parse(
 
         data.original = string.to_owned();
 
-        let tokens = Self::tokens(string).collect::<Vec<&str>>();
-
-        for token in tokens {
+        for token in Self::tokens(string) {
             match token {
                 "should_panic" => {
                     data.should_panic = true;
index 534a542d58ed0b596e5ffe754128715b5ea80fb9..2455d56bd2b3f9c1038bd4b58e81ed5b6b000ee2 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,
@@ -562,22 +554,13 @@ fn after_krate(&mut self) -> Result<(), Error> {
             extra_scripts: &[],
             static_extra_scripts: &[],
         };
-        let sidebar = if let Some(ref version) = self.shared.cache.crate_version {
-            format!(
-                "<h2 class=\"location\">Crate {}</h2>\
-                     <div class=\"block version\">\
-                         <p>Version {}</p>\
-                     </div>\
-                     <a id=\"all-types\" href=\"index.html\"><p>Back to index</p></a>",
-                crate_name,
-                Escape(version),
-            )
+        let sidebar = if self.shared.cache.crate_version.is_some() {
+            format!("<h2 class=\"location\">Crate {}</h2>", crate_name)
         } else {
             String::new()
         };
         let all = self.shared.all.replace(AllTypes::new());
         let v = layout::render(
-            &self.shared.templates,
             &self.shared.layout,
             &page,
             sidebar,
@@ -599,7 +582,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 +626,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 +647,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 7adf63f26f6025bc9201da9147eceafbb3fba424..8badce8226fd9e67a444b2f6e9ce21cb34b1647f 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)
     }
 }
 
@@ -422,6 +422,12 @@ fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<S
             "Theme preferences",
             vec![
                 Setting::from(("use-system-theme", "Use system theme", true)),
+                Setting::Select {
+                    js_data_name: "theme",
+                    description: "Theme",
+                    default_value: "light",
+                    options: theme_names.clone(),
+                },
                 Setting::Select {
                     js_data_name: "preferred-dark-theme",
                     description: "Preferred dark theme",
@@ -793,57 +799,77 @@ fn assoc_type(
     }
 }
 
+/// Writes a span containing the versions at which an item became stable and/or const-stable. For
+/// example, if the item became stable at 1.0.0, and const-stable at 1.45.0, this function would
+/// write a span containing "1.0.0 (const: 1.45.0)".
+///
+/// Returns `true` if a stability annotation was rendered.
+///
+/// Stability and const-stability are considered separately. If the item is unstable, no version
+/// will be written. If the item is const-unstable, "const: unstable" will be appended to the
+/// span, with a link to the tracking issue if present. If an item's stability or const-stability
+/// version matches the version of its enclosing item, that version will be omitted.
+///
+/// Note that it is possible for an unstable function to be const-stable. In that case, the span
+/// will include the const-stable version, but no stable version will be emitted, as a natural
+/// consequence of the above rules.
 fn render_stability_since_raw(
     w: &mut Buffer,
     ver: Option<Symbol>,
     const_stability: Option<ConstStability>,
     containing_ver: Option<Symbol>,
     containing_const_ver: Option<Symbol>,
-) {
-    let ver = ver.filter(|inner| !inner.is_empty());
+) -> bool {
+    let stable_version = ver.filter(|inner| !inner.is_empty() && Some(*inner) != containing_ver);
 
-    match (ver, const_stability) {
-        // stable and const stable
-        (Some(v), Some(ConstStability { level: StabilityLevel::Stable { since }, .. }))
+    let mut title = String::new();
+    let mut stability = String::new();
+
+    if let Some(ver) = stable_version {
+        stability.push_str(&ver.as_str());
+        title.push_str(&format!("Stable since Rust version {}", ver));
+    }
+
+    let const_title_and_stability = match const_stability {
+        Some(ConstStability { level: StabilityLevel::Stable { since }, .. })
             if Some(since) != containing_const_ver =>
         {
-            write!(
-                w,
-                "<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>",
-                v, since
-            );
+            Some((format!("const since {}", since), format!("const: {}", since)))
         }
-        // stable and const unstable
-        (
-            Some(v),
-            Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }),
-        ) => {
-            write!(
-                w,
-                "<span class=\"since\" title=\"Stable since Rust version {0}, const unstable\">{0} (const: ",
-                v
-            );
-            if let Some(n) = issue {
-                write!(
-                    w,
-                    "<a href=\"https://github.com/rust-lang/rust/issues/{}\" title=\"Tracking issue for {}\">unstable</a>",
+        Some(ConstStability { level: StabilityLevel::Unstable { issue, .. }, feature, .. }) => {
+            let unstable = if let Some(n) = issue {
+                format!(
+                    r#"<a href="https://github.com/rust-lang/rust/issues/{}" title="Tracking issue for {}">unstable</a>"#,
                     n, feature
-                );
+                )
             } else {
-                write!(w, "unstable");
-            }
-            write!(w, ")</span>");
+                String::from("unstable")
+            };
+
+            Some((String::from("const unstable"), format!("const: {}", unstable)))
         }
-        // stable
-        (Some(v), _) if ver != containing_ver => {
-            write!(
-                w,
-                "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
-                v
-            );
+        _ => None,
+    };
+
+    if let Some((const_title, const_stability)) = const_title_and_stability {
+        if !title.is_empty() {
+            title.push_str(&format!(", {}", const_title));
+        } else {
+            title.push_str(&const_title);
+        }
+
+        if !stability.is_empty() {
+            stability.push_str(&format!(" ({})", const_stability));
+        } else {
+            stability.push_str(&const_stability);
         }
-        _ => {}
     }
+
+    if !stability.is_empty() {
+        write!(w, r#"<span class="since" title="{}">{}</span>"#, title, stability);
+    }
+
+    !stability.is_empty()
 }
 
 fn render_assoc_item(
@@ -1190,11 +1216,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);
         }
     }
 }
@@ -1632,7 +1656,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<'_>,
@@ -1650,13 +1674,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>");
@@ -1734,15 +1761,8 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
     {
         write!(
             buffer,
-            "<h2 class=\"location\">{}{}</h2>",
+            "<h2 class=\"location\"><a href=\"#\">{}{}</a></h2>",
             match *it.kind {
-                clean::StructItem(..) => "Struct ",
-                clean::TraitItem(..) => "Trait ",
-                clean::PrimitiveItem(..) => "Primitive Type ",
-                clean::UnionItem(..) => "Union ",
-                clean::EnumItem(..) => "Enum ",
-                clean::TypedefItem(..) => "Type Definition ",
-                clean::ForeignTypeItem => "Foreign Type ",
                 clean::ModuleItem(..) =>
                     if it.is_crate() {
                         "Crate "
@@ -1755,26 +1775,14 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
         );
     }
 
+    buffer.write_str("<div class=\"sidebar-elems\">");
     if it.is_crate() {
+        write!(buffer, "<div class=\"block\"><ul>");
         if let Some(ref version) = cx.cache().crate_version {
-            write!(
-                buffer,
-                "<div class=\"block version\">\
-                     <div class=\"narrow-helper\"></div>\
-                     <p>Version {}</p>\
-                 </div>",
-                Escape(version),
-            );
+            write!(buffer, "<li class=\"version\">Version {}</li>", Escape(version));
         }
-    }
-
-    buffer.write_str("<div class=\"sidebar-elems\">");
-    if it.is_crate() {
-        write!(
-            buffer,
-            "<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>",
-            it.name.as_ref().expect("crates always have a name"),
-        );
+        write!(buffer, "<li><a id=\"all-types\" href=\"all.html\">All Items</a></li>");
+        buffer.write_str("</div></ul>");
     }
 
     match *it.kind {
@@ -1798,7 +1806,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) {
     // to navigate the documentation (though slightly inefficiently).
 
     if !it.is_mod() {
-        buffer.write_str("<h2 class=\"location\">Other items in<br>");
+        buffer.write_str("<h2 class=\"location\">In ");
         for (i, name) in cx.current.iter().take(parentlen).enumerate() {
             if i > 0 {
                 buffer.write_str("::<wbr>");
@@ -1823,7 +1831,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>");
 }
@@ -2508,7 +2520,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..f2c111495edfbaf5362c51eee66a6614fb458137 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));
@@ -679,7 +670,11 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
         }
         write!(w, "<div id=\"{}\" class=\"method has-srclink\">", id);
         write!(w, "<div class=\"rightside\">");
-        render_stability_since(w, m, t, cx.tcx());
+
+        let has_stability = render_stability_since(w, m, t, cx.tcx());
+        if has_stability {
+            w.write_str(" · ");
+        }
         write_srclink(cx, m, w);
         write!(w, "</div>");
         write!(w, "<h4 class=\"code-header\">");
@@ -864,20 +859,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 +884,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 +908,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 +947,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 +1000,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 +1045,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 +1060,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 +1109,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 +1128,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 +1153,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 +1164,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 +1203,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 +1247,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 +1340,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 +1357,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 +1409,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
@@ -1460,7 +1461,7 @@ fn render_stability_since(
     item: &clean::Item,
     containing_item: &clean::Item,
     tcx: TyCtxt<'_>,
-) {
+) -> bool {
     render_stability_since_raw(
         w,
         item.stable_since(tcx),
@@ -1524,12 +1525,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 +1545,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 +1553,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 +1576,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 +1601,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 +1609,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 +1770,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)?;
             }
index 54d9b6905c53d56f6829f9380f73590335937370..221e0113d3a43c448b822ed8c277ca603a42988f 100644 (file)
@@ -4,8 +4,9 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{ExprKind, GenericParam, GenericParamKind, HirId, Mod, Node};
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
 
@@ -93,10 +94,10 @@ fn handle_path(&mut self, path: &rustc_hir::Path<'_>, path_span: Option<Span>) {
 }
 
 impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
-    type Map = rustc_middle::hir::map::Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.tcx.hir()
     }
 
     fn visit_generic_param(&mut self, p: &'tcx GenericParam<'tcx>) {
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 fab64abc3e1493c2eab1a9e6b3952522d16a7cd9..44a9a571fa1f81c39ae9cbd23fcdcaa09ce516bb 100644 (file)
@@ -111,6 +111,12 @@ body {
        font: 1rem/1.4 "Source Serif 4", NanumBarunGothic, serif;
        margin: 0;
        position: relative;
+       /* We use overflow-wrap: break-word for Safari, which doesn't recognize
+          `anywhere`: https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap */
+       overflow-wrap: break-word;
+       /* Then override it with `anywhere`, which is required to make non-Safari browsers break
+          more aggressively when we want them to. */
+       overflow-wrap: anywhere;
 
        -webkit-font-feature-settings: "kern", "liga";
        -moz-font-feature-settings: "kern", "liga";
@@ -137,17 +143,23 @@ 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;
+       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)
@@ -155,8 +167,7 @@ h1.fqn > .in-band > a:hover {
        section hierarchies. */
 h2,
 .top-doc h3,
-.top-doc h4,
-.sidebar .others h3 {
+.top-doc h4 {
        border-bottom: 1px solid;
 }
 h3.code-header {
@@ -192,14 +203,20 @@ div.impl-items > div {
 }
 
 h1, h2, h3, h4, h5, h6,
-.sidebar, a.source, .search-input, .search-results .result-name,
+.sidebar,
+.mobile-topbar,
+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;
@@ -245,6 +262,11 @@ textarea {
        margin: 0;
 }
 
+button {
+       /* Buttons on Safari have different default padding than other platforms. Make them the same. */
+       padding: 1px 6px;
+}
+
 /* end tweaks for normalize.css 8 */
 
 .rustdoc {
@@ -343,15 +365,25 @@ nav.sub {
 }
 
 .sidebar {
-       width: 200px;
+       font-size: 0.9rem;
+       width: 250px;
+       min-width: 200px;
        overflow-y: scroll;
        position: sticky;
-       min-width: 200px;
        height: 100vh;
        top: 0;
        left: 0;
 }
 
+.sidebar-elems,
+.sidebar > .location {
+       padding-left: 24px;
+}
+
+.sidebar .location {
+       overflow-wrap: anywhere;
+}
+
 .rustdoc.source .sidebar {
        width: 50px;
        min-width: 0px;
@@ -380,6 +412,10 @@ nav.sub {
        visibility: visible;
 }
 
+#all-types {
+       margin-top: 1em;
+}
+
 /* Improve the scrollbar display on firefox */
 * {
        scrollbar-width: initial;
@@ -399,47 +435,28 @@ nav.sub {
        -webkit-box-shadow: inset 0;
 }
 
-.sidebar .block > ul > li {
-       margin-right: -10px;
-}
-
 /* Everything else */
 
 .hidden {
        display: none !important;
 }
 
-.logo-container {
+.sidebar .logo-container {
        display: flex;
        margin-top: 10px;
        margin-bottom: 10px;
        justify-content: center;
 }
 
+.version {
+       overflow-wrap: break-word;
+}
+
 .logo-container > img {
        height: 100px;
        width: 100px;
 }
 
-.sidebar .location {
-       border: 1px solid;
-       font-size: 1.0625rem;
-       margin: 30px 10px 20px 10px;
-       text-align: center;
-       word-wrap: break-word;
-       font-weight: inherit;
-       padding: 0;
-}
-
-.sidebar .version {
-       font-size: 0.9375rem;
-       text-align: center;
-       border-bottom: 1px solid;
-       overflow-wrap: break-word;
-       word-wrap: break-word; /* deprecated */
-       word-break: break-word; /* Chrome, non-standard */
-}
-
 .location:empty {
        border: none;
 }
@@ -453,48 +470,45 @@ nav.sub {
 
 .block {
        padding: 0;
-       margin-bottom: 14px;
-}
-.block h2, .block h3 {
-       text-align: center;
 }
 .block ul, .block li {
-       margin: 0 10px;
        padding: 0;
        list-style: none;
 }
 
 .block a {
        display: block;
+       padding: 0.3em;
+       margin-left: -0.3em;
+
        text-overflow: ellipsis;
        overflow: hidden;
-       line-height: 15px;
-       padding: 7px 5px;
-       font-size: 0.875rem;
-       font-weight: 300;
-       transition: border 500ms ease-out;
 }
 
-.sidebar-title {
-       border-top: 1px solid;
-       border-bottom: 1px solid;
-       text-align: center;
-       font-size: 1.0625rem;
-       margin-bottom: 5px;
-       font-weight: inherit;
+.sidebar h2 {
+       border-bottom: none;
+       font-weight: 500;
        padding: 0;
+       margin: 0;
+       margin-top: 1rem;
+       margin-bottom: 1rem;
 }
 
-.sidebar-links {
-       margin-bottom: 15px;
+.sidebar h3 {
+       font-size: 1.1rem;
+       font-weight: 500;
+       padding: 0;
+       margin: 0;
+       margin-top: 0.5rem;
+       margin-bottom: 0.25rem;
 }
 
-.sidebar-links > a {
-       padding-left: 10px;
-       width: 100%;
+.sidebar-links,
+.block {
+       margin-bottom: 2em;
 }
 
-.sidebar-menu {
+.mobile-topbar {
        display: none;
 }
 
@@ -566,6 +580,7 @@ nav.sub {
 }
 
 .docblock-short {
+       overflow-wrap: break-word;
        overflow-wrap: anywhere;
 }
 .docblock-short p {
@@ -609,10 +624,12 @@ nav.sub {
 .content .out-of-band {
        flex-grow: 0;
        text-align: right;
-       font-size: 1.4375rem;
-       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 {
@@ -629,6 +646,7 @@ nav.sub {
        flex-grow: 1;
        margin: 0px;
        padding: 0px;
+       overflow-wrap: break-word;
        overflow-wrap: anywhere;
 }
 
@@ -657,6 +675,7 @@ nav.sub {
        margin: .5em 0;
        width: calc(100% - 2px);
        overflow-x: auto;
+       overflow-wrap: normal;
        display: block;
 }
 
@@ -762,13 +781,11 @@ nav.sub {
        margin-top: 0;
 }
 
-nav:not(.sidebar) {
+nav.sub {
        flex-grow: 1;
-       border-bottom: 1px solid;
-       padding-bottom: 10px;
        margin-bottom: 25px;
 }
-.source nav:not(.sidebar).sub {
+.source nav.sub {
        margin-left: 32px;
 }
 nav.main {
@@ -922,11 +939,6 @@ h2.small-section-header > .anchor {
        width: 100%;
 }
 
-#crate-search + .search-input {
-       border-radius: 0 1px 1px 0;
-       width: calc(100% - 32px);
-}
-
 .search-input:focus {
        border-radius: 2px;
        border: 0;
@@ -1082,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;
@@ -1160,10 +1172,6 @@ a.test-arrow:hover{
        font-weight: 300;
 }
 
-.since + .srclink {
-       padding-left: 10px;
-}
-
 .item-spacer {
        width: 100%;
        height: 12px;
@@ -1382,18 +1390,6 @@ pre.rust {
        margin-left: 5px;
 }
 
-#all-types {
-       text-align: center;
-       border: 1px solid;
-       margin: 0 10px;
-       margin-bottom: 10px;
-       display: block;
-       border-radius: 7px;
-}
-#all-types > p {
-       margin: 5px 0;
-}
-
 #sidebar-toggle {
        position: sticky;
        top: 0;
@@ -1487,6 +1483,7 @@ pre.rust {
        padding: 4px 8px;
        text-align: center;
        background: rgba(0,0,0,0);
+       overflow-wrap: normal;
 }
 
 #theme-choices > button:not(:first-child) {
@@ -1738,8 +1735,12 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 }
 
 @media (max-width: 700px) {
-       body {
+       .rustdoc {
                padding-top: 0px;
+               /* Sidebar should overlay main content, rather than pushing main content to the right.
+                  Turn off `display: flex` on the body element. */
+               display: block;
+               scroll-margin-top: 45px;
        }
 
        main {
@@ -1751,128 +1752,104 @@ details.rustdoc-toggle[open] > summary.hideme::after {
                flex-direction: column;
        }
 
-       .rustdoc:not(.source) > .sidebar {
-               width: 100%;
-               height: 45px;
-               min-height: 40px;
-               max-height: 45px;
-               margin: 0;
-               padding: 0 15px;
-               position: static;
-               z-index: 11;
-               overflow-y: hidden;
+       /* Hide the logo and item name from the sidebar. Those are displayed
+          in the mobile-topbar instead. */
+       .sidebar .sidebar-logo,
+       .sidebar .location {
+               display: none;
        }
 
-       .rustdoc.source > .sidebar {
+       .sidebar-elems {
+               margin-top: 1em;
+       }
+
+       .sidebar {
                position: fixed;
-               top: 0;
-               left: 0;
+               top: 45px;
+               /* Hide the sidebar offscreen while not in use. Doing this instead of display: none means
+                  the sidebar stays visible for screen readers, which is useful for navigation. */
+               left: -1000px;
+               margin-left: 0;
+               background-color: rgba(0,0,0,0);
                margin: 0;
+               padding: 0;
+               padding-left: 15px;
                z-index: 11;
-               width: 0;
        }
 
-       .sidebar.mobile {
-               position: sticky !important;
+       /* The source view uses a different design for the sidebar toggle, and doesn't have a topbar,
+          so don't bump down the main content or the sidebar. */
+       .source main,
+       .source .sidebar {
                top: 0;
+               padding: 0;
+       }
+
+       .sidebar.shown,
+       .sidebar.expanded,
+       .sidebar:focus-within {
                left: 0;
-               width: 100%;
-               margin-left: 0;
-               background-color: rgba(0,0,0,0);
        }
 
-       .sidebar > .location {
-               float: right;
-               margin: 0px;
-               margin-top: 2px;
-               padding: 3px 10px 1px 10px;
-               min-height: 39px;
-               background: inherit;
-               text-align: left;
-               font-size: 1.5rem;
+       .rustdoc.source > .sidebar {
+               position: fixed;
+               margin: 0;
+               z-index: 11;
+               width: 0;
        }
 
-       .sidebar .location:empty {
-               padding: 0;
+       .mobile-topbar .location {
+               border: none;
+               margin: 0;
+               margin-left: auto;
+               padding: 0.3em;
+               padding-right: 0.6em;
+               text-overflow: ellipsis;
+               overflow-x: hidden;
        }
 
-       .rustdoc:not(.source) .sidebar .logo-container {
-               width: 35px;
-               height: 35px;
-               margin-top: 5px;
-               margin-bottom: 5px;
-               float: left;
-               margin-left: 50px;
+       .mobile-topbar .logo-container {
+               max-height: 45px;
        }
 
-       .sidebar .logo-container > img {
+       .mobile-topbar .logo-container > img {
                max-width: 35px;
                max-height: 35px;
+               margin-left: 20px;
+               margin-top: 5px;
+               margin-bottom: 5px;
        }
 
-       .sidebar-menu {
-               position: fixed;
+       .mobile-topbar {
+               display: flex;
+               flex-direction: row;
+               position: sticky;
                z-index: 10;
                font-size: 2rem;
                cursor: pointer;
-               width: 45px;
+               height: 45px;
+               width: 100%;
                left: 0;
                top: 0;
-               text-align: center;
-               display: block;
-               border-bottom: 1px solid;
-               border-right: 1px solid;
-               height: 45px;
        }
 
-       .rustdoc.source > .sidebar > .sidebar-menu {
+       .source .mobile-topbar {
                display: none;
        }
 
-       /* We do NOT hide this element so that alternative device readers still have this information
-          available. */
-       .sidebar-elems {
-               position: fixed;
-               z-index: 1;
-               top: 45px;
-               bottom: 0;
-               width: 246px;
-               /* We move the sidebar to the left by its own width so it doesn't appear. */
-               left: -246px;
-               overflow-y: auto;
-               border-right: 1px solid;
-       }
-
-       .sidebar > .block.version {
-               overflow: hidden;
-               border-bottom: none;
-               margin-bottom: 0;
-               height: 100%;
-               padding-left: 12px;
-       }
-       .sidebar > .block.version > div.narrow-helper {
-               float: left;
-               width: 1px;
-               height: 100%;
-       }
-       .sidebar > .block.version > p {
-               /* hide Version text if too narrow */
-               margin: 0;
-               min-width: 55px;
-               /* vertically center */
-               display: flex;
-               align-items: center;
-               height: 100%;
+       .sidebar-menu-toggle {
+               width: 45px;
+               border: none;
        }
 
-       nav.sub {
-               width: calc(100% - 32px);
+       .source nav:not(.sidebar).sub {
                margin-left: 32px;
-               margin-bottom: 10px;
        }
 
-       .source nav:not(.sidebar).sub {
-               margin-left: 32px;
+       /* Space is at a premium on mobile, so remove the theme-picker icon. */
+       #theme-picker {
+               display: none;
+               width: 0;
        }
 
        .content {
@@ -1911,28 +1888,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
                height: 50px;
        }
 
-       .show-it, .sidebar-elems:focus-within {
-               z-index:  2;
-               left: 0;
-       }
-
-       .show-it > .block.items {
-               margin: 8px 0;
-       }
-
-       .show-it > .block.items > ul {
-               margin: 0;
-       }
-
-       .show-it > .block.items > ul > li {
-               text-align: center;
-               margin: 2px 0;
-       }
-
-       .show-it > .block.items > ul > li > a {
-               font-size: 1.3125rem;
-       }
-
        /* Because of ios, we need to actually have a full height sidebar title so the
         * actual sidebar can show up. But then we need to make it transparent so we don't
         * hide content. The filler just allows to create the background for the sidebar
@@ -1953,10 +1908,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
                left: -11px;
        }
 
-       #all-types {
-               margin: 10px;
-       }
-
        .sidebar.expanded #sidebar-toggle {
                font-size: 1.5rem;
        }
@@ -2062,16 +2013,10 @@ details.rustdoc-toggle[open] > summary.hideme::after {
        }
 
        #crate-search {
-               width: 100%;
                border-radius: 4px;
                border: 0;
        }
 
-       #crate-search + .search-input {
-               width: calc(100% + 71px);
-               margin-left: -36px;
-       }
-
        #theme-picker, #settings-menu {
                padding: 5px;
                width: 31px;
@@ -2091,9 +2036,14 @@ details.rustdoc-toggle[open] > summary.hideme::after {
        }
 
        .docblock code {
+               overflow-wrap: break-word;
                overflow-wrap: anywhere;
        }
 
+       .docblock table code {
+               overflow-wrap: normal;
+       }
+
        .sub-container {
                flex-direction: column;
        }
index 6ed7845e83a354f9c8ebe31c6bf11169abeb9d24..69097b81b9f1ca0a946ff346ea5935520108f445 100644 (file)
@@ -57,11 +57,11 @@ pre, .rustdoc.source .example-wrap {
        background-color: #191f26;
 }
 
-.sidebar {
+.sidebar, .mobile-topbar, .sidebar-menu-toggle {
        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)
@@ -100,12 +100,6 @@ pre, .rustdoc.source .example-wrap {
        background-color: #14191f;
 }
 
-.sidebar .location {
-       border-color: #000;
-       background-color: #0f1419;
-       color: #fff;
-}
-
 .sidebar-elems .location {
        color: #ff7733;
 }
@@ -114,15 +108,6 @@ pre, .rustdoc.source .example-wrap {
        color: #fff;
 }
 
-.sidebar .version {
-       border-bottom-color: #424c57;
-}
-
-.sidebar-title {
-       border-top-color: #5c6773;
-       border-bottom-color: #5c6773;
-}
-
 .block a:hover {
        background: transparent;
        color: #ffb44c;
@@ -209,9 +194,6 @@ pre, .rustdoc.source .example-wrap {
 pre.rust .comment { color: #788797; }
 pre.rust .doccomment { color: #a1ac88; }
 
-nav:not(.sidebar) {
-       border-bottom-color: #424c57;
-}
 nav.main .current {
        border-top-color: #5c6773;
        border-bottom-color: #5c6773;
@@ -222,13 +204,14 @@ nav.main .separator {
 a {
        color: #39AFD7;
 }
-a.srclink,
+
 a#toggle-all-docs,
 a.anchor,
 .small-section-header a,
 #source-sidebar a,
 pre.rust a,
-.sidebar a,
+.sidebar h2 a,
+.sidebar h3 a,
 .in-band a {
        color: #c5c5c5;
 }
@@ -299,7 +282,8 @@ details.undocumented > summary::before {
        border-color: #5c6773;
 }
 
-.since {
+.rightside,
+.out-of-band {
        color: grey;
 }
 
@@ -580,13 +564,6 @@ kbd {
        }
 }
 
-#all-types {
-       background-color: #14191f;
-}
-#all-types:hover {
-       background-color: rgba(70, 70, 70, 0.33);
-}
-
 .search-results .result-name span.alias {
        color: #c5c5c5;
 }
index 64b6eb6696b831219f19899ee844b17e23cb5e63..39165b2fc058f3192badc5d5925a2453058ebaee 100644 (file)
@@ -28,11 +28,11 @@ pre, .rustdoc.source .example-wrap {
        background-color: #2A2A2A;
 }
 
-.sidebar {
+.sidebar, .mobile-topbar, .sidebar-menu-toggle {
        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)
@@ -69,21 +69,6 @@ pre, .rustdoc.source .example-wrap {
        background-color: #565656;
 }
 
-.sidebar .location {
-       border-color: #fff;
-       background: #575757;
-       color: #DDD;
-}
-
-.sidebar .version {
-       border-bottom-color: #DDD;
-}
-
-.sidebar-title {
-       border-top-color: #777;
-       border-bottom-color: #777;
-}
-
 .block a:hover {
        background: #444;
 }
@@ -166,9 +151,6 @@ a.result-keyword:focus { background-color: #884719; }
 pre.rust .comment { color: #8d8d8b; }
 pre.rust .doccomment { color: #8ca375; }
 
-nav:not(.sidebar) {
-       border-bottom-color: #4e4e4e;
-}
 nav.main .current {
        border-top-color: #eee;
        border-bottom-color: #eee;
@@ -180,13 +162,14 @@ nav.main .separator {
 a {
        color: #D2991D;
 }
-a.srclink,
+
 a#toggle-all-docs,
 a.anchor,
 .small-section-header a,
 #source-sidebar a,
 pre.rust a,
-.sidebar a,
+.sidebar h2 a,
+.sidebar h3 a,
 .in-band a {
        color: #ddd;
 }
@@ -256,7 +239,8 @@ details.undocumented > summary::before {
        background: rgba(0,0,0,0);
 }
 
-.since {
+.rightside,
+.out-of-band {
        color: grey;
 }
 
@@ -452,13 +436,6 @@ kbd {
        }
 }
 
-#all-types {
-       background-color: #505050;
-}
-#all-types:hover {
-       background-color: #606060;
-}
-
 .search-results .result-name span.alias {
        color: #fff;
 }
index dbacc9f30735bf837f6632c14e26fa07fca7a15d..448c9ac603c82c66b60c970f3f82a9ab4e2835c0 100644 (file)
@@ -30,7 +30,7 @@ pre, .rustdoc.source .example-wrap {
        background-color: #F5F5F5;
 }
 
-.sidebar {
+.sidebar, .mobile-topbar, .sidebar-menu-toggle {
        background-color: #F5F5F5;
 }
 
@@ -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! */
 }
 
@@ -69,21 +69,6 @@ pre, .rustdoc.source .example-wrap {
        background-color: #f1f1f1;
 }
 
-.sidebar .location {
-       border-color: #000;
-       background-color: #fff;
-       color: #333;
-}
-
-.sidebar .version {
-       border-bottom-color: #DDD;
-}
-
-.sidebar-title {
-       border-top-color: #777;
-       border-bottom-color: #777;
-}
-
 .block a:hover {
        background: #F5F5F5;
 }
@@ -163,9 +148,6 @@ a.result-keyword:focus { background-color: #afc6e4; }
 .content .fnname { color: #AD7C37; }
 .content span.keyword, .content a.keyword, .block a.current.keyword { color: #3873AD; }
 
-nav:not(.sidebar) {
-       border-bottom-color: #e0e0e0;
-}
 nav.main .current {
        border-top-color: #000;
        border-bottom-color: #000;
@@ -177,13 +159,14 @@ nav.main .separator {
 a {
        color: #3873AD;
 }
-a.srclink,
+
 a#toggle-all-docs,
 a.anchor,
 .small-section-header a,
 #source-sidebar a,
 pre.rust a,
-.sidebar a,
+.sidebar h2 a,
+.sidebar h3 a,
 .in-band a {
        color: #000;
 }
@@ -243,7 +226,8 @@ details.undocumented > summary::before {
        border-color: #bfbfbf;
 }
 
-.since {
+.rightside,
+.out-of-band {
        color: grey;
 }
 
@@ -439,13 +423,6 @@ kbd {
        }
 }
 
-#all-types {
-       background-color: #fff;
-}
-#all-types:hover {
-       background-color: #f9f9f9;
-}
-
 .search-results .result-name span.alias {
        color: #000;
 }
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 f41c1bd817ab284f3afb2a58eb804a45208fbc54..161b95d99930e761de21ae49be2b8e41df3377ba 100644 (file)
@@ -67,6 +67,13 @@ function resourcePath(basename, extension) {
             ty: sidebarVars.attributes["data-ty"].value,
             relpath: sidebarVars.attributes["data-relpath"].value,
         };
+        // FIXME: It would be nicer to generate this text content directly in HTML,
+        // but with the current code it's hard to get the right information in the right place.
+        var mobileLocationTitle = document.querySelector(".mobile-topbar h2.location");
+        var locationTitle = document.querySelector(".sidebar h2.location");
+        if (mobileLocationTitle && locationTitle) {
+            mobileLocationTitle.innerText = locationTitle.innerText;
+        }
     }
 }());
 
@@ -129,10 +136,15 @@ function hideThemeButtonState() {
 
 // Set up the theme picker list.
 (function () {
+    if (!document.location.href.startsWith("file:///")) {
+        return;
+    }
     var themeChoices = getThemesElement();
     var themePicker = getThemePickerElement();
     var availableThemes = getVar("themes").split(",");
 
+    removeClass(themeChoices.parentElement, "hidden");
+
     function switchThemeButtonState() {
         if (themeChoices.style.display === "block") {
             hideThemeButtonState();
@@ -283,9 +295,6 @@ function hideThemeButtonState() {
                 loadSearch();
             }
 
-            // `crates{version}.js` should always be loaded before this script, so we can use it
-            // safely.
-            searchState.addCrateDropdown(window.ALL_CRATES);
             var params = searchState.getQueryStringParams();
             if (params.search !== undefined) {
                 var search = searchState.outputElement();
@@ -295,30 +304,6 @@ function hideThemeButtonState() {
                 loadSearch();
             }
         },
-        addCrateDropdown: function(crates) {
-            var elem = document.getElementById("crate-search");
-
-            if (!elem) {
-                return;
-            }
-            var savedCrate = getSettingValue("saved-filter-crate");
-            for (var i = 0, len = crates.length; i < len; ++i) {
-                var option = document.createElement("option");
-                option.value = crates[i];
-                option.innerText = crates[i];
-                elem.appendChild(option);
-                // Set the crate filter from saved storage, if the current page has the saved crate
-                // filter.
-                //
-                // If not, ignore the crate filter -- we want to support filtering for crates on
-                // sites like doc.rust-lang.org where the crates may differ from page to page while
-                // on the
-                // same domain.
-                if (crates[i] === savedCrate) {
-                    elem.value = savedCrate;
-                }
-            }
-        },
     };
 
     function getPageId() {
@@ -331,37 +316,6 @@ function hideThemeButtonState() {
         return null;
     }
 
-    function showSidebar() {
-        var elems = document.getElementsByClassName("sidebar-elems")[0];
-        if (elems) {
-            addClass(elems, "show-it");
-        }
-        var sidebar = document.getElementsByClassName("sidebar")[0];
-        if (sidebar) {
-            addClass(sidebar, "mobile");
-            var filler = document.getElementById("sidebar-filler");
-            if (!filler) {
-                var div = document.createElement("div");
-                div.id = "sidebar-filler";
-                sidebar.appendChild(div);
-            }
-        }
-    }
-
-    function hideSidebar() {
-        var elems = document.getElementsByClassName("sidebar-elems")[0];
-        if (elems) {
-            removeClass(elems, "show-it");
-        }
-        var sidebar = document.getElementsByClassName("sidebar")[0];
-        removeClass(sidebar, "mobile");
-        var filler = document.getElementById("sidebar-filler");
-        if (filler) {
-            filler.remove();
-        }
-        document.getElementsByTagName("body")[0].style.marginTop = "";
-    }
-
     var toggleAllDocsId = "toggle-all-docs";
     var main = document.getElementById(MAIN_ID);
     var savedHash = "";
@@ -396,7 +350,8 @@ function hideThemeButtonState() {
 
     function onHashChange(ev) {
         // If we're in mobile mode, we should hide the sidebar in any case.
-        hideSidebar();
+        var sidebar = document.getElementsByClassName("sidebar")[0];
+        removeClass(sidebar, "shown");
         handleHashes(ev);
     }
 
@@ -888,6 +843,11 @@ function hideThemeButtonState() {
         });
     }());
 
+    function hideSidebar() {
+        var sidebar = document.getElementsByClassName("sidebar")[0];
+        removeClass(sidebar, "shown");
+    }
+
     function handleClick(id, f) {
         var elem = document.getElementById(id);
         if (elem) {
@@ -897,6 +857,9 @@ function hideThemeButtonState() {
     handleClick("help-button", function(ev) {
         displayHelp(true, ev);
     });
+    handleClick(MAIN_ID, function() {
+        hideSidebar();
+    });
 
     onEachLazy(document.getElementsByTagName("a"), function(el) {
         // For clicks on internal links (<A> tags with a hash property), we expand the section we're
@@ -905,6 +868,7 @@ function hideThemeButtonState() {
         if (el.hash) {
             el.addEventListener("click", function() {
                 expandSection(el.hash.slice(1));
+                hideSidebar();
             });
         }
     });
@@ -924,16 +888,16 @@ function hideThemeButtonState() {
         };
     });
 
-    var sidebar_menu = document.getElementsByClassName("sidebar-menu")[0];
-    if (sidebar_menu) {
-        sidebar_menu.onclick = function() {
+    var sidebar_menu_toggle = document.getElementsByClassName("sidebar-menu-toggle")[0];
+    if (sidebar_menu_toggle) {
+        sidebar_menu_toggle.addEventListener("click", function() {
             var sidebar = document.getElementsByClassName("sidebar")[0];
-            if (hasClass(sidebar, "mobile")) {
-                hideSidebar();
+            if (!hasClass(sidebar, "shown")) {
+                addClass(sidebar, "shown");
             } else {
-                showSidebar();
+                removeClass(sidebar, "shown");
             }
-        };
+        });
     }
 
     var buildHelperPopup = function() {
index e859431e1f189e68a7b761d85374b89df4a929a4..104464b3881147a476802deb439b6bcf6ac5e274 100644 (file)
@@ -1126,15 +1126,18 @@ window.initSearch = function(rawSearchIndex) {
             }
         }
 
-        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>`;
+        let crates = "";
+        if (window.ALL_CRATES.length > 1) {
+            crates = ` in <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>`;
         }
-        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>" +
-            ` in ${crates} ` +
+            crates +
             `</div><div id="titles">` +
             makeTabHeader(0, "In Names", ret_others[1]) +
             makeTabHeader(1, "In Parameters", ret_in_args[1]) +
@@ -1148,7 +1151,10 @@ window.initSearch = function(rawSearchIndex) {
         resultsElem.appendChild(ret_returned[0]);
 
         search.innerHTML = output;
-        document.getElementById("crate-search").addEventListener("input", updateCrate);
+        let crateSearch = document.getElementById("crate-search");
+        if (crateSearch) {
+            crateSearch.addEventListener("input", updateCrate);
+        }
         search.appendChild(resultsElem);
         // Reset focused elements.
         searchState.focusedByTab = [null, null, null];
index 4f10e14e8558c71cde4c5ef964d91ae90e03a796..e5c7e1ea1a03c36c57455d9106f979f07c079247 100644 (file)
@@ -1,15 +1,18 @@
 // Local js definitions:
 /* global getSettingValue, getVirtualKey, onEachLazy, updateLocalStorage, updateSystemTheme */
+/* global addClass, removeClass */
 
 (function () {
     function changeSetting(settingName, value) {
         updateLocalStorage("rustdoc-" + settingName, value);
 
         switch (settingName) {
+            case "theme":
             case "preferred-dark-theme":
             case "preferred-light-theme":
             case "use-system-theme":
                 updateSystemTheme();
+                updateLightAndDark();
                 break;
         }
     }
         }
     }
 
+    function showLightAndDark() {
+        addClass(document.getElementById("theme").parentElement.parentElement, "hidden");
+        removeClass(document.getElementById("preferred-light-theme").parentElement.parentElement,
+            "hidden");
+        removeClass(document.getElementById("preferred-dark-theme").parentElement.parentElement,
+            "hidden");
+    }
+
+    function hideLightAndDark() {
+        addClass(document.getElementById("preferred-light-theme").parentElement.parentElement,
+            "hidden");
+        addClass(document.getElementById("preferred-dark-theme").parentElement.parentElement,
+            "hidden");
+        removeClass(document.getElementById("theme").parentElement.parentElement, "hidden");
+    }
+
+    function updateLightAndDark() {
+        if (getSettingValue("use-system-theme") !== "false") {
+            showLightAndDark();
+        } else {
+            hideLightAndDark();
+        }
+    }
+
     function setEvents() {
+        updateLightAndDark();
         onEachLazy(document.getElementsByClassName("slider"), function(elem) {
             var toggle = elem.previousElementSibling;
             var settingId = toggle.id;
index 81dc0b2fb1eb9d1044c9e32f1af2c1d52845eff1..498f60e9f25ae4fd601dd22087421667209c8493 100644 (file)
@@ -139,7 +139,7 @@ function createSourceSidebar() {
                                       currentFile, hasFoundFile);
     });
 
-    container.insertBefore(sidebar, document.querySelector(".sidebar-logo").nextSibling);
+    container.appendChild(sidebar);
     // Focus on the current file in the source files sidebar.
     var selected_elem = sidebar.getElementsByClassName("selected")[0];
     if (typeof selected_elem !== "undefined") {
index d8b3ba92dcba2d0f6a5ed89e044a2959a9cfa232..2394df4c715d4fc5421c2e94a510ed76904e08df 100644 (file)
@@ -187,22 +187,25 @@ var updateSystemTheme = (function() {
     var mql = window.matchMedia("(prefers-color-scheme: dark)");
 
     function handlePreferenceChange(mql) {
+        let use = function(theme) {
+            switchTheme(window.currentTheme, window.mainTheme, theme, true);
+        };
         // maybe the user has disabled the setting in the meantime!
         if (getSettingValue("use-system-theme") !== "false") {
             var lightTheme = getSettingValue("preferred-light-theme") || "light";
             var darkTheme = getSettingValue("preferred-dark-theme") || "dark";
 
             if (mql.matches) {
-                // prefers a dark theme
-                switchTheme(window.currentTheme, window.mainTheme, darkTheme, true);
+                use(darkTheme);
             } else {
                 // prefers a light theme, or has no preference
-                switchTheme(window.currentTheme, window.mainTheme, lightTheme, true);
+                use(lightTheme);
             }
-
             // note: we save the theme so that it doesn't suddenly change when
             // the user disables "use-system-theme" and reloads the page or
             // navigates to another page
+        } else {
+            use(getSettingValue("theme"));
         }
     }
 
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");
index 5cade1b1a4c73d370929ef831f7eb2eeca368913..1322b854b7fc77298fa6390f3fb080d133439134 100644 (file)
@@ -7,20 +7,20 @@
     <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="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"> {#- -#}
+          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" {# -#}
+          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" {# -#}
+            href="{{static_root_path|safe}}{{theme}}{{page.resource_suffix}}.css" {# -#}
         {%- if theme == "light" -%}
             id="themeStyle"
         {%- else -%}
         >
     {%- endfor -%}
     <script id="default-settings" {# -#}
-      {% for k, v in layout.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> {#- -#}
+    <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> {#- -#}
+    <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> {#- -#}
+    <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> {#- -#}
+    <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"> {#- -#}
+           href="{{static_root_path|safe}}noscript{{page.resource_suffix}}.css"> {#- -#}
     </noscript> {#- -#}
-    {%- if layout.css_file_extension -%}
+    {%- if layout.css_file_extension.is_some() -%}
         <link rel="stylesheet" type="text/css" {# -#}
-            href="{{static_root_path | safe}}theme{{page.resource_suffix}}.css"> {#- -#}
+            href="{{static_root_path|safe}}theme{{page.resource_suffix}}.css"> {#- -#}
     {%- endif -%}
-    {%- if layout.favicon -%}
+    {%- 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"> {#- -#}
+            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"> {#- -#}
+            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"> {#- -#}
+            href="{{static_root_path|safe}}favicon{{page.resource_suffix}}.svg"> {#- -#}
     {%- endif -%}
-    {{- layout.external_html.in_header | safe -}}
+    {{- layout.external_html.in_header|safe -}}
 </head> {#- -#}
 <body class="rustdoc {{page.css_class}}"> {#- -#}
     <!--[if lte IE 11]> {#- -#}
         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"> {#- -#}
+    {{- layout.external_html.before_content|safe -}}
+    <nav class="mobile-topbar"> {#- -#}
+        <button class="sidebar-menu-toggle">&#9776;</button> {#- -#}
+        <a class="sidebar-logo" href="{{page.root_path|safe}}{{krate_with_trailing_slash|safe}}index.html"> {#- -#}
             <div class="logo-container"> {#- -#}
-            {%- if layout.logo -%}
+            {%- 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}}.png" alt="logo"> {#- -#}
+                <img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
             {%- endif -%}
             </div>
         </a> {#- -#}
-        {{- sidebar | safe -}}
+        <h2 class="location"></h2>
+    </nav>
+    <nav class="sidebar"> {#- -#}
+        <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 -%}
-                    <img src="{{layout.logo}}" alt="logo">
+                <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}}.png" alt="logo">
+                        <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"> {#- -#}
+                    <div class="theme-picker hidden"> {#- -#}
                         <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"> {#- -#}
+                             src="{{static_root_path|safe}}brush{{page.resource_suffix}}.svg"> {#- -#}
                         </button> {#- -#}
                         <div id="theme-choices" role="menu"></div> {#- -#}
                     </div> {#- -#}
                                     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"> {#- -#}
+                            <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"> {#- -#}
+                                     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="main-content" class="content">{{- content|safe -}}</section> {#- -#}
             <section id="search" class="content hidden"></section> {#- -#}
         </div> {#- -#}
     </main> {#- -#}
-    {{- layout.external_html.after_content | safe -}}
+    {{- layout.external_html.after_content|safe -}}
     <div id="rustdoc-vars" {# -#}
-         data-root-path="{{page.root_path | safe}}" {# -#}
+         data-root-path="{{page.root_path|safe}}" {# -#}
          data-current-crate="{{layout.krate}}" {# -#}
-         data-themes="{{themes | join(sep=",") }}" {# -#}
+         data-themes="{{themes|join(",") }}" {# -#}
          data-resource-suffix="{{page.resource_suffix}}" {# -#}
          data-rustdoc-version="{{rustdoc_version}}" {# -#}
     > {#- -#}
index 5a468f3cc1ea02cca9ba17dfc339a6b9d6090bdc..459b01a9960d20b18ff4e005cb16740b5bf3c3ec 100644 (file)
@@ -1,26 +1,30 @@
-<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> {#- -#}
+<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> {#- -#}
-        {%- if src_href -%}
-        <a class="srclink" href="{{src_href | safe}}" title="goto source code">[src]</a>
-        {%- endif -%}
+    </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> {#- -#}
-</h1> {#- -#}
+</div>
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 c8efa4bbbcc300b8cfde8075f2ad07874de4ad6d..e77bd5c9223138ddc81b0a3faf07d0ade82cd450 100644 (file)
@@ -162,7 +162,7 @@ impl FromWithTcx<clean::TypeBindingKind> for TypeBindingKind {
     fn from_tcx(kind: clean::TypeBindingKind, tcx: TyCtxt<'_>) -> Self {
         use clean::TypeBindingKind::*;
         match kind {
-            Equality { ty } => TypeBindingKind::Equality(ty.into_tcx(tcx)),
+            Equality { term } => TypeBindingKind::Equality(term.into_tcx(tcx)),
             Constraint { bounds } => {
                 TypeBindingKind::Constraint(bounds.into_iter().map(|a| a.into_tcx(tcx)).collect())
             }
@@ -452,6 +452,15 @@ fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
     }
 }
 
+impl FromWithTcx<clean::Term> for Term {
+    fn from_tcx(term: clean::Term, tcx: TyCtxt<'_>) -> Term {
+        match term {
+            clean::Term::Type(ty) => Term::Type(FromWithTcx::from_tcx(ty, tcx)),
+            clean::Term::Constant(c) => Term::Constant(FromWithTcx::from_tcx(c, tcx)),
+        }
+    }
+}
+
 impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
     fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
         let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl;
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 d7741c4fde2391a0cb75c3e8c44d3c71f13b2cce..d854aa86b3afd0434a18270ad89e9b126fa034c6 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;
@@ -70,7 +71,8 @@
 use tikv_jemalloc_sys as jemalloc_sys;
 
 use std::default::Default;
-use std::env;
+use std::env::{self, VarError};
+use std::io;
 use std::process;
 
 use rustc_driver::{abort_on_err, describe_lints};
@@ -178,47 +180,20 @@ pub fn main() {
 }
 
 fn init_logging() {
-    use std::io;
-
-    // FIXME remove these and use winapi 0.3 instead
-    // Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs, rustc_driver/lib.rs
-    #[cfg(unix)]
-    fn stdout_isatty() -> bool {
-        extern crate libc;
-        unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
-    }
-
-    #[cfg(windows)]
-    fn stdout_isatty() -> bool {
-        extern crate winapi;
-        use winapi::um::consoleapi::GetConsoleMode;
-        use winapi::um::processenv::GetStdHandle;
-        use winapi::um::winbase::STD_OUTPUT_HANDLE;
-
-        unsafe {
-            let handle = GetStdHandle(STD_OUTPUT_HANDLE);
-            let mut out = 0;
-            GetConsoleMode(handle, &mut out) != 0
-        }
-    }
-
-    let color_logs = match std::env::var("RUSTDOC_LOG_COLOR") {
-        Ok(value) => match value.as_ref() {
-            "always" => true,
-            "never" => false,
-            "auto" => stdout_isatty(),
-            _ => early_error(
-                ErrorOutputType::default(),
-                &format!(
-                    "invalid log color value '{}': expected one of always, never, or auto",
-                    value
-                ),
-            ),
-        },
-        Err(std::env::VarError::NotPresent) => stdout_isatty(),
-        Err(std::env::VarError::NotUnicode(_value)) => early_error(
+    let color_logs = match std::env::var("RUSTDOC_LOG_COLOR").as_deref() {
+        Ok("always") => true,
+        Ok("never") => false,
+        Ok("auto") | Err(VarError::NotPresent) => atty::is(atty::Stream::Stdout),
+        Ok(value) => early_error(
+            ErrorOutputType::default(),
+            &format!("invalid log color value '{}': expected one of always, never, or auto", value),
+        ),
+        Err(VarError::NotUnicode(value)) => early_error(
             ErrorOutputType::default(),
-            "non-Unicode log color value: expected one of always, never, or auto",
+            &format!(
+                "invalid log color value '{}': expected one of always, never, or auto",
+                value.to_string_lossy()
+            ),
         ),
     };
     let filter = tracing_subscriber::EnvFilter::from_env("RUSTDOC_LOG");
index 49ff4517a4eb01d4f6b3ab8f48b95b9940d55b17..7dbf00420de126c3eec76c09640a3e5ffb766092 100644 (file)
@@ -6,14 +6,13 @@
 use rustc_data_structures::{fx::FxHashMap, stable_set::FxHashSet};
 use rustc_errors::{Applicability, DiagnosticBuilder};
 use rustc_expand::base::SyntaxExtensionKind;
-use rustc_hir as hir;
 use rustc_hir::def::{
     DefKind,
     Namespace::{self, *},
     PerNS,
 };
-use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_ID};
+use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug, ty};
 use rustc_resolve::ParentScope;
 use rustc_session::lint::Lint;
@@ -25,8 +24,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;
 
 };
 
 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
 }
@@ -113,6 +108,45 @@ fn as_hir_res(self) -> Option<rustc_hir::def::Res> {
             Res::Primitive(_) => None,
         }
     }
+
+    /// Used for error reporting.
+    fn disambiguator_suggestion(self) -> Suggestion {
+        let kind = match self {
+            Res::Primitive(_) => return Suggestion::Prefix("prim"),
+            Res::Def(kind, _) => kind,
+        };
+        if kind == DefKind::Macro(MacroKind::Bang) {
+            return Suggestion::Macro;
+        } else if kind == DefKind::Fn || kind == DefKind::AssocFn {
+            return Suggestion::Function;
+        } else if kind == DefKind::Field {
+            return Suggestion::RemoveDisambiguator;
+        }
+
+        let prefix = match kind {
+            DefKind::Struct => "struct",
+            DefKind::Enum => "enum",
+            DefKind::Trait => "trait",
+            DefKind::Union => "union",
+            DefKind::Mod => "mod",
+            DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => {
+                "const"
+            }
+            DefKind::Static => "static",
+            DefKind::Macro(MacroKind::Derive) => "derive",
+            // Now handle things that don't have a specific disambiguator
+            _ => match kind
+                .ns()
+                .expect("tried to calculate a disambiguator for a def without a namespace?")
+            {
+                Namespace::TypeNS => "type",
+                Namespace::ValueNS => "value",
+                Namespace::MacroNS => "macro",
+            },
+        };
+
+        Suggestion::Prefix(prefix)
+    }
 }
 
 impl TryFrom<ResolveRes> for Res {
@@ -240,53 +274,72 @@ 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 {
-        match kind {
+    #[instrument(level = "debug")]
+    fn from_assoc_item(item: &ty::AssocItem) -> Self {
+        let def_id = item.def_id;
+        match item.kind {
             ty::AssocKind::Fn => {
-                if is_prototype {
-                    UrlFragment::TyMethod(name)
+                if item.defaultness.has_value() {
+                    ItemFragment(FragmentKind::Method, def_id)
                 } else {
-                    UrlFragment::Method(name)
+                    ItemFragment(FragmentKind::TyMethod, 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 +349,7 @@ struct ResolutionInfo {
     module_id: DefId,
     dis: Option<Disambiguator>,
     path_str: String,
-    extra_fragment: Option<UrlFragment>,
+    extra_fragment: Option<String>,
 }
 
 #[derive(Clone)]
@@ -310,7 +363,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 +372,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>>,
@@ -335,12 +383,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
     /// In particular, this will return an error whenever there aren't three
     /// full path segments left in the link.
     ///
-    /// [enum struct variant]: hir::VariantData::Struct
+    /// [enum struct variant]: rustc_hir::VariantData::Struct
     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 +435,9 @@ 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.name == variant_field_name)
+                        {
+                            Ok((ty_res, Some(ItemFragment(FragmentKind::VariantField, field.did))))
                         } else {
                             Err(ResolutionFailure::NotResolved {
                                 module_id,
@@ -422,16 +465,15 @@ 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_| {
             tcx.associated_items(impl_)
                 .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);
+                    (Res::Primitive(prim_ty), fragment)
                 })
         })
     }
@@ -505,8 +547,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 +578,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 +612,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 {
@@ -651,17 +702,15 @@ fn primitive_type_to_ty(&mut self, prim: PrimitiveType) -> Option<Ty<'tcx>> {
         }))
     }
 
-    /// Returns:
-    /// - None if no associated item was found
-    /// - Some((_, _, Some(_))) if an item was found and should go through a side channel
-    /// - Some((_, _, None)) otherwise
+    /// Resolve an associated item, returning its containing page's `Res`
+    /// and the fragment targeting the associated item on its page.
     fn resolve_associated_item(
         &mut self,
         root_res: Res,
         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 {
@@ -675,12 +724,8 @@ fn resolve_associated_item(
                         .flatten();
 
                     assoc_item.map(|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.
-                        (root_res, fragment, Some((kind.as_def_kind(), item.def_id)))
+                        let fragment = ItemFragment::from_assoc_item(&item);
+                        (root_res, fragment)
                     })
                 })
             }
@@ -717,24 +762,20 @@ 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(
+                        resolve_associated_trait_item(
                             tcx.type_of(did),
                             module_id,
                             item_name,
                             ns,
                             self.cx,
-                        );
-                        debug!("got associated item {:?}", item);
-                        item
+                        )
                     });
 
+                debug!("got associated item {:?}", assoc_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);
+                    return Some((root_res, fragment));
                 }
 
                 if ns != Namespace::ValueNS {
@@ -760,28 +801,17 @@ fn resolve_associated_item(
                     ty::Adt(def, _) if !def.is_enum() => def,
                     _ => return None,
                 };
-                let field = def
-                    .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)),
-                ))
+                let field =
+                    def.non_enum_variant().fields.iter().find(|item| item.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,
-                        item.kind,
-                        !item.defaultness.has_value(),
-                    );
+                    let fragment = ItemFragment::from_assoc_item(item);
                     let res = Res::Def(item.kind.as_def_kind(), item.def_id);
-                    (res, fragment, None)
+                    (res, fragment)
                 }),
             _ => None,
         }
@@ -798,23 +828,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
     }
 }
 
@@ -836,30 +875,56 @@ fn resolve_associated_trait_item<'a>(
 
     // Next consider explicit impls: `impl MyTrait for MyType`
     // Give precedence to inherent impls.
-    let traits = traits_implemented_by(cx, ty, module);
+    let traits = trait_impls_for(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(
-            cx.tcx,
-            Ident::with_dummy_span(item_name),
-            ns,
-            trait_,
-        )
+    let mut candidates = traits.iter().filter_map(|&(impl_, trait_)| {
+        cx.tcx
+            .associated_items(trait_)
+            .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_)
+            .map(|trait_assoc| {
+                trait_assoc_to_impl_assoc_item(cx.tcx, impl_, trait_assoc.def_id)
+                    .unwrap_or(trait_assoc)
+            })
     });
     // FIXME(#74563): warn about ambiguity
     debug!("the candidates were {:?}", candidates.clone().collect::<Vec<_>>());
     candidates.next().copied()
 }
 
-/// Given a type, return all traits in scope in `module` implemented by that type.
+/// Find the associated item in the impl `impl_id` that corresponds to the
+/// trait associated item `trait_assoc_id`.
+///
+/// This function returns `None` if no associated item was found in the impl.
+/// This can occur when the trait associated item has a default value that is
+/// not overriden in the impl.
+///
+/// This is just a wrapper around [`TyCtxt::impl_item_implementor_ids()`] and
+/// [`TyCtxt::associated_item()`] (with some helpful logging added).
+#[instrument(level = "debug", skip(tcx))]
+fn trait_assoc_to_impl_assoc_item<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    impl_id: DefId,
+    trait_assoc_id: DefId,
+) -> Option<&'tcx ty::AssocItem> {
+    let trait_to_impl_assoc_map = tcx.impl_item_implementor_ids(impl_id);
+    debug!(?trait_to_impl_assoc_map);
+    let impl_assoc_id = *trait_to_impl_assoc_map.get(&trait_assoc_id)?;
+    debug!(?impl_assoc_id);
+    let impl_assoc = tcx.associated_item(impl_assoc_id);
+    debug!(?impl_assoc);
+    Some(impl_assoc)
+}
+
+/// Given a type, return all trait impls in scope in `module` for that type.
+/// Returns a set of pairs of `(impl_id, trait_id)`.
 ///
 /// 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<'a>(
+fn trait_impls_for<'a>(
     cx: &mut DocContext<'a>,
     ty: Ty<'a>,
     module: DefId,
-) -> FxHashSet<DefId> {
+) -> FxHashSet<(DefId, DefId)> {
     let mut resolver = cx.resolver.borrow_mut();
     let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| {
         resolver.access(|resolver| {
@@ -888,9 +953,20 @@ fn traits_implemented_by<'a>(
                 ty
             );
             // Fast path: if this is a primitive simple `==` will work
-            let saw_impl = impl_type == ty;
+            // NOTE: the `match` is necessary; see #92662.
+            // this allows us to ignore generics because the user input
+            // may not include the generic placeholders
+            // e.g. this allows us to match Foo (user comment) with Foo<T> (actual type)
+            let saw_impl = impl_type == ty
+                || match (impl_type.kind(), ty.kind()) {
+                    (ty::Adt(impl_def, _), ty::Adt(ty_def, _)) => {
+                        debug!("impl def_id: {:?}, ty def_id: {:?}", impl_def.did, ty_def.did);
+                        impl_def.did == ty_def.did
+                    }
+                    _ => false,
+                };
 
-            if saw_impl { Some(trait_) } else { None }
+            if saw_impl { Some((impl_, trait_)) } else { None }
         })
     });
     iter.collect()
@@ -912,8 +988,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() {
@@ -945,17 +1019,7 @@ fn visit_item(&mut self, item: &Item) {
             {
                 self.cx.tcx.parent(did)
             }
-            Some(did) => match self.cx.tcx.parent(did) {
-                // HACK(jynelson): `clean` marks associated types as `TypedefItem`, not as `AssocTypeItem`.
-                // Fixing this breaks `fn render_deref_methods`.
-                // As a workaround, see if the parent of the item is an `impl`; if so this must be an associated item,
-                // regardless of what rustdoc wants to call it.
-                Some(parent) => {
-                    let parent_kind = self.cx.tcx.def_kind(parent);
-                    Some(if parent_kind == DefKind::Impl { parent } else { did })
-                }
-                None => Some(did),
-            },
+            Some(did) => Some(did),
         };
 
         // FIXME(jynelson): this shouldn't go through stringification, rustdoc should just use the DefId directly
@@ -1033,7 +1097,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,
 }
 
@@ -1119,7 +1183,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(),
     }))
 }
@@ -1264,73 +1328,9 @@ fn resolve_link(
             }
         }
 
-        let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| {
-            // The resolved item did not match the disambiguator; give a better error than 'not found'
-            let msg = format!("incompatible link kind for `{}`", path_str);
-            let callback = |diag: &mut DiagnosticBuilder<'_>, sp: Option<rustc_span::Span>| {
-                let note = format!(
-                    "this link resolved to {} {}, which is not {} {}",
-                    resolved.article(),
-                    resolved.descr(),
-                    specified.article(),
-                    specified.descr()
-                );
-                if let Some(sp) = sp {
-                    diag.span_label(sp, &note);
-                } else {
-                    diag.note(&note);
-                }
-                suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp);
-            };
-            report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, callback);
-        };
-
-        let verify = |kind: DefKind, id: DefId| {
-            let (kind, id) = self.kind_side_channel.take().unwrap_or((kind, id));
-            debug!("intra-doc link to {} resolved to {:?} (id: {:?})", path_str, res, id);
-
-            // Disallow e.g. linking to enums with `struct@`
-            debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
-            match (kind, disambiguator) {
-                | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
-                // NOTE: this allows 'method' to mean both normal functions and associated functions
-                // This can't cause ambiguity because both are in the same namespace.
-                | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
-                // These are namespaces; allow anything in the namespace to match
-                | (_, Some(Disambiguator::Namespace(_)))
-                // If no disambiguator given, allow anything
-                | (_, None)
-                // All of these are valid, so do nothing
-                => {}
-                (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
-                (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
-                    report_mismatch(specified, Disambiguator::Kind(kind));
-                    return None;
-                }
-            }
-
-            // item can be non-local e.g. when using #[doc(primitive = "pointer")]
-            if let Some((src_id, dst_id)) = id
-                .as_local()
-                // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
-                // would presumably panic if a fake `DefIndex` were passed.
-                .and_then(|dst_id| {
-                    item.def_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
-                })
-            {
-                if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
-                    && !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
-                {
-                    privacy_error(self.cx, &diag_info, path_str);
-                }
-            }
-
-            Some(())
-        };
-
         match res {
             Res::Primitive(prim) => {
-                if let Some((kind, id)) = self.kind_side_channel.take() {
+                if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
                     // 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,
@@ -1339,7 +1339,16 @@ fn resolve_link(
                     // doesn't allow statements like `use str::trim;`, making this a (hopefully)
                     // valid omission. See https://github.com/rust-lang/rust/pull/80660#discussion_r551585677
                     // for discussion on the matter.
-                    verify(kind, id)?;
+                    let kind = self.cx.tcx.def_kind(id);
+                    self.verify_disambiguator(
+                        path_str,
+                        &ori_link,
+                        kind,
+                        id,
+                        disambiguator,
+                        item,
+                        &diag_info,
+                    )?;
 
                     // FIXME: it would be nice to check that the feature gate was enabled in the original crate, not just ignore it altogether.
                     // However I'm not sure how to check that across crates.
@@ -1347,28 +1356,15 @@ 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 {
                         Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => {}
                         Some(other) => {
-                            report_mismatch(other, Disambiguator::Primitive);
+                            self.report_disambiguator_mismatch(
+                                path_str, &ori_link, other, res, &diag_info,
+                            );
                             return None;
                         }
                     }
@@ -1382,24 +1378,129 @@ fn resolve_link(
                 })
             }
             Res::Def(kind, id) => {
-                verify(kind, id)?;
+                let (kind_for_dis, id_for_dis) =
+                    if let Some(UrlFragment::Item(ItemFragment(_, id))) = fragment {
+                        (self.cx.tcx.def_kind(id), id)
+                    } else {
+                        (kind, id)
+                    };
+                self.verify_disambiguator(
+                    path_str,
+                    &ori_link,
+                    kind_for_dis,
+                    id_for_dis,
+                    disambiguator,
+                    item,
+                    &diag_info,
+                )?;
                 let id = clean::register_res(self.cx, rustc_hir::def::Res::Def(kind, id));
                 Some(ItemLink { link: ori_link.link, link_text, did: id, fragment })
             }
         }
     }
 
+    fn verify_disambiguator(
+        &self,
+        path_str: &str,
+        ori_link: &MarkdownLink,
+        kind: DefKind,
+        id: DefId,
+        disambiguator: Option<Disambiguator>,
+        item: &Item,
+        diag_info: &DiagnosticInfo<'_>,
+    ) -> Option<()> {
+        debug!("intra-doc link to {} resolved to {:?}", path_str, (kind, id));
+
+        // Disallow e.g. linking to enums with `struct@`
+        debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
+        match (kind, disambiguator) {
+                | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
+                // NOTE: this allows 'method' to mean both normal functions and associated functions
+                // This can't cause ambiguity because both are in the same namespace.
+                | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
+                // These are namespaces; allow anything in the namespace to match
+                | (_, Some(Disambiguator::Namespace(_)))
+                // If no disambiguator given, allow anything
+                | (_, None)
+                // All of these are valid, so do nothing
+                => {}
+                (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
+                (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => {
+                    self.report_disambiguator_mismatch(path_str,ori_link,specified, Res::Def(kind, id),diag_info);
+                    return None;
+                }
+            }
+
+        // item can be non-local e.g. when using #[doc(primitive = "pointer")]
+        if let Some((src_id, dst_id)) = id
+            .as_local()
+            // The `expect_def_id()` should be okay because `local_def_id_to_hir_id`
+            // would presumably panic if a fake `DefIndex` were passed.
+            .and_then(|dst_id| {
+                item.def_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
+            })
+        {
+            if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
+                && !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
+            {
+                privacy_error(self.cx, diag_info, path_str);
+            }
+        }
+
+        Some(())
+    }
+
+    fn report_disambiguator_mismatch(
+        &self,
+        path_str: &str,
+        ori_link: &MarkdownLink,
+        specified: Disambiguator,
+        resolved: Res,
+        diag_info: &DiagnosticInfo<'_>,
+    ) {
+        // The resolved item did not match the disambiguator; give a better error than 'not found'
+        let msg = format!("incompatible link kind for `{}`", path_str);
+        let callback = |diag: &mut DiagnosticBuilder<'_>, sp: Option<rustc_span::Span>| {
+            let note = format!(
+                "this link resolved to {} {}, which is not {} {}",
+                resolved.article(),
+                resolved.descr(),
+                specified.article(),
+                specified.descr(),
+            );
+            if let Some(sp) = sp {
+                diag.span_label(sp, &note);
+            } else {
+                diag.note(&note);
+            }
+            suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp);
+        };
+        report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, &diag_info, callback);
+    }
+
+    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,
         diag: DiagnosticInfo<'_>,
         cache_resolution_failure: bool,
     ) -> Option<(Res, Option<UrlFragment>)> {
-        // Try to look up both the result and the corresponding side channel value
         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,
@@ -1416,13 +1517,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 {
@@ -1484,7 +1579,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);
@@ -1516,7 +1611,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)))
+                                    }
                                 }
                             }
                         }
@@ -1553,7 +1651,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] {
@@ -1672,53 +1770,6 @@ fn from_str(link: &str) -> Result<Option<(Self, &str, &str)>, (String, Range<usi
         }
     }
 
-    fn from_res(res: Res) -> Self {
-        match res {
-            Res::Def(kind, _) => Disambiguator::Kind(kind),
-            Res::Primitive(_) => Disambiguator::Primitive,
-        }
-    }
-
-    /// Used for error reporting.
-    fn suggestion(self) -> Suggestion {
-        let kind = match self {
-            Disambiguator::Primitive => return Suggestion::Prefix("prim"),
-            Disambiguator::Kind(kind) => kind,
-            Disambiguator::Namespace(_) => panic!("display_for cannot be used on namespaces"),
-        };
-        if kind == DefKind::Macro(MacroKind::Bang) {
-            return Suggestion::Macro;
-        } else if kind == DefKind::Fn || kind == DefKind::AssocFn {
-            return Suggestion::Function;
-        } else if kind == DefKind::Field {
-            return Suggestion::RemoveDisambiguator;
-        }
-
-        let prefix = match kind {
-            DefKind::Struct => "struct",
-            DefKind::Enum => "enum",
-            DefKind::Trait => "trait",
-            DefKind::Union => "union",
-            DefKind::Mod => "mod",
-            DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => {
-                "const"
-            }
-            DefKind::Static => "static",
-            DefKind::Macro(MacroKind::Derive) => "derive",
-            // Now handle things that don't have a specific disambiguator
-            _ => match kind
-                .ns()
-                .expect("tried to calculate a disambiguator for a def without a namespace?")
-            {
-                Namespace::TypeNS => "type",
-                Namespace::ValueNS => "value",
-                Namespace::MacroNS => "macro",
-            },
-        };
-
-        Suggestion::Prefix(prefix)
-    }
-
     fn ns(self) -> Namespace {
         match self {
             Self::Namespace(n) => n,
@@ -1740,9 +1791,9 @@ fn article(self) -> &'static str {
     fn descr(self) -> &'static str {
         match self {
             Self::Namespace(n) => n.descr(),
-            // HACK(jynelson): by looking at the source I saw the DefId we pass
-            // for `expected.descr()` doesn't matter, since it's not a crate
-            Self::Kind(k) => k.descr(DefId::local(hir::def_id::DefIndex::from_usize(0))),
+            // HACK(jynelson): the source of `DefKind::descr` only uses the DefId for
+            // printing "module" vs "crate" so using the wrong ID is not a huge problem
+            Self::Kind(k) => k.descr(CRATE_DEF_ID.to_def_id()),
             Self::Primitive => "builtin type",
         }
     }
@@ -2066,16 +2117,7 @@ fn split(path: &str) -> Option<(&str, &str)> {
                     ResolutionFailure::NotResolved { .. } => unreachable!("handled above"),
                     ResolutionFailure::Dummy => continue,
                     ResolutionFailure::WrongNamespace { res, expected_ns } => {
-                        if let Res::Def(kind, _) = res {
-                            let disambiguator = Disambiguator::Kind(kind);
-                            suggest_disambiguator(
-                                disambiguator,
-                                diag,
-                                path_str,
-                                diag_info.ori_link,
-                                sp,
-                            )
-                        }
+                        suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
 
                         format!(
                             "this link resolves to {}, which is not in the {} namespace",
@@ -2210,8 +2252,7 @@ fn ambiguity_error(
         }
 
         for res in candidates {
-            let disambiguator = Disambiguator::from_res(res);
-            suggest_disambiguator(disambiguator, diag, path_str, diag_info.ori_link, sp);
+            suggest_disambiguator(res, diag, path_str, diag_info.ori_link, sp);
         }
     });
 }
@@ -2219,14 +2260,14 @@ fn ambiguity_error(
 /// In case of an ambiguity or mismatched disambiguator, suggest the correct
 /// disambiguator.
 fn suggest_disambiguator(
-    disambiguator: Disambiguator,
+    res: Res,
     diag: &mut DiagnosticBuilder<'_>,
     path_str: &str,
     ori_link: &str,
     sp: Option<rustc_span::Span>,
 ) {
-    let suggestion = disambiguator.suggestion();
-    let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr());
+    let suggestion = res.disambiguator_suggestion();
+    let help = format!("to link to the {}, {}", res.descr(), suggestion.descr());
 
     if let Some(sp) = sp {
         let mut spans = suggestion.as_help_span(path_str, ori_link, sp);
@@ -2272,20 +2313,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 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..c509d3f882c78b692a32f2809ec1a3bab96c5e97 100644 (file)
@@ -14,6 +14,7 @@
 use rustc_interface::interface;
 use rustc_macros::{Decodable, Encodable};
 use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_serialize::{
     opaque::{Decoder, FileEncoder},
@@ -117,10 +118,10 @@ impl<'a, 'tcx> Visitor<'tcx> for FindCalls<'a, 'tcx>
 where
     'tcx: 'a,
 {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::OnlyBodies(self.map)
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.map
     }
 
     fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
@@ -173,7 +174,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;
index 6f1736afc3bdc510915bc09033a52e0844c2d212..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> {
index 9466f84ffcd59192dce3492270034af4efdfdd0a..618c8aab86a19416986712912d64f3cb853cbb65 100644 (file)
@@ -148,7 +148,7 @@ pub struct TypeBinding {
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 #[serde(rename_all = "snake_case")]
 pub enum TypeBindingKind {
-    Equality(Type),
+    Equality(Term),
     Constraint(Vec<GenericBound>),
 }
 
@@ -335,7 +335,7 @@ pub enum GenericParamDefKind {
 pub enum WherePredicate {
     BoundPredicate { ty: Type, bounds: Vec<GenericBound> },
     RegionPredicate { lifetime: String, bounds: Vec<GenericBound> },
-    EqPredicate { lhs: Type, rhs: Type },
+    EqPredicate { lhs: Type, rhs: Term },
 }
 
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
@@ -359,6 +359,13 @@ pub enum TraitBoundModifier {
     MaybeConst,
 }
 
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[serde(rename_all = "snake_case")]
+pub enum Term {
+    Type(Type),
+    Constant(Constant),
+}
+
 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 #[serde(rename_all = "snake_case")]
 #[serde(tag = "kind", content = "inner")]
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]*]]
diff --git a/src/test/codegen/no-output-asm-is-volatile.rs b/src/test/codegen/no-output-asm-is-volatile.rs
deleted file mode 100644 (file)
index 4037621..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// compile-flags: -O
-
-#![feature(llvm_asm)]
-#![crate_type = "lib"]
-
-// Check that inline assembly expressions without any outputs
-// are marked as having side effects / being volatile
-
-// CHECK-LABEL: @assembly
-#[no_mangle]
-pub fn assembly() {
-    unsafe { llvm_asm!("") }
-// CHECK: tail call void asm sideeffect "", {{.*}}
-}
index 5ac30d949fa4e4c5aff0611d88ca4fca41a6e892..c59b088f7a6d66264bba29d7d7d0a37d63579a7c 100644 (file)
@@ -19,7 +19,7 @@
 // CHECK-LABEL: @get
 #[no_mangle]
 fn get() -> u32 {
-    // CHECK: %0 = load i32, i32* bitcast ({{.*}} [[TLS]] to i32*)
+    // CHECK: %0 = load i32, i32* {{.*}}[[TLS]]{{.*}}
     // CHECK-NEXT: ret i32 %0
     A.with(|a| a.get())
 }
@@ -27,7 +27,7 @@ fn get() -> u32 {
 // CHECK-LABEL: @set
 #[no_mangle]
 fn set(v: u32) {
-    // CHECK: store i32 %0, i32* bitcast ({{.*}} [[TLS]] to i32*)
+    // CHECK: store i32 %0, i32* {{.*}}[[TLS]]{{.*}}
     // CHECK-NEXT: ret void
     A.with(|a| a.set(v))
 }
index 7f1ef886ac83152d8ae32b8434173e79a03bf140..9cf611c3379e8b9ef23579ce6c72b2a0483d7a68 100644 (file)
@@ -7,7 +7,7 @@
 
 // The `l33t haxx0r` Rust compiler is known to produce incr. comp. artifacts
 // that are outrageously incompatible with just about anything, even itself:
-//[rpass1] rustc-env:RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER="l33t haxx0r rustc 2.1 LTS"
+//[rpass1] rustc-env:RUSTC_FORCE_RUSTC_VERSION="l33t haxx0r rustc 2.1 LTS"
 
 // revisions:rpass1 rpass2
 // compile-flags: -Z query-dep-graph
index 1ddb345e5664c20f6b6a1e8159ee792993c68f53..bb836f203f5c060f1f2e0ac5dbc801bc3b8e305c 100644 (file)
 
 #![allow(warnings)]
 #![feature(rustc_attrs)]
-#![feature(llvm_asm)]
 #![crate_type="rlib"]
 
-
+use std::arch::asm;
 
 // Change template
 #[cfg(any(cfail1,cfail4))]
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-pub fn change_template(a: i32) -> i32 {
+pub fn change_template(_a: i32) -> i32 {
     let c: i32;
     unsafe {
-        llvm_asm!("add 1, $0"
-                  : "=r"(c)
-                  : "0"(a)
-                  :
-                  :
-                  );
+        asm!("mov {0}, 1",
+             out(reg) c
+             );
     }
     c
 }
@@ -45,15 +41,12 @@ pub fn change_template(a: i32) -> i32 {
 #[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
 #[rustc_clean(cfg="cfail6")]
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-pub fn change_template(a: i32) -> i32 {
+pub fn change_template(_a: i32) -> i32 {
     let c: i32;
     unsafe {
-        llvm_asm!("add 2, $0"
-                  : "=r"(c)
-                  : "0"(a)
-                  :
-                  :
-                  );
+        asm!("mov {0}, 2",
+             out(reg) c
+             );
     }
     c
 }
@@ -67,12 +60,10 @@ pub fn change_output(a: i32) -> i32 {
     let mut _out1: i32 = 0;
     let mut _out2: i32 = 0;
     unsafe {
-        llvm_asm!("add 1, $0"
-                  : "=r"(_out1)
-                  : "0"(a)
-                  :
-                  :
-                  );
+        asm!("mov {0}, {1}",
+             out(reg) _out1,
+             in(reg) a
+             );
     }
     _out1
 }
@@ -87,12 +78,10 @@ pub fn change_output(a: i32) -> i32 {
     let mut _out1: i32 = 0;
     let mut _out2: i32 = 0;
     unsafe {
-        llvm_asm!("add 1, $0"
-                  : "=r"(_out2)
-                  : "0"(a)
-                  :
-                  :
-                  );
+        asm!("mov {0}, {1}",
+             out(reg) _out2,
+             in(reg) a
+             );
     }
     _out1
 }
@@ -105,12 +94,10 @@ pub fn change_output(a: i32) -> i32 {
 pub fn change_input(_a: i32, _b: i32) -> i32 {
     let _out;
     unsafe {
-        llvm_asm!("add 1, $0"
-                  : "=r"(_out)
-                  : "0"(_a)
-                  :
-                  :
-                  );
+        asm!("mov {0}, {1}",
+             out(reg) _out,
+             in(reg) _a
+             );
     }
     _out
 }
@@ -124,12 +111,10 @@ pub fn change_input(_a: i32, _b: i32) -> i32 {
 pub fn change_input(_a: i32, _b: i32) -> i32 {
     let _out;
     unsafe {
-        llvm_asm!("add 1, $0"
-                  : "=r"(_out)
-                  : "0"(_b)
-                  :
-                  :
-                  );
+        asm!("mov {0}, {1}",
+             out(reg) _out,
+             in(reg) _b
+             );
     }
     _out
 }
@@ -142,12 +127,10 @@ pub fn change_input(_a: i32, _b: i32) -> i32 {
 pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
     let _out;
     unsafe {
-        llvm_asm!("add 1, $0"
-                  : "=r"(_out)
-                  : "0"(_a), "r"(_b)
-                  :
-                  :
-                  );
+        asm!("mov {0}, {1}",
+             out(reg) _out,
+             in(reg) _a,
+             in("eax") _b);
     }
     _out
 }
@@ -161,30 +144,26 @@ pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
 pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
     let _out;
     unsafe {
-        llvm_asm!("add 1, $0"
-                  : "=r"(_out)
-                  : "r"(_a), "0"(_b)
-                  :
-                  :
-                  );
+        asm!("mov {0}, {1}",
+             out(reg) _out,
+             in(reg) _a,
+             in("ecx") _b);
     }
     _out
 }
 
 
-
 // Change clobber
 #[cfg(any(cfail1,cfail4))]
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
 pub fn change_clobber(_a: i32) -> i32 {
     let _out;
     unsafe {
-        llvm_asm!("add 1, $0"
-                  : "=r"(_out)
-                  : "0"(_a)
-                  :/*--*/
-                  :
-                  );
+        asm!("mov {0}, {1}",
+             out(reg) _out,
+             in(reg) _a,
+             lateout("ecx") _
+             );
     }
     _out
 }
@@ -198,12 +177,11 @@ pub fn change_clobber(_a: i32) -> i32 {
 pub fn change_clobber(_a: i32) -> i32 {
     let _out;
     unsafe {
-        llvm_asm!("add 1, $0"
-                  : "=r"(_out)
-                  : "0"(_a)
-                  : "eax"
-                  :
-                  );
+        asm!("mov {0}, {1}",
+             out(reg) _out,
+             in(reg) _a,
+             lateout("edx") _
+             );
     }
     _out
 }
@@ -216,12 +194,11 @@ pub fn change_clobber(_a: i32) -> i32 {
 pub fn change_options(_a: i32) -> i32 {
     let _out;
     unsafe {
-        llvm_asm!("add 1, $0"
-                  : "=r"(_out)
-                  : "0"(_a)
-                  :
-                  :/*-------*/
-                  );
+        asm!("mov {0}, {1}",
+             out(reg) _out,
+             in(reg) _a,
+             options(readonly),
+             );
     }
     _out
 }
@@ -235,12 +212,11 @@ pub fn change_options(_a: i32) -> i32 {
 pub fn change_options(_a: i32) -> i32 {
     let _out;
     unsafe {
-        llvm_asm!("add 1, $0"
-                  : "=r"(_out)
-                  : "0"(_a)
-                  :
-                  : "volatile"
-                  );
+        asm!("mov {0}, {1}",
+             out(reg) _out,
+             in(reg) _a,
+             options(nomem   ),
+             );
     }
     _out
 }
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
diff --git a/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_asm.main.UnreachablePropagation.diff
deleted file mode 100644 (file)
index c60997b..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-- // MIR for `main` before UnreachablePropagation
-+ // MIR for `main` after UnreachablePropagation
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/unreachable_asm.rs:10:11: 10:11
-      let mut _1: std::option::Option<Empty>; // in scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30
-      let mut _2: isize;                   // in scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
-      let _3: Empty;                       // in scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
-      let mut _4: i32;                     // in scope 0 at $DIR/unreachable_asm.rs:12:13: 12:19
-      let _5: ();                          // in scope 0 at $DIR/unreachable_asm.rs:14:9: 18:10
-      let mut _6: bool;                    // in scope 0 at $DIR/unreachable_asm.rs:14:12: 14:16
-      let _7: ();                          // in scope 0 at $DIR/unreachable_asm.rs:21:9: 21:37
-      let mut _8: !;                       // in scope 0 at $DIR/unreachable_asm.rs:22:9: 22:21
-      scope 1 {
-          debug _x => _3;                  // in scope 1 at $DIR/unreachable_asm.rs:11:17: 11:19
-      }
-      scope 2 {
-          debug _y => _4;                  // in scope 2 at $DIR/unreachable_asm.rs:12:13: 12:19
-          scope 3 {
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30
-          _1 = empty() -> bb1;             // scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30
-                                           // mir::Constant
-                                           // + span: $DIR/unreachable_asm.rs:11:23: 11:28
-                                           // + literal: Const { ty: fn() -> std::option::Option<Empty> {empty}, val: Value(Scalar(<ZST>)) }
-      }
-  
-      bb1: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
-          switchInt(move _2) -> [1_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
-      }
-  
-      bb2: {
-          StorageLive(_3);                 // scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
-          _3 = move ((_1 as Some).0: Empty); // scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
-          StorageLive(_4);                 // scope 0 at $DIR/unreachable_asm.rs:12:13: 12:19
-          StorageLive(_5);                 // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10
-          StorageLive(_6);                 // scope 2 at $DIR/unreachable_asm.rs:14:12: 14:16
-          _6 = const true;                 // scope 2 at $DIR/unreachable_asm.rs:14:12: 14:16
-          switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable_asm.rs:14:12: 14:16
-      }
-  
-      bb3: {
-          _4 = const 21_i32;               // scope 2 at $DIR/unreachable_asm.rs:15:13: 15:20
-          _5 = const ();                   // scope 2 at $DIR/unreachable_asm.rs:14:17: 16:10
-          goto -> bb5;                     // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10
-      }
-  
-      bb4: {
-          _4 = const 42_i32;               // scope 2 at $DIR/unreachable_asm.rs:17:13: 17:20
-          _5 = const ();                   // scope 2 at $DIR/unreachable_asm.rs:16:16: 18:10
-          goto -> bb5;                     // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10
-      }
-  
-      bb5: {
-          StorageDead(_6);                 // scope 2 at $DIR/unreachable_asm.rs:18:9: 18:10
-          StorageDead(_5);                 // scope 2 at $DIR/unreachable_asm.rs:18:9: 18:10
-          StorageLive(_7);                 // scope 2 at $DIR/unreachable_asm.rs:21:9: 21:37
-          llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm.rs:21:18: 21:34
-          _7 = const ();                   // scope 3 at $DIR/unreachable_asm.rs:21:9: 21:37
-          StorageDead(_7);                 // scope 2 at $DIR/unreachable_asm.rs:21:36: 21:37
-          StorageLive(_8);                 // scope 2 at $DIR/unreachable_asm.rs:22:9: 22:21
-          unreachable;                     // scope 2 at $DIR/unreachable_asm.rs:22:15: 22:17
-      }
-  
-      bb6: {
-          _0 = const ();                   // scope 0 at $DIR/unreachable_asm.rs:23:6: 23:6
-          StorageDead(_1);                 // scope 0 at $DIR/unreachable_asm.rs:24:1: 24:2
-          return;                          // scope 0 at $DIR/unreachable_asm.rs:24:2: 24:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/unreachable_asm.rs b/src/test/mir-opt/unreachable_asm.rs
deleted file mode 100644 (file)
index cbef05a..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#![feature(llvm_asm)]
-
-enum Empty {}
-
-fn empty() -> Option<Empty> {
-    None
-}
-
-// EMIT_MIR unreachable_asm.main.UnreachablePropagation.diff
-fn main() {
-    if let Some(_x) = empty() {
-        let mut _y;
-
-        if true {
-            _y = 21;
-        } else {
-            _y = 42;
-        }
-
-        // asm instruction stops unreachable propagation to if else blocks bb4 and bb5.
-        unsafe { llvm_asm!("NOP"); }
-        match _x { }
-    }
-}
diff --git a/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff b/src/test/mir-opt/unreachable_asm_2.main.UnreachablePropagation.diff
deleted file mode 100644 (file)
index 28c5f03..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-- // MIR for `main` before UnreachablePropagation
-+ // MIR for `main` after UnreachablePropagation
-  
-  fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/unreachable_asm_2.rs:10:11: 10:11
-      let mut _1: std::option::Option<Empty>; // in scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30
-      let mut _2: isize;                   // in scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
-      let _3: Empty;                       // in scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
-      let mut _4: i32;                     // in scope 0 at $DIR/unreachable_asm_2.rs:12:13: 12:19
-      let _5: ();                          // in scope 0 at $DIR/unreachable_asm_2.rs:14:9: 22:10
-      let mut _6: bool;                    // in scope 0 at $DIR/unreachable_asm_2.rs:14:12: 14:16
-      let _7: ();                          // in scope 0 at $DIR/unreachable_asm_2.rs:16:13: 16:41
-      let _8: ();                          // in scope 0 at $DIR/unreachable_asm_2.rs:20:13: 20:41
-      let mut _9: !;                       // in scope 0 at $DIR/unreachable_asm_2.rs:24:9: 24:21
-      scope 1 {
-          debug _x => _3;                  // in scope 1 at $DIR/unreachable_asm_2.rs:11:17: 11:19
-      }
-      scope 2 {
-          debug _y => _4;                  // in scope 2 at $DIR/unreachable_asm_2.rs:12:13: 12:19
-          scope 3 {
-          }
-          scope 4 {
-          }
-      }
-  
-      bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30
-          _1 = empty() -> bb1;             // scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30
-                                           // mir::Constant
-                                           // + span: $DIR/unreachable_asm_2.rs:11:23: 11:28
-                                           // + literal: Const { ty: fn() -> std::option::Option<Empty> {empty}, val: Value(Scalar(<ZST>)) }
-      }
-  
-      bb1: {
-          _2 = discriminant(_1);           // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
--         switchInt(move _2) -> [1_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
-+         switchInt(move _2) -> [1_isize: bb2, otherwise: bb5]; // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
-      }
-  
-      bb2: {
-          StorageLive(_3);                 // scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
-          _3 = move ((_1 as Some).0: Empty); // scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
-          StorageLive(_4);                 // scope 0 at $DIR/unreachable_asm_2.rs:12:13: 12:19
-          StorageLive(_5);                 // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
-          StorageLive(_6);                 // scope 2 at $DIR/unreachable_asm_2.rs:14:12: 14:16
-          _6 = const true;                 // scope 2 at $DIR/unreachable_asm_2.rs:14:12: 14:16
-          switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable_asm_2.rs:14:12: 14:16
-      }
-  
-      bb3: {
-          StorageLive(_7);                 // scope 2 at $DIR/unreachable_asm_2.rs:16:13: 16:41
-          llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm_2.rs:16:22: 16:38
-          _7 = const ();                   // scope 3 at $DIR/unreachable_asm_2.rs:16:13: 16:41
-          StorageDead(_7);                 // scope 2 at $DIR/unreachable_asm_2.rs:16:40: 16:41
-          _4 = const 21_i32;               // scope 2 at $DIR/unreachable_asm_2.rs:17:13: 17:20
-          _5 = const ();                   // scope 2 at $DIR/unreachable_asm_2.rs:14:17: 18:10
--         goto -> bb5;                     // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
-+         unreachable;                     // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
-      }
-  
-      bb4: {
-          StorageLive(_8);                 // scope 2 at $DIR/unreachable_asm_2.rs:20:13: 20:41
-          llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 4 at $DIR/unreachable_asm_2.rs:20:22: 20:38
-          _8 = const ();                   // scope 4 at $DIR/unreachable_asm_2.rs:20:13: 20:41
-          StorageDead(_8);                 // scope 2 at $DIR/unreachable_asm_2.rs:20:40: 20:41
-          _4 = const 42_i32;               // scope 2 at $DIR/unreachable_asm_2.rs:21:13: 21:20
-          _5 = const ();                   // scope 2 at $DIR/unreachable_asm_2.rs:18:16: 22:10
--         goto -> bb5;                     // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
-+         unreachable;                     // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
-      }
-  
-      bb5: {
--         StorageDead(_6);                 // scope 2 at $DIR/unreachable_asm_2.rs:22:9: 22:10
--         StorageDead(_5);                 // scope 2 at $DIR/unreachable_asm_2.rs:22:9: 22:10
--         StorageLive(_9);                 // scope 2 at $DIR/unreachable_asm_2.rs:24:9: 24:21
--         unreachable;                     // scope 2 at $DIR/unreachable_asm_2.rs:24:15: 24:17
--     }
-- 
--     bb6: {
-          _0 = const ();                   // scope 0 at $DIR/unreachable_asm_2.rs:25:6: 25:6
-          StorageDead(_1);                 // scope 0 at $DIR/unreachable_asm_2.rs:26:1: 26:2
-          return;                          // scope 0 at $DIR/unreachable_asm_2.rs:26:2: 26:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/unreachable_asm_2.rs b/src/test/mir-opt/unreachable_asm_2.rs
deleted file mode 100644 (file)
index e0d8e72..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#![feature(llvm_asm)]
-
-enum Empty {}
-
-fn empty() -> Option<Empty> {
-    None
-}
-
-// EMIT_MIR unreachable_asm_2.main.UnreachablePropagation.diff
-fn main() {
-    if let Some(_x) = empty() {
-        let mut _y;
-
-        if true {
-            // asm instruction stops unreachable propagation to block bb3.
-            unsafe { llvm_asm!("NOP"); }
-            _y = 21;
-        } else {
-            // asm instruction stops unreachable propagation to block bb3.
-            unsafe { llvm_asm!("NOP"); }
-            _y = 42;
-        }
-
-        match _x { }
-    }
-}
diff --git a/src/test/pretty/llvm-asm-clobbers.rs b/src/test/pretty/llvm-asm-clobbers.rs
deleted file mode 100644 (file)
index 2c09646..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#![feature(llvm_asm)]
-
-pub fn main() { unsafe { llvm_asm!("" : : : "hello", "world") }; }
diff --git a/src/test/pretty/llvm-asm-options.rs b/src/test/pretty/llvm-asm-options.rs
deleted file mode 100644 (file)
index 86a881b..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#![feature(llvm_asm)]
-
-// pp-exact
-
-pub fn main() {
-    unsafe {
-        llvm_asm!("" : : : : "volatile");
-        llvm_asm!("" : : : : "alignstack");
-        llvm_asm!("" : : : : "intel");
-    }
-}
index 41227898f24a8fcfcbd57e425b6cdbd49928b0c1..7af80979b4349effb1cc5465ec438822d7c38953 100644 (file)
@@ -1,8 +1,8 @@
 // pp-exact
 
-#![feature(llvm_asm)]
-
 #[cfg(foo = r#"just parse this"#)]
 extern crate blah as blah;
 
-fn main() { unsafe { llvm_asm!(r###"blah"###); } }
+use std::arch::asm;
+
+fn main() { unsafe { asm!(r###"blah"###); } }
index 39e9a9bdd6b684493da1400d21413eb55fb59423..f1410b69b3fceafe49a87bbab3a602b00610c3f0 100644 (file)
@@ -24,8 +24,8 @@ all:
        $(RUSTC) -C lto dummy.rs
 
        # Should not link dead code...
-       $(RUSTC) -Z print-link-args dummy.rs 2>&1 | \
+       $(RUSTC) --print link-args dummy.rs 2>&1 | \
                $(CGREP) -e '--gc-sections|-z[^ ]* [^ ]*<ignore>|-dead_strip|/OPT:REF'
        # ... unless you specifically ask to keep it
-       $(RUSTC) -Z print-link-args -C link-dead-code dummy.rs 2>&1 | \
+       $(RUSTC) --print link-args -C link-dead-code dummy.rs 2>&1 | \
                $(CGREP) -ve '--gc-sections|-z[^ ]* [^ ]*<ignore>|-dead_strip|/OPT:REF'
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 fd66702db7f2a1115b9cfd2f0245d0a7ff04ad39..091508cd805b9b0b6f5534cf9f747ac1732fb83b 100644 (file)
@@ -27,7 +27,7 @@ all:
        $(RUSTC) b.rs --extern a=$(TMPDIR)/liba$(EXT) --crate-type=bin -Crpath $(FLAGS)
        $(call RUN,b)
        # Now re-compile a.rs with another rustc version
-       RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER=deadfeed $(RUSTC) a.rs --crate-type=dylib $(FLAGS)
+       RUSTC_FORCE_RUSTC_VERSION=deadfeed $(RUSTC) a.rs --crate-type=dylib $(FLAGS)
        # After compiling with a different rustc version, write symbols to disk again.
        $(NM_CMD) $(call DYLIB,a) > $(TMPDIR)/symbolsafter
        # As a sanity check, test if the symbols changed:
index 1268022e37b744294eb2772f96333598109f9e33..0a50859cdaa4dd670423cb6cefcec9e546e38843 100644 (file)
@@ -11,4 +11,4 @@
 all: $(call NATIVE_STATICLIB,foo) $(call NATIVE_STATICLIB,bar)
        $(RUSTC) foo.rs
        $(RUSTC) bar.rs
-       $(RUSTC) main.rs -Z print-link-args
+       $(RUSTC) main.rs --print link-args
index 2e81667cf39c6f6f95e425063ed2ea1cfc3dae8d..e7b9694d9f2ad6f20a2fb17d70f45b0550451f5c 100644 (file)
@@ -1,12 +1,11 @@
-#![feature(llvm_asm)]
 #![crate_type="lib"]
+use std::arch::asm;
 
 #[deny(unreachable_code)]
 pub fn exit(n: usize) -> i32 {
     unsafe {
         // Pretend this asm is an exit() syscall.
-        llvm_asm!("" :: "r"(n) :: "volatile");
-        // Can't actually reach this point, but rustc doesn't know that.
+        asm!("/*{0}*/", in(reg) n);
     }
     // This return value is just here to generate some extra code for a return
     // value, making it easier for the test script to detect whether the
index fb3848b0db617aead09adef1525ec4a728d17bb4..ec85db733df04d59a3c461d3eb6c64f252c2f15c 100644 (file)
@@ -1,5 +1,6 @@
-#![feature(llvm_asm, core_intrinsics)]
+#![feature(core_intrinsics)]
 #![crate_type="lib"]
+use std::arch::asm;
 
 use std::intrinsics;
 
@@ -7,7 +8,7 @@
 pub fn exit(n: usize) -> i32 {
     unsafe {
         // Pretend this asm is an exit() syscall.
-        llvm_asm!("" :: "r"(n) :: "volatile");
+        asm!("/*{0}*/", in(reg) n);
         intrinsics::unreachable()
     }
     // This return value is just here to generate some extra code for a return
index d7c9fd2711285b14e2f4c28edc2954b955cd93d0..0360ede762551a673873abba499d6293992e2df0 100644 (file)
@@ -1,5 +1,5 @@
 -include ../tools.mk
-RUSTC_FLAGS = -C link-arg="-lfoo" -C link-arg="-lbar" -Z print-link-args
+RUSTC_FLAGS = -C link-arg="-lfoo" -C link-arg="-lbar" --print link-args
 
 all:
        $(RUSTC) $(RUSTC_FLAGS) empty.rs | $(CGREP) lfoo lbar
index 09e6ae0bbf7cd01f578084b768dd967d7f02d505..3ffbba9444bc2ea338d31e8e31c184c99f7980d2 100644 (file)
@@ -6,5 +6,5 @@ all:
        $(RUSTC) bar.rs \
                --extern foo1=$(TMPDIR)/libfoo-a.rlib \
                --extern foo2=$(TMPDIR)/libfoo-b.rlib \
-               -Z print-link-args
+               --print link-args
        $(call RUN,bar)
index b9688f16c646465d82d216f8b42579c1cf2220da..2e41be39d5d00851348915f5ebfa2e2a200f5ed3 100644 (file)
@@ -6,4 +6,4 @@ all:
        # Build an executable that depends on that crate using LTO. The no_builtins crate doesn't
        # participate in LTO, so its rlib must be explicitly linked into the final binary. Verify this by
        # grepping the linker arguments.
-       $(RUSTC) main.rs -C lto -Z print-link-args | $(CGREP) 'libno_builtins.rlib'
+       $(RUSTC) main.rs -C lto --print link-args | $(CGREP) 'libno_builtins.rlib'
index 8468d102bec8312a276df6de130368ef4d492891..e09841fb42e1876ae337328568d6994a20ac0e33 100644 (file)
@@ -16,7 +16,7 @@ RUSTC_FLAGS = \
     -l foo \
     -l static=baz \
     -l foo \
-    -Z print-link-args
+    --print link-args
 
 all: $(call DYLIB,foo) $(call STATICLIB,bar) $(call STATICLIB,baz)
        $(RUSTC) $(RUSTC_FLAGS) main.rs
index abc32d4423b05a8ffb01d12977c78592a8ffd394..8f78c401a11415fe9b4665d9117187b77734adb3 100644 (file)
@@ -13,9 +13,9 @@ all: $(call NATIVE_STATICLIB,aaa)
        nm $(TMPDIR)/libbbb.rlib | $(CGREP) -e "U _*native_func"
 
        # Check that aaa gets linked (either as `-l aaa` or `aaa.lib`) when building ccc.
-       $(RUSTC) ccc.rs -C prefer-dynamic --crate-type=dylib -Z print-link-args | $(CGREP) -e '-l[" ]*aaa|aaa\.lib'
+       $(RUSTC) ccc.rs -C prefer-dynamic --crate-type=dylib --print link-args | $(CGREP) -e '-l[" ]*aaa|aaa\.lib'
 
        # Check that aaa does NOT get linked when building ddd.
-       $(RUSTC) ddd.rs -Z print-link-args | $(CGREP) -ve '-l[" ]*aaa|aaa\.lib'
+       $(RUSTC) ddd.rs --print link-args | $(CGREP) -ve '-l[" ]*aaa|aaa\.lib'
 
        $(call RUN,ddd)
index 26ab4d34764d136dbe3aa93abead4aaac097398b..166305672e6f229790c35292ad5f39d221aa9f5f 100644 (file)
@@ -1,14 +1,19 @@
 # Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc
 
-# only-windows-msvc
+# only-windows
 
 -include ../../run-make-fulldeps/tools.mk
 
 all:
        $(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
        $(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
+ifdef IS_MSVC
        $(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll
        $(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll
+else
+       $(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
+       $(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
+endif
        $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
        $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
        "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
index 04b257d063204d6c044d3f71c7ff53529fde583e..0e84a749b05782151ae4008333b319947ba56421 100644 (file)
@@ -1,12 +1,16 @@
 # Test the behavior of #[link(.., kind = "raw-dylib")] and #[link_ordinal] on windows-msvc
 
-# only-windows-msvc
+# only-windows
 
 -include ../../run-make-fulldeps/tools.mk
 
 all:
        $(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
+ifdef IS_MSVC
        $(CC) "$(TMPDIR)"/exporter.obj exporter.def -link -dll -out:"$(TMPDIR)"/exporter.dll
+else
+       $(CC) "$(TMPDIR)"/exporter.obj exporter.def -shared -o "$(TMPDIR)"/exporter.dll
+endif
        $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
        $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
        "$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile b/src/test/run-make/raw-dylib-stdcall-ordinal/Makefile
new file mode 100644 (file)
index 0000000..69f6266
--- /dev/null
@@ -0,0 +1,23 @@
+# Test the behavior of #[link(.., kind = "raw-dylib")], #[link_ordinal], and alternative calling conventions on i686 windows.
+
+# only-x86
+# only-windows
+
+-include ../../run-make-fulldeps/tools.mk
+
+all:
+       $(call COMPILE_OBJ,"$(TMPDIR)"/exporter.obj,exporter.c)
+ifdef IS_MSVC
+       $(CC) "$(TMPDIR)"/exporter.obj exporter-msvc.def -link -dll -out:"$(TMPDIR)"/exporter.dll
+else
+       $(CC) "$(TMPDIR)"/exporter.obj exporter-gnu.def -shared -o "$(TMPDIR)"/exporter.dll
+endif
+       $(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
+       $(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
+       "$(TMPDIR)"/driver > "$(TMPDIR)"/actual_output.txt
+
+ifdef RUSTC_BLESS_TEST
+       cp "$(TMPDIR)"/actual_output.txt expected_output.txt
+else
+       $(DIFF) expected_output.txt "$(TMPDIR)"/actual_output.txt
+endif
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/driver.rs b/src/test/run-make/raw-dylib-stdcall-ordinal/driver.rs
new file mode 100644 (file)
index 0000000..4059ede
--- /dev/null
@@ -0,0 +1,5 @@
+extern crate raw_dylib_test;
+
+fn main() {
+    raw_dylib_test::library_function();
+}
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/expected_output.txt b/src/test/run-make/raw-dylib-stdcall-ordinal/expected_output.txt
new file mode 100644 (file)
index 0000000..2015776
--- /dev/null
@@ -0,0 +1,2 @@
+exported_function_stdcall(6)
+exported_function_fastcall(125)
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/exporter-gnu.def b/src/test/run-make/raw-dylib-stdcall-ordinal/exporter-gnu.def
new file mode 100644 (file)
index 0000000..8d28d71
--- /dev/null
@@ -0,0 +1,4 @@
+LIBRARY exporter
+EXPORTS
+    exported_function_stdcall@4 @15 NONAME
+    @exported_function_fastcall@4 @18 NONAME
\ No newline at end of file
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/exporter-msvc.def b/src/test/run-make/raw-dylib-stdcall-ordinal/exporter-msvc.def
new file mode 100644 (file)
index 0000000..5a4c79a
--- /dev/null
@@ -0,0 +1,4 @@
+LIBRARY exporter
+EXPORTS
+    _exported_function_stdcall@4 @15 NONAME
+    @exported_function_fastcall@4 @18 NONAME
\ No newline at end of file
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/exporter.c b/src/test/run-make/raw-dylib-stdcall-ordinal/exporter.c
new file mode 100644 (file)
index 0000000..1fb45bf
--- /dev/null
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+void __stdcall exported_function_stdcall(int i) {
+    printf("exported_function_stdcall(%d)\n", i);
+    fflush(stdout);
+}
+
+void __fastcall exported_function_fastcall(int i) {
+    printf("exported_function_fastcall(%d)\n", i);
+    fflush(stdout);
+}
diff --git a/src/test/run-make/raw-dylib-stdcall-ordinal/lib.rs b/src/test/run-make/raw-dylib-stdcall-ordinal/lib.rs
new file mode 100644 (file)
index 0000000..07dd3d7
--- /dev/null
@@ -0,0 +1,20 @@
+#![feature(raw_dylib)]
+
+#[link(name = "exporter", kind = "raw-dylib")]
+extern "stdcall" {
+    #[link_ordinal(15)]
+    fn imported_function_stdcall(i: i32);
+}
+
+#[link(name = "exporter", kind = "raw-dylib")]
+extern "fastcall" {
+    #[link_ordinal(18)]
+    fn imported_function_fastcall(i: i32);
+}
+
+pub fn library_function() {
+    unsafe {
+        imported_function_stdcall(6);
+        imported_function_fastcall(125);
+    }
+}
index ca60be72cea468a6626d13b34d03f546deca3cc0..2d48d21dc1b05da4e2d5571af6af732c40519fbc 100644 (file)
@@ -13,12 +13,14 @@ 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)"})
 
-assert-css: (".sidebar a", {"color": "rgb(0, 0, 0)"})
+assert-css: (".sidebar a", {"color": "rgb(56, 115, 173)"})
 assert-css: (".in-band a", {"color": "rgb(0, 0, 0)"})
 
 // We move the cursor over the "Implementations" title so the anchor is displayed.
index ee4dad444e93219861026e24eb4ed7cabd970b44..f93f3f0aefc51e9ad30e7969a9f63ba39292ea09 100644 (file)
@@ -5,4 +5,4 @@ size: (1080, 600)
 assert-count: (".docblock > .example-wrap", 2)
 assert: ".docblock > .example-wrap > .language-txt"
 assert: ".docblock > .example-wrap > .rust-example-rendered"
-assert-css: (".docblock > .example-wrap > pre", {"width": "796px", "overflow-x": "auto"}, ALL)
+assert-css: (".docblock > .example-wrap > pre", {"width": "785.25px", "overflow-x": "auto"}, ALL)
index 1b3006155d8b632a7c9314667a0011d6378a4fa4..a9af88189a67de78bcee02314831f56d355ebbab 100644 (file)
@@ -4,7 +4,7 @@ goto: file://|DOC_PATH|/lib2/long_table/struct.Foo.html
 size: (1100, 800)
 // Logically, the ".docblock" and the "<p>" should have the same scroll width.
 compare-elements-property: (".top-doc .docblock", ".top-doc .docblock > p", ["scrollWidth"])
-assert-property: (".top-doc .docblock", {"scrollWidth": "816"})
+assert-property: (".top-doc .docblock", {"scrollWidth": "801"})
 // However, since there is overflow in the <table>, its scroll width is bigger.
 assert-property: (".top-doc .docblock table", {"scrollWidth": "1573"})
 
@@ -16,6 +16,6 @@ compare-elements-property: (
     "#implementations + details .docblock > p",
     ["scrollWidth"],
 )
-assert-property: ("#implementations + details .docblock", {"scrollWidth": "816"})
+assert-property: ("#implementations + details .docblock", {"scrollWidth": "801"})
 // However, since there is overflow in the <table>, its scroll width is bigger.
 assert-property: ("#implementations + details .docblock table", {"scrollWidth": "1573"})
index 87c512468e05fd9a1dcfd0fdc5a91028c8933c2a..48e0156f1b81b8ee7789e05138d4563efc9107a7 100644 (file)
@@ -15,7 +15,6 @@
 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: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -55,7 +54,6 @@ 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: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -110,12 +108,11 @@ assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"font-size": "15.2px"
 assert-css: ("h6#sub-sub-heading-for-enum-impl-item-doc", {"border-bottom-width": "0px"})
 
 assert-text: (".sidebar .others h3", "Modules")
-assert-css: (".sidebar .others h3", {"border-bottom-width": "1px"}, ALL)
+assert-css: (".sidebar .others h3", {"border-bottom-width": "0px"}, 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: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
@@ -148,9 +145,21 @@ 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: ("h2#top-doc-prose-title", {"font-size": "20.8px"})
 assert-css: ("h2#top-doc-prose-title", {"border-bottom-width": "1px"})
 assert-css: ("h3#top-doc-prose-sub-heading", {"font-size": "18.4px"})
 assert-css: ("h3#top-doc-prose-sub-heading", {"border-bottom-width": "1px"})
+
+goto: file://|DOC_PATH|/staged_api/struct.Foo.html
+show-text: true
+local-storage: {"rustdoc-theme": "light", "rustdoc-use-system-theme": "false"}
+assert-css: (".since", {"color": "rgb(128, 128, 128)"})
+
+local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"}
+reload:
+assert-css: (".since", {"color": "rgb(128, 128, 128)"})
+
+local-storage: {"rustdoc-theme": "ayu", "rustdoc-use-system-theme": "false"}
+reload:
+assert-css: (".since", {"color": "rgb(128, 128, 128)"})
index cdc00d341140332246dc0e3355472dc3bb45a651..acb30141ce577c9ff693714a14e7c2b4921adb4a 100644 (file)
@@ -3,5 +3,5 @@ goto: file://|DOC_PATH|/lib2/struct.Foo.html
 // We set a fixed size so there is no chance of "random" resize.
 size: (1100, 800)
 // We check that ".item-info" is bigger than its content.
-assert-css: (".item-info", {"width": "807px"})
+assert-css: (".item-info", {"width": "757px"})
 assert-css: (".item-info .stab", {"width": "341px"})
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 ea94e5640fbd1bcb5ccbe09ee28ea00318440f0b..3162a067d2107f8c16b7f2aa41552c9e82448808 100644 (file)
@@ -5,7 +5,7 @@ write: (".search-input", "test")
 wait-for: "#titles"
 // The width is returned by "getComputedStyle" which returns the exact number instead of the
 // CSS rule which is "50%"...
-assert-css: (".search-results div.desc", {"width": "320px"})
+assert-css: (".search-results div.desc", {"width": "295px"})
 size: (600, 100)
 // As counter-intuitive as it may seem, in this width, the width is "100%", which is why
 // when computed it's larger.
index 7138f91667573bcda4ae8c425139a603cfb6af70..547eb3fd1b3d107e63cfa1d864ddf3d2a1b73585 100644 (file)
@@ -4,17 +4,28 @@
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
 // Switching to "mobile view" by reducing the width to 600px.
 size: (600, 600)
-assert-css: (".sidebar-elems", {"display": "block", "left": "-246px"})
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 // Opening the sidebar menu.
-click: ".sidebar-menu"
-assert-css: (".sidebar-elems", {"display": "block", "left": "0px"})
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"display": "block", "left": "0px"})
 // Closing the sidebar menu.
-click: ".sidebar-menu"
-assert-css: (".sidebar-elems", {"display": "block", "left": "-246px"})
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
 // Force the sidebar open by focusing a link inside it.
 // This makes it easier for keyboard users to get to it.
 focus: ".sidebar-title a"
-assert-css: (".sidebar-elems", {"display": "block", "left": "0px"})
+assert-css: (".sidebar", {"display": "block", "left": "0px"})
 // When we tab out of the sidebar, close it.
 focus: ".search-input"
-assert-css: (".sidebar-elems", {"display": "block", "left": "-246px"})
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+assert-css: (".sidebar", {"left": "0px"})
+
+// Click elsewhere.
+click: "body"
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
+
+// Check that the topbar is visible
+assert-property: (".mobile-topbar", {"clientHeight": "45"})
index 98f4fdf4233c28e1e085f58631e9153dbed6e82a..1c5eb9239ba8bba6468a73153205a0e4d10a8513 100644 (file)
@@ -10,6 +10,7 @@ click: (10, 10)
 // We wait for the sidebar to be expanded (there is a 0.5s animation).
 wait-for: 600
 assert-css: ("nav.sidebar.expanded", {"width": "300px"})
+assert-css: ("nav.sidebar.expanded a", {"font-size": "14.4px"})
 // We collapse the sidebar.
 click: (10, 10)
 // We wait for the sidebar to be collapsed (there is a 0.5s animation).
@@ -30,3 +31,6 @@ click: (10, 10)
 // We ensure that the class has been removed.
 assert-false: "nav.sidebar.expanded"
 assert: "nav.sidebar"
+
+// Check that the topbar is not visible
+assert-property: (".mobile-topbar", {"offsetParent": "null"})
index f9c707f81e79c8022c510a1f183d74f2f92cd5f6..a1175525858200b390f243e3e1d5399dec222256 100644 (file)
@@ -1,8 +1,14 @@
 goto: file://|DOC_PATH|/test_docs/index.html
+show-text: true
+local-storage: {"rustdoc-theme": "light"}
+// We reload the page so the local storage settings are being used.
+reload:
+
 assert-text: (".sidebar > .location", "Crate test_docs")
 // In modules, we only have one "location" element.
 assert-count: (".sidebar .location", 1)
-assert-text: (".sidebar-elems > #all-types", "See all test_docs's items")
+assert-text: ("#all-types", "All Items")
+assert-css: ("#all-types", {"color": "rgb(56, 115, 173)"})
 // We check that we have the crates list and that the "current" on is "test_docs".
 assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs")
 // And we're also supposed to have the list of items in the current module.
@@ -22,8 +28,16 @@ click: "#structs + .item-table .item-left > a"
 assert-count: (".sidebar .location", 2)
 // We check that there is no crate listed outside of the top level.
 assert-false: ".sidebar-elems > .crate"
+
+click: ".sidebar-links a"
+assert-property-false: ("html", {"scrollTop": "0"})
+
+click: ".sidebar h2.location a"
+assert-property: ("html", {"scrollTop": "0"})
+
 // We now go back to the crate page to click on the "lib2" crate link.
 goto: file://|DOC_PATH|/test_docs/index.html
+assert-css: (".sidebar-elems .crate > ul > li:first-child > a", {"color": "rgb(56, 115, 173)"})
 click: ".sidebar-elems .crate > ul > li:first-child > a"
 
 // PAGE: lib2/index.html
@@ -44,8 +58,7 @@ click: "#functions + .item-table .item-left > a"
 // In items containing no items (like functions or constants) and in modules, we have one
 // "location" elements.
 assert-count: (".sidebar .location", 1)
-// There is a "<br>" tag between "in" and "lib2", but it doesn't count as a space.
-assert-text: (".sidebar .sidebar-elems .location", "Other items inlib2")
+assert-text: (".sidebar .sidebar-elems .location", "In lib2")
 // We check that we don't have the crate list.
 assert-false: ".sidebar-elems > .crate"
 
diff --git a/src/test/rustdoc-gui/src/staged_api/Cargo.lock b/src/test/rustdoc-gui/src/staged_api/Cargo.lock
new file mode 100644 (file)
index 0000000..6e8eba5
--- /dev/null
@@ -0,0 +1,7 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "staged_api"
+version = "0.1.0"
diff --git a/src/test/rustdoc-gui/src/staged_api/Cargo.toml b/src/test/rustdoc-gui/src/staged_api/Cargo.toml
new file mode 100644 (file)
index 0000000..117c413
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name = "staged_api"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+path = "lib.rs"
+
+[features]
+default = ["some_feature"]
+some_feature = []
diff --git a/src/test/rustdoc-gui/src/staged_api/lib.rs b/src/test/rustdoc-gui/src/staged_api/lib.rs
new file mode 100644 (file)
index 0000000..0cb460f
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(staged_api)]
+#![stable(feature = "some_feature", since = "1.3.5")]
+
+#[stable(feature = "some_feature", since = "1.3.5")]
+pub struct Foo {}
+
+impl Foo {
+    #[stable(feature = "some_feature", since = "1.3.5")]
+    pub fn bar() {}
+}
index 6e0ad8e0fa7fbcc48020e4bea2b82ae8ac393137..4c83fd6c0e31c5ef9161127a8a1865b60b2be1be 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, 240) // This is the position of the top doc comment toggle
+click: (4, 250) // This is the position of the top doc comment toggle
 assert-attribute-false: (".top-doc", {"open": ""})
-click: (4, 240)
+click: (4, 250)
 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, 240)
+click: (3, 250)
 assert-attribute: (".top-doc", {"open": ""})
 
 // Assert the position of the toggle on the top doc block.
@@ -22,10 +22,10 @@ assert-position: (
 // Now we do the same but with a little bigger width
 size: (600, 600)
 assert-attribute: (".top-doc", {"open": ""})
-click: (4, 240) // New Y position since all search elements are back on one line.
+click: (4, 250) // New Y position since all search elements are back on one line.
 assert-attribute-false: (".top-doc", {"open": ""})
-click: (4, 240)
+click: (4, 250)
 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, 240)
+click: (3, 250)
 assert-attribute: (".top-doc", {"open": ""})
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 bb24d0ce792545ad8d1a9ffd3d01286782e958f2..21874f786f1ad17cc81564f5e6cfa960fcad1965 100644 (file)
@@ -11,7 +11,7 @@ assert-property: (".item-decl pre", {"scrollWidth": "1324"})
 goto: file://|DOC_PATH|/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html
 assert-property: ("body", {"scrollWidth": "1100"})
 // We now check that the section width hasn't grown because of it.
-assert-property: ("#main-content", {"scrollWidth": "840"})
+assert-property: ("#main-content", {"scrollWidth": "825"})
 // And now checking that it has scrollable content.
 assert-property: (".item-decl pre", {"scrollWidth": "1103"})
 
@@ -20,6 +20,13 @@ assert-property: (".item-decl pre", {"scrollWidth": "1103"})
 goto: file://|DOC_PATH|/lib2/too_long/constant.ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong.html
 assert-property: ("body", {"scrollWidth": "1100"})
 // We now check that the section width hasn't grown because of it.
-assert-property: ("#main-content", {"scrollWidth": "840"})
+assert-property: ("#main-content", {"scrollWidth": "825"})
 // And now checking that it has scrollable content.
 assert-property: (".item-decl pre", {"scrollWidth": "950"})
+
+// On mobile:
+size: (600, 600)
+goto: file://|DOC_PATH|/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html
+assert-property: (".mobile-topbar .location", {"scrollWidth": "504"})
+assert-property: (".mobile-topbar .location", {"clientWidth": "504"})
+assert-css: (".mobile-topbar .location", {"overflow-x": "hidden"})
index 142008cf76508f5acddc1b6743a2c398a5428b8a..2d66566119bc3027accb42f24cf09c473ebd14bd 100644 (file)
@@ -73,4 +73,9 @@ trait T {}
 //~^ ERROR incompatible link kind for `f`
 //~| NOTE this link resolved
 //~| HELP add parentheses
+
+/// Link to [fn@std]
+//~^ ERROR unresolved link to `std`
+//~| NOTE this link resolves to the crate `std`
+//~| HELP to link to the crate, prefix with `mod@`
 pub fn f() {}
index 12122f5fa867431a9bb51a863eedd37ee689bd3b..ad9102c506f7fb792dc291b64071b9c3ff43da63 100644 (file)
@@ -138,5 +138,16 @@ LL - /// Link to [const@f]
 LL + /// Link to [f()]
    | 
 
-error: aborting due to 12 previous errors
+error: unresolved link to `std`
+  --> $DIR/disambiguator-mismatch.rs:77:14
+   |
+LL | /// Link to [fn@std]
+   |              ^^^^^^ this link resolves to the crate `std`, which is not in the value namespace
+   |
+help: to link to the crate, prefix with `mod@`
+   |
+LL | /// Link to [mod@std]
+   |              ~~~~
+
+error: aborting due to 13 previous errors
 
index 15910e1e9006d1e8ff738a7c8814ecda10c483c1..08a35339680cd91b76502fc894b5538e2d90e5b5 100644 (file)
@@ -3,7 +3,7 @@
 // therefore should not concern itself with the lints.
 #[deny(warnings)]
 
-// @has cap_lints/struct.Foo.html //* 'Struct Foo'
+// @has cap_lints/struct.Foo.html //* 'Foo'
 pub struct Foo {
     field: i32,
 }
index fb8ea7e33c28ce2f419bd60d7eee6ca6b770616d..b8e101038f8f11b4ba74c1f8f97c7aabd148807d 100644 (file)
@@ -67,3 +67,20 @@ pub const fn gated() -> u32 { 42 }
     #[rustc_const_stable(feature = "rust1", since = "1.2.0")]
     pub const fn stable_impl() -> u32 { 42 }
 }
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Bar;
+
+impl Bar {
+    // Do not show non-const stabilities that are the same as the enclosing item.
+    // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.2.0$'
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "rust1", since = "1.2.0")]
+    pub const fn stable_impl() -> u32 { 42 }
+
+    // Show const-stability even for unstable functions.
+    // @matches 'foo/struct.Bar.html' '//span[@class="since"]' '^const: 1.3.0$'
+    #[unstable(feature = "foo2", issue = "none")]
+    #[rustc_const_stable(feature = "rust1", since = "1.3.0")]
+    pub const fn const_stable_unstable() -> u32 { 42 }
+}
index 2f91eea339b39afd6133b2aff753751717f90bb2..8413709f15e909af3052fc62aec17d6e9b616e82 100644 (file)
@@ -2,5 +2,4 @@
 
 #![crate_name = "foo"]
 
-// @has 'foo/index.html' '//div[@class="block version"]/p' 'Version <script>alert("hi")</script>'
-// @has 'foo/all.html' '//div[@class="block version"]/p' 'Version <script>alert("hi")</script>'
+// @has 'foo/index.html' '//li[@class="version"]' 'Version <script>alert("hi")</script>'
index 893af5c61332d1009dc471ab4f8f33c7b24e976e..2592c98530fe44e0292def4385de24f7aa30e967 100644 (file)
@@ -1,3 +1,3 @@
 // compile-flags: --crate-version=1.3.37
 
-// @has 'crate_version/index.html' '//div[@class="block version"]/p' 'Version 1.3.37'
+// @has 'crate_version/index.html' '//*[@class="version"]' 'Version 1.3.37'
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 ca51f3c7b5af08677677f4b4123fde0b75462de4..8ecca6d12d24af01bd4c61fe58a422a97bd9e607 100644 (file)
@@ -13,7 +13,7 @@
 
 impl Bar {
     // @has - '//*[@id="method.len"]' 'pub const fn len(&self) -> usize'
-    // @has - '//*[@id="method.len"]//span[@class="since"]' '1.0.0 (const: 1.0.0)'
+    // @has - '//*[@id="method.len"]//span[@class="since"]' 'const: 1.0.0'
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
     pub const fn len(&self) -> usize { 0 }
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!();
index f37ae62dde1aa45076563fe149bdbb9fc323dc06..ab088ab789d43b15d886cd3ec7a4402deb84e5e7 100644 (file)
@@ -4,14 +4,34 @@
     pub type ExternType;
 }
 
+pub trait T {
+    fn test(&self) {}
+}
+
+pub trait G<N> {
+    fn g(&self, n: N) {}
+}
+
 impl ExternType {
-    pub fn f(&self) {
+    pub fn f(&self) {}
+}
 
-    }
+impl T for ExternType {
+    fn test(&self) {}
+}
+
+impl G<usize> for ExternType {
+    fn g(&self, n: usize) {}
 }
 
 // @has 'extern_type/foreigntype.ExternType.html'
 // @has 'extern_type/fn.links_to_extern_type.html' \
 // 'href="foreigntype.ExternType.html#method.f"'
+// @has 'extern_type/fn.links_to_extern_type.html' \
+// 'href="foreigntype.ExternType.html#method.test"'
+// @has 'extern_type/fn.links_to_extern_type.html' \
+// 'href="foreigntype.ExternType.html#method.g"'
 /// See also [ExternType::f]
+/// See also [ExternType::test]
+/// See also [ExternType::g]
 pub fn links_to_extern_type() {}
diff --git a/src/test/rustdoc/intra-doc/generic-trait-impl.rs b/src/test/rustdoc/intra-doc/generic-trait-impl.rs
new file mode 100644 (file)
index 0000000..ba8595a
--- /dev/null
@@ -0,0 +1,20 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// Test intra-doc links on trait implementations with generics
+// regression test for issue #92662
+
+use std::marker::PhantomData;
+
+pub trait Bar<T> {
+    fn bar(&self);
+}
+
+pub struct Foo<U>(PhantomData<U>);
+
+impl<T, U> Bar<T> for Foo<U> {
+    fn bar(&self) {}
+}
+
+// @has generic_trait_impl/fn.main.html '//a[@href="struct.Foo.html#method.bar"]' 'Foo::bar'
+/// link to [`Foo::bar`]
+pub fn main() {}
diff --git a/src/test/rustdoc/intra-doc/prim-self.rs b/src/test/rustdoc/intra-doc/prim-self.rs
new file mode 100644 (file)
index 0000000..7a65723
--- /dev/null
@@ -0,0 +1,37 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![allow(incomplete_features)] // inherent_associated_types
+#![feature(lang_items)]
+#![feature(no_core)]
+#![feature(rustdoc_internals)]
+#![feature(inherent_associated_types)]
+#![no_core]
+
+#[lang = "usize"]
+/// [Self::f]
+/// [Self::MAX]
+// @has prim_self/primitive.usize.html
+// @has - '//a[@href="primitive.usize.html#method.f"]' 'Self::f'
+// @has - '//a[@href="primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
+impl usize {
+    /// Some docs
+    pub fn f() {}
+
+    /// 10 and 2^32 are basically the same.
+    pub const MAX: usize = 10;
+
+    // @has - '//a[@href="primitive.usize.html#associatedtype.ME"]' 'Self::ME'
+    /// [Self::ME]
+    pub type ME = usize;
+}
+
+#[doc(primitive = "usize")]
+/// This has some docs.
+mod usize {}
+
+/// [S::f]
+/// [Self::f]
+pub struct S;
+
+impl S {
+    pub fn f() {}
+}
diff --git a/src/test/rustdoc/intra-doc/self-cache.rs b/src/test/rustdoc/intra-doc/self-cache.rs
new file mode 100644 (file)
index 0000000..63bf7fa
--- /dev/null
@@ -0,0 +1,14 @@
+#![crate_name = "foo"]
+// @has foo/enum.E1.html '//a/@href' 'enum.E1.html#variant.A'
+
+/// [Self::A::b]
+pub enum E1 {
+    A { b: usize }
+}
+
+// @has foo/enum.E2.html '//a/@href' 'enum.E2.html#variant.A'
+
+/// [Self::A::b]
+pub enum E2 {
+    A { b: usize }
+}
diff --git a/src/test/rustdoc/intra-link-prim-self.rs b/src/test/rustdoc/intra-link-prim-self.rs
deleted file mode 100644 (file)
index 8a564ac..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#![deny(rustdoc::broken_intra_doc_links)]
-#![feature(lang_items)]
-#![feature(no_core)]
-#![feature(rustdoc_internals)]
-#![no_core]
-
-#[lang = "usize"]
-/// [Self::f]
-/// [Self::MAX]
-// @has intra_link_prim_self/primitive.usize.html
-// @has - '//a[@href="primitive.usize.html#method.f"]' 'Self::f'
-// @has - '//a[@href="primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
-impl usize {
-    /// Some docs
-    pub fn f() {}
-
-    /// 10 and 2^32 are basically the same.
-    pub const MAX: usize = 10;
-
-    // FIXME(#8995) uncomment this when associated types in inherent impls are supported
-    // @ has - '//a[@href="{{channel}}/std/primitive.usize.html#associatedtype.ME"]' 'Self::ME'
-    // / [Self::ME]
-    //pub type ME = usize;
-}
-
-#[doc(primitive = "usize")]
-/// This has some docs.
-mod usize {}
-
-/// [S::f]
-/// [Self::f]
-pub struct S;
-
-impl S {
-    pub fn f() {}
-}
diff --git a/src/test/rustdoc/intra-link-self-cache.rs b/src/test/rustdoc/intra-link-self-cache.rs
deleted file mode 100644 (file)
index 63bf7fa..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#![crate_name = "foo"]
-// @has foo/enum.E1.html '//a/@href' 'enum.E1.html#variant.A'
-
-/// [Self::A::b]
-pub enum E1 {
-    A { b: usize }
-}
-
-// @has foo/enum.E2.html '//a/@href' 'enum.E2.html#variant.A'
-
-/// [Self::A::b]
-pub enum E2 {
-    A { b: usize }
-}
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;
diff --git a/src/test/rustdoc/source-version-separator.rs b/src/test/rustdoc/source-version-separator.rs
new file mode 100644 (file)
index 0000000..45a555e
--- /dev/null
@@ -0,0 +1,31 @@
+#![stable(feature = "bar", since = "1.0")]
+#![crate_name = "foo"]
+
+#![feature(staged_api)]
+
+// @has foo/trait.Bar.html
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0· source · '
+#[stable(feature = "bar", since = "1.0")]
+pub trait Bar {
+    // @has - '//div[@id="tymethod.foo"]/*[@class="rightside"]' '3.0 · source'
+    #[stable(feature = "foobar", since = "3.0")]
+    fn foo();
+}
+
+// @has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0 · source'
+
+// @has foo/struct.Foo.html
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0· source · '
+#[stable(feature = "baz", since = "1.0")]
+pub struct Foo;
+
+impl Foo {
+    // @has - '//div[@id="method.foofoo"]/*[@class="rightside"]' '3.0 · source'
+    #[stable(feature = "foobar", since = "3.0")]
+    pub fn foofoo() {}
+}
+
+#[stable(feature = "yolo", since = "4.0")]
+impl Bar for Foo {
+    fn foo() {}
+}
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 016ec7bfaa307225b1d403993ad3d42a63875ea2..69e8b856b0a26142cbf6461a5b336f35f42eefe5 100644 (file)
@@ -1,10 +1,11 @@
 #![crate_name = "foo"]
-
 #![feature(rustdoc_internals)]
 
 // @matches 'foo/index.html' '//h1' 'Crate foo'
+// @matches 'foo/index.html' '//h2[@class="location"]' 'Crate foo'
 
 // @matches 'foo/foo_mod/index.html' '//h1' 'Module foo::foo_mod'
+// @matches 'foo/foo_mod/index.html' '//h2[@class="location"]' 'Module foo_mod'
 pub mod foo_mod {
     pub struct __Thing {}
 }
@@ -18,15 +19,19 @@ pub struct __Thing {}
 pub fn foo_fn() {}
 
 // @matches 'foo/trait.FooTrait.html' '//h1' 'Trait foo::FooTrait'
+// @matches 'foo/trait.FooTrait.html' '//h2[@class="location"]' 'FooTrait'
 pub trait FooTrait {}
 
 // @matches 'foo/struct.FooStruct.html' '//h1' 'Struct foo::FooStruct'
+// @matches 'foo/struct.FooStruct.html' '//h2[@class="location"]' 'FooStruct'
 pub struct FooStruct;
 
 // @matches 'foo/enum.FooEnum.html' '//h1' 'Enum foo::FooEnum'
+// @matches 'foo/enum.FooEnum.html' '//h2[@class="location"]' 'FooEnum'
 pub enum FooEnum {}
 
 // @matches 'foo/type.FooType.html' '//h1' 'Type Definition foo::FooType'
+// @matches 'foo/type.FooType.html' '//h2[@class="location"]' 'FooType'
 pub type FooType = FooStruct;
 
 // @matches 'foo/macro.foo_macro.html' '//h1' 'Macro foo::foo_macro'
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 1fb28ee99702f7dc2eae764330cd0f291293c26c..4ecd62cded22e9a22c56ff6c0356978b483002ed 100644 (file)
@@ -12,7 +12,7 @@ pub fn method_on_mystruct() {}
 // @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyAlias'
 // @has - '//*[@class="impl has-srclink"]//h3[@class="code-header in-band"]' 'impl MyTrait for MyAlias'
 // @has - 'Alias docstring'
-// @has - '//*[@class="sidebar"]//*[@class="location"]' 'Type Definition MyAlias'
+// @has - '//*[@class="sidebar"]//*[@class="location"]' 'MyAlias'
 // @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods'
 // @has - '//*[@class="sidebar"]//a[@href="#trait-implementations"]' 'Trait Implementations'
 /// Alias docstring
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,
 }
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");
diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.rs
deleted file mode 100644 (file)
index e0fdbae..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// compile-flags: -Z unstable-options
-
-#![feature(rustc_private)]
-#![deny(rustc::ty_pass_by_reference)]
-#![allow(unused)]
-
-extern crate rustc_middle;
-
-use rustc_middle::ty::{Ty, TyCtxt};
-
-fn ty_by_ref(
-    ty_val: Ty<'_>,
-    ty_ref: &Ty<'_>, //~ ERROR passing `Ty<'_>` by reference
-    ty_ctxt_val: TyCtxt<'_>,
-    ty_ctxt_ref: &TyCtxt<'_>, //~ ERROR passing `TyCtxt<'_>` by reference
-) {
-}
-
-fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
-//~^ ERROR passing `Ty<'_>` by reference
-//~^^ ERROR passing `TyCtxt<'_>` by reference
-
-trait T {
-    fn ty_by_ref_in_trait(
-        ty_val: Ty<'_>,
-        ty_ref: &Ty<'_>, //~ ERROR passing `Ty<'_>` by reference
-        ty_ctxt_val: TyCtxt<'_>,
-        ty_ctxt_ref: &TyCtxt<'_>, //~ ERROR passing `TyCtxt<'_>` by reference
-    );
-
-    fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
-    //~^ ERROR passing `Ty<'_>` by reference
-    //~^^ ERROR passing `TyCtxt<'_>` by reference
-}
-
-struct Foo;
-
-impl T for Foo {
-    fn ty_by_ref_in_trait(
-        ty_val: Ty<'_>,
-        ty_ref: &Ty<'_>,
-        ty_ctxt_val: TyCtxt<'_>,
-        ty_ctxt_ref: &TyCtxt<'_>,
-    ) {
-    }
-
-    fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
-}
-
-impl Foo {
-    fn ty_by_ref_assoc(
-        ty_val: Ty<'_>,
-        ty_ref: &Ty<'_>, //~ ERROR passing `Ty<'_>` by reference
-        ty_ctxt_val: TyCtxt<'_>,
-        ty_ctxt_ref: &TyCtxt<'_>, //~ ERROR passing `TyCtxt<'_>` by reference
-    ) {
-    }
-
-    fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
-    //~^ ERROR passing `Ty<'_>` by reference
-    //~^^ ERROR passing `TyCtxt<'_>` by reference
-}
-
-fn main() {}
diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref.stderr
deleted file mode 100644 (file)
index 2751a37..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:13:13
-   |
-LL |     ty_ref: &Ty<'_>,
-   |             ^^^^^^^ help: try passing by value: `Ty<'_>`
-   |
-note: the lint level is defined here
-  --> $DIR/pass_ty_by_ref.rs:4:9
-   |
-LL | #![deny(rustc::ty_pass_by_reference)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:15:18
-   |
-LL |     ty_ctxt_ref: &TyCtxt<'_>,
-   |                  ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:19:28
-   |
-LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
-   |                            ^^^^^^^ help: try passing by value: `Ty<'_>`
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:19:55
-   |
-LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
-   |                                                       ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:26:17
-   |
-LL |         ty_ref: &Ty<'_>,
-   |                 ^^^^^^^ help: try passing by value: `Ty<'_>`
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:28:22
-   |
-LL |         ty_ctxt_ref: &TyCtxt<'_>,
-   |                      ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:31:41
-   |
-LL |     fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
-   |                                         ^^^^^^^ help: try passing by value: `Ty<'_>`
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:31:68
-   |
-LL |     fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
-   |                                                                    ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:53:17
-   |
-LL |         ty_ref: &Ty<'_>,
-   |                 ^^^^^^^ help: try passing by value: `Ty<'_>`
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:55:22
-   |
-LL |         ty_ctxt_ref: &TyCtxt<'_>,
-   |                      ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: passing `Ty<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:59:38
-   |
-LL |     fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
-   |                                      ^^^^^^^ help: try passing by value: `Ty<'_>`
-
-error: passing `TyCtxt<'_>` by reference
-  --> $DIR/pass_ty_by_ref.rs:59:65
-   |
-LL |     fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
-   |                                                                 ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
-
-error: aborting due to 12 previous errors
-
diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs
deleted file mode 100644 (file)
index 48b140d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// compile-flags: -Z unstable-options
-// NOTE: This test doesn't actually require `fulldeps`
-// so we could instead use it as a `ui` test.
-//
-// Considering that all other `internal-lints` are tested here
-// this seems like the cleaner solution though.
-#![feature(rustc_attrs)]
-#![deny(rustc::ty_pass_by_reference)]
-#![allow(unused)]
-
-#[rustc_diagnostic_item = "TyCtxt"]
-struct TyCtxt<'tcx> {
-    inner: &'tcx (),
-}
-
-impl<'tcx> TyCtxt<'tcx> {
-    fn by_value(self) {} // OK
-    fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference
-}
-
-
-struct TyS<'tcx> {
-    inner: &'tcx (),
-}
-
-#[rustc_diagnostic_item = "Ty"]
-type Ty<'tcx> = &'tcx TyS<'tcx>;
-
-impl<'tcx> TyS<'tcx> {
-    fn by_value(self: Ty<'tcx>) {}
-    fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference
-}
-
-fn main() {}
diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr
deleted file mode 100644 (file)
index 15a06e7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: passing `TyCtxt<'tcx>` by reference
-  --> $DIR/pass_ty_by_ref_self.rs:18:15
-   |
-LL |     fn by_ref(&self) {}
-   |               ^^^^^ help: try passing by value: `TyCtxt<'tcx>`
-   |
-note: the lint level is defined here
-  --> $DIR/pass_ty_by_ref_self.rs:8:9
-   |
-LL | #![deny(rustc::ty_pass_by_reference)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: passing `Ty<'tcx>` by reference
-  --> $DIR/pass_ty_by_ref_self.rs:31:21
-   |
-LL |     fn by_ref(self: &Ty<'tcx>) {}
-   |                     ^^^^^^^^^ help: try passing by value: `Ty<'tcx>`
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.rs
new file mode 100644 (file)
index 0000000..402c41f
--- /dev/null
@@ -0,0 +1,118 @@
+// compile-flags: -Z unstable-options
+
+#![feature(rustc_attrs)]
+#![feature(rustc_private)]
+#![deny(rustc::pass_by_value)]
+#![allow(unused)]
+
+extern crate rustc_middle;
+
+use rustc_middle::ty::{Ty, TyCtxt};
+
+fn ty_by_ref(
+    ty_val: Ty<'_>,
+    ty_ref: &Ty<'_>, //~ ERROR passing `Ty<'_>` by reference
+    ty_ctxt_val: TyCtxt<'_>,
+    ty_ctxt_ref: &TyCtxt<'_>, //~ ERROR passing `TyCtxt<'_>` by reference
+) {
+}
+
+fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
+//~^ ERROR passing `Ty<'_>` by reference
+//~^^ ERROR passing `TyCtxt<'_>` by reference
+
+trait T {
+    fn ty_by_ref_in_trait(
+        ty_val: Ty<'_>,
+        ty_ref: &Ty<'_>, //~ ERROR passing `Ty<'_>` by reference
+        ty_ctxt_val: TyCtxt<'_>,
+        ty_ctxt_ref: &TyCtxt<'_>, //~ ERROR passing `TyCtxt<'_>` by reference
+    );
+
+    fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
+    //~^ ERROR passing `Ty<'_>` by reference
+    //~^^ ERROR passing `TyCtxt<'_>` by reference
+}
+
+struct Foo;
+
+impl T for Foo {
+    fn ty_by_ref_in_trait(
+        ty_val: Ty<'_>,
+        ty_ref: &Ty<'_>,
+        ty_ctxt_val: TyCtxt<'_>,
+        ty_ctxt_ref: &TyCtxt<'_>,
+    ) {
+    }
+
+    fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
+}
+
+impl Foo {
+    fn ty_by_ref_assoc(
+        ty_val: Ty<'_>,
+        ty_ref: &Ty<'_>, //~ ERROR passing `Ty<'_>` by reference
+        ty_ctxt_val: TyCtxt<'_>,
+        ty_ctxt_ref: &TyCtxt<'_>, //~ ERROR passing `TyCtxt<'_>` by reference
+    ) {
+    }
+
+    fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
+    //~^ ERROR passing `Ty<'_>` by reference
+    //~^^ ERROR passing `TyCtxt<'_>` by reference
+}
+
+#[rustc_pass_by_value]
+enum CustomEnum {
+    A,
+    B,
+}
+
+impl CustomEnum {
+    fn test(
+        value: CustomEnum,
+        reference: &CustomEnum, //~ ERROR passing `CustomEnum` by reference
+    ) {
+    }
+}
+
+#[rustc_pass_by_value]
+struct CustomStruct {
+    s: u8,
+}
+
+#[rustc_pass_by_value]
+type CustomAlias<'a> = &'a CustomStruct; //~ ERROR passing `CustomStruct` by reference
+
+impl CustomStruct {
+    fn test(
+        value: CustomStruct,
+        reference: &CustomStruct, //~ ERROR passing `CustomStruct` by reference
+    ) {
+    }
+
+    fn test_alias(
+        value: CustomAlias,
+        reference: &CustomAlias, //~ ERROR passing `CustomAlias<>` by reference
+    ) {
+    }
+}
+
+#[rustc_pass_by_value]
+struct WithParameters<T, const N: usize, M = u32> {
+    slice: [T; N],
+    m: M,
+}
+
+impl<T> WithParameters<T, 1> {
+    fn test<'a>(
+        value: WithParameters<T, 1>,
+        reference: &'a WithParameters<T, 1>, //~ ERROR passing `WithParameters<T, 1>` by reference
+        reference_with_m: &WithParameters<T, 1, u32>, //~ ERROR passing `WithParameters<T, 1, u32>` by reference
+    ) -> &'a WithParameters<T, 1> {
+        //~^ ERROR passing `WithParameters<T, 1>` by reference
+        reference as &WithParameters<_, 1> //~ ERROR passing `WithParameters<_, 1>` by reference
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value.stderr
new file mode 100644 (file)
index 0000000..7f6e57b
--- /dev/null
@@ -0,0 +1,128 @@
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:14:13
+   |
+LL |     ty_ref: &Ty<'_>,
+   |             ^^^^^^^ help: try passing by value: `Ty<'_>`
+   |
+note: the lint level is defined here
+  --> $DIR/rustc_pass_by_value.rs:5:9
+   |
+LL | #![deny(rustc::pass_by_value)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:16:18
+   |
+LL |     ty_ctxt_ref: &TyCtxt<'_>,
+   |                  ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:20:28
+   |
+LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
+   |                            ^^^^^^^ help: try passing by value: `Ty<'_>`
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:20:55
+   |
+LL | fn ty_multi_ref(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
+   |                                                       ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:27:17
+   |
+LL |         ty_ref: &Ty<'_>,
+   |                 ^^^^^^^ help: try passing by value: `Ty<'_>`
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:29:22
+   |
+LL |         ty_ctxt_ref: &TyCtxt<'_>,
+   |                      ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:32:41
+   |
+LL |     fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
+   |                                         ^^^^^^^ help: try passing by value: `Ty<'_>`
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:32:68
+   |
+LL |     fn ty_multi_ref_in_trait(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>);
+   |                                                                    ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:54:17
+   |
+LL |         ty_ref: &Ty<'_>,
+   |                 ^^^^^^^ help: try passing by value: `Ty<'_>`
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:56:22
+   |
+LL |         ty_ctxt_ref: &TyCtxt<'_>,
+   |                      ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `Ty<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:60:38
+   |
+LL |     fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
+   |                                      ^^^^^^^ help: try passing by value: `Ty<'_>`
+
+error: passing `TyCtxt<'_>` by reference
+  --> $DIR/rustc_pass_by_value.rs:60:65
+   |
+LL |     fn ty_multi_ref_assoc(ty_multi: &&Ty<'_>, ty_ctxt_multi: &&&&TyCtxt<'_>) {}
+   |                                                                 ^^^^^^^^^^^ help: try passing by value: `TyCtxt<'_>`
+
+error: passing `CustomEnum` by reference
+  --> $DIR/rustc_pass_by_value.rs:74:20
+   |
+LL |         reference: &CustomEnum,
+   |                    ^^^^^^^^^^^ help: try passing by value: `CustomEnum`
+
+error: passing `CustomStruct` by reference
+  --> $DIR/rustc_pass_by_value.rs:85:24
+   |
+LL | type CustomAlias<'a> = &'a CustomStruct;
+   |                        ^^^^^^^^^^^^^^^^ help: try passing by value: `CustomStruct`
+
+error: passing `CustomStruct` by reference
+  --> $DIR/rustc_pass_by_value.rs:90:20
+   |
+LL |         reference: &CustomStruct,
+   |                    ^^^^^^^^^^^^^ help: try passing by value: `CustomStruct`
+
+error: passing `CustomAlias<>` by reference
+  --> $DIR/rustc_pass_by_value.rs:96:20
+   |
+LL |         reference: &CustomAlias,
+   |                    ^^^^^^^^^^^^ help: try passing by value: `CustomAlias<>`
+
+error: passing `WithParameters<T, 1>` by reference
+  --> $DIR/rustc_pass_by_value.rs:110:20
+   |
+LL |         reference: &'a WithParameters<T, 1>,
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1>`
+
+error: passing `WithParameters<T, 1, u32>` by reference
+  --> $DIR/rustc_pass_by_value.rs:111:27
+   |
+LL |         reference_with_m: &WithParameters<T, 1, u32>,
+   |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1, u32>`
+
+error: passing `WithParameters<T, 1>` by reference
+  --> $DIR/rustc_pass_by_value.rs:112:10
+   |
+LL |     ) -> &'a WithParameters<T, 1> {
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<T, 1>`
+
+error: passing `WithParameters<_, 1>` by reference
+  --> $DIR/rustc_pass_by_value.rs:114:22
+   |
+LL |         reference as &WithParameters<_, 1>
+   |                      ^^^^^^^^^^^^^^^^^^^^^ help: try passing by value: `WithParameters<_, 1>`
+
+error: aborting due to 20 previous errors
+
diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.rs
new file mode 100644 (file)
index 0000000..2868517
--- /dev/null
@@ -0,0 +1,54 @@
+// compile-flags: -Z unstable-options
+// NOTE: This test doesn't actually require `fulldeps`
+// so we could instead use it as a `ui` test.
+//
+// Considering that all other `internal-lints` are tested here
+// this seems like the cleaner solution though.
+#![feature(rustc_attrs)]
+#![deny(rustc::pass_by_value)]
+#![allow(unused)]
+
+#[rustc_pass_by_value]
+struct TyCtxt<'tcx> {
+    inner: &'tcx (),
+}
+
+impl<'tcx> TyCtxt<'tcx> {
+    fn by_value(self) {} // OK
+    fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference
+}
+
+struct TyS<'tcx> {
+    inner: &'tcx (),
+}
+
+#[rustc_pass_by_value]
+type Ty<'tcx> = &'tcx TyS<'tcx>;
+
+impl<'tcx> TyS<'tcx> {
+    fn by_value(self: Ty<'tcx>) {}
+    fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference
+}
+
+#[rustc_pass_by_value]
+struct Foo;
+
+impl Foo {
+    fn with_ref(&self) {} //~ ERROR passing `Foo` by reference
+}
+
+#[rustc_pass_by_value]
+struct WithParameters<T, const N: usize, M = u32> {
+    slice: [T; N],
+    m: M,
+}
+
+impl<T> WithParameters<T, 1> {
+    fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize>` by reference
+}
+
+impl<T> WithParameters<T, 1, u8> {
+    fn with_ref(&self) {} //~ ERROR passing `WithParameters<T, 1_usize, u8>` by reference
+}
+
+fn main() {}
diff --git a/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr b/src/test/ui-fulldeps/internal-lints/rustc_pass_by_value_self.stderr
new file mode 100644 (file)
index 0000000..54a7cf7
--- /dev/null
@@ -0,0 +1,38 @@
+error: passing `TyCtxt<'tcx>` by reference
+  --> $DIR/rustc_pass_by_value_self.rs:18:15
+   |
+LL |     fn by_ref(&self) {}
+   |               ^^^^^ help: try passing by value: `TyCtxt<'tcx>`
+   |
+note: the lint level is defined here
+  --> $DIR/rustc_pass_by_value_self.rs:8:9
+   |
+LL | #![deny(rustc::pass_by_value)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+
+error: passing `Ty<'tcx>` by reference
+  --> $DIR/rustc_pass_by_value_self.rs:30:21
+   |
+LL |     fn by_ref(self: &Ty<'tcx>) {}
+   |                     ^^^^^^^^^ help: try passing by value: `Ty<'tcx>`
+
+error: passing `Foo` by reference
+  --> $DIR/rustc_pass_by_value_self.rs:37:17
+   |
+LL |     fn with_ref(&self) {}
+   |                 ^^^^^ help: try passing by value: `Foo`
+
+error: passing `WithParameters<T, 1_usize>` by reference
+  --> $DIR/rustc_pass_by_value_self.rs:47:17
+   |
+LL |     fn with_ref(&self) {}
+   |                 ^^^^^ help: try passing by value: `WithParameters<T, 1_usize>`
+
+error: passing `WithParameters<T, 1_usize, u8>` by reference
+  --> $DIR/rustc_pass_by_value_self.rs:51:17
+   |
+LL |     fn with_ref(&self) {}
+   |                 ^^^^^ help: try passing by value: `WithParameters<T, 1_usize, u8>`
+
+error: aborting due to 5 previous errors
+
index 9eba9e0ca769cd63c7df5bc5b7339f8f80e02718..e3eff2eb1433e5b30186b1d83631c229454f4884 100644 (file)
@@ -5,9 +5,7 @@
 // ignore-android
 // ignore-arm
 // ignore-aarch64
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
+#![feature(asm_sym)]
 
 #[cfg(target_arch = "x86_64")]
 pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64,
@@ -54,37 +52,37 @@ pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct
 
 #[cfg(target_arch = "x86_64")]
 pub fn main() {
+    use std::arch::asm;
+
     let result: i64;
     unsafe {
-        llvm_asm!("mov rdi, 1;
-                   mov rsi, 2;
-                   mov rdx, 3;
-                   mov rcx, 4;
-                   mov r8,  5;
-                   mov r9,  6;
-                   mov eax, 0x3F800000;
-                   movd xmm0, eax;
-                   mov eax, 0x40000000;
-                   movd xmm1, eax;
-                   mov eax, 0x40800000;
-                   movd xmm2, eax;
-                   mov eax, 0x41000000;
-                   movd xmm3, eax;
-                   mov eax, 0x41800000;
-                   movd xmm4, eax;
-                   mov eax, 0x42000000;
-                   movd xmm5, eax;
-                   mov eax, 0x42800000;
-                   movd xmm6, eax;
-                   mov eax, 0x43000000;
-                   movd xmm7, eax;
-                   call r10
-                   "
-                 : "={rax}"(result)
-                 : "{r10}"(all_the_registers as usize)
-                 : "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r11", "cc", "memory"
-                 : "intel", "alignstack"
-        )
+        asm!("mov rdi, 1",
+             "mov rsi, 2",
+             "mov rdx, 3",
+             "mov rcx, 4",
+             "mov r8,  5",
+             "mov r9,  6",
+             "mov eax, 0x3F800000",
+             "movd xmm0, eax",
+             "mov eax, 0x40000000",
+             "movd xmm1, eax",
+             "mov eax, 0x40800000",
+             "movd xmm2, eax",
+             "mov eax, 0x41000000",
+             "movd xmm3, eax",
+             "mov eax, 0x41800000",
+             "movd xmm4, eax",
+             "mov eax, 0x42000000",
+             "movd xmm5, eax",
+             "mov eax, 0x42800000",
+             "movd xmm6, eax",
+             "mov eax, 0x43000000",
+             "movd xmm7, eax",
+             "call {0}",
+             sym all_the_registers,
+             out("rax") result,
+             clobber_abi("sysv64"),
+        );
     }
     assert_eq!(result, 42);
 
index b44204b9005655d260f372dd72ecac94c6b681ad..32431d9e7c6fe8bcbcb47f7722d0dc863944bee3 100644 (file)
@@ -3,12 +3,10 @@
 // ignore-spirv
 // ignore-wasm32
 
-#![feature(llvm_asm)]
 #![feature(naked_functions)]
 #![feature(or_patterns)]
 #![feature(asm_const, asm_sym)]
 #![crate_type = "lib"]
-#![allow(deprecated)] // llvm_asm!
 
 use std::arch::asm;
 
@@ -114,16 +112,6 @@ pub extern "C" fn inner(y: usize) -> usize {
     inner
 }
 
-#[naked]
-unsafe extern "C" fn llvm() -> ! {
-    //~^ WARN naked functions must contain a single asm block
-    //~| WARN this was previously accepted
-    llvm_asm!("");
-    //~^ WARN LLVM-style inline assembly is unsupported in naked functions
-    //~| WARN this was previously accepted
-    core::hint::unreachable_unchecked();
-}
-
 #[naked]
 unsafe extern "C" fn invalid_options() {
     asm!("", options(nomem, preserves_flags, noreturn));
index 8e177f5a52ca4004b779ed72632a297048670f55..c2dfe443d6038baaf5a63d1e6d6603c9232e30ec 100644 (file)
@@ -1,35 +1,35 @@
 error: asm with the `pure` option must have at least one output
-  --> $DIR/naked-functions.rs:136:14
+  --> $DIR/naked-functions.rs:124:14
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:23:5
+  --> $DIR/naked-functions.rs:21:5
    |
 LL |     mut a: u32,
    |     ^^^^^
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:25:5
+  --> $DIR/naked-functions.rs:23:5
    |
 LL |     &b: &i32,
    |     ^^
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:27:6
+  --> $DIR/naked-functions.rs:25:6
    |
 LL |     (None | Some(_)): Option<std::ptr::NonNull<u8>>,
    |      ^^^^^^^^^^^^^^
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:29:5
+  --> $DIR/naked-functions.rs:27:5
    |
 LL |     P { x, y }: P,
    |     ^^^^^^^^^^
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:39:5
+  --> $DIR/naked-functions.rs:37:5
    |
 LL |     a + 1
    |     ^
@@ -37,7 +37,7 @@ LL |     a + 1
    = help: follow the calling convention in asm block to use parameters
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:36:1
+  --> $DIR/naked-functions.rs:34:1
    |
 LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
 LL | |
@@ -53,7 +53,7 @@ LL | | }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:45:31
+  --> $DIR/naked-functions.rs:43:31
    |
 LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    |                               ^
@@ -61,7 +61,7 @@ LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    = help: follow the calling convention in asm block to use parameters
 
 warning: only `const` and `sym` operands are supported in naked functions
-  --> $DIR/naked-functions.rs:45:23
+  --> $DIR/naked-functions.rs:43:23
    |
 LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    |                       ^^^^^^^^^
@@ -70,7 +70,7 @@ LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:52:1
+  --> $DIR/naked-functions.rs:50:1
    |
 LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
 LL | |
@@ -84,7 +84,7 @@ LL | | }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: only `const` and `sym` operands are supported in naked functions
-  --> $DIR/naked-functions.rs:72:10
+  --> $DIR/naked-functions.rs:70:10
    |
 LL |          in(reg) a,
    |          ^^^^^^^^^
@@ -102,7 +102,7 @@ LL |          out(reg) e,
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:69:5
+  --> $DIR/naked-functions.rs:67:5
    |
 LL | /     asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
 LL | |
@@ -117,7 +117,7 @@ LL | |     );
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:59:1
+  --> $DIR/naked-functions.rs:57:1
    |
 LL | / pub unsafe extern "C" fn unsupported_operands() {
 LL | |
@@ -141,7 +141,7 @@ LL | | }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:85:1
+  --> $DIR/naked-functions.rs:83:1
    |
 LL | / pub extern "C" fn missing_assembly() {
 LL | |
@@ -153,7 +153,7 @@ LL | | }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:94:5
+  --> $DIR/naked-functions.rs:92:5
    |
 LL |     asm!("");
    |     ^^^^^^^^
@@ -162,7 +162,7 @@ LL |     asm!("");
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:97:5
+  --> $DIR/naked-functions.rs:95:5
    |
 LL |     asm!("");
    |     ^^^^^^^^
@@ -171,7 +171,7 @@ LL |     asm!("");
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:100:5
+  --> $DIR/naked-functions.rs:98:5
    |
 LL |     asm!("");
    |     ^^^^^^^^
@@ -180,7 +180,7 @@ LL |     asm!("");
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:91:1
+  --> $DIR/naked-functions.rs:89:1
    |
 LL | / pub extern "C" fn too_many_asm_blocks() {
 LL | |
@@ -202,7 +202,7 @@ LL | | }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:111:11
+  --> $DIR/naked-functions.rs:109:11
    |
 LL |         *&y
    |           ^
@@ -210,7 +210,7 @@ LL |         *&y
    = help: follow the calling convention in asm block to use parameters
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:108:5
+  --> $DIR/naked-functions.rs:106:5
    |
 LL | /     pub extern "C" fn inner(y: usize) -> usize {
 LL | |
@@ -224,35 +224,8 @@ LL | |     }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: the LLVM-style inline assembly is unsupported in naked functions
-  --> $DIR/naked-functions.rs:121:5
-   |
-LL |     llvm_asm!("");
-   |     ^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
-   = help: use the new asm! syntax specified in RFC 2873
-   = note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:118:1
-   |
-LL | / unsafe extern "C" fn llvm() -> ! {
-LL | |
-LL | |
-LL | |     llvm_asm!("");
-...  |
-LL | |     core::hint::unreachable_unchecked();
-   | |     ------------------------------------ non-asm is unsupported in naked functions
-LL | | }
-   | |_^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
-
 warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
-  --> $DIR/naked-functions.rs:129:5
+  --> $DIR/naked-functions.rs:117:5
    |
 LL |     asm!("", options(nomem, preserves_flags, noreturn));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -261,7 +234,7 @@ LL |     asm!("", options(nomem, preserves_flags, noreturn));
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
-  --> $DIR/naked-functions.rs:136:5
+  --> $DIR/naked-functions.rs:124:5
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -270,7 +243,7 @@ LL |     asm!("", options(readonly, nostack), options(pure));
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:136:5
+  --> $DIR/naked-functions.rs:124:5
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -279,7 +252,7 @@ LL |     asm!("", options(readonly, nostack), options(pure));
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:145:15
+  --> $DIR/naked-functions.rs:133:15
    |
 LL | pub unsafe fn default_abi() {
    |               ^^^^^^^^^^^
@@ -287,13 +260,13 @@ LL | pub unsafe fn default_abi() {
    = note: `#[warn(undefined_naked_function_abi)]` on by default
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:151:15
+  --> $DIR/naked-functions.rs:139:15
    |
 LL | pub unsafe fn rust_abi() {
    |               ^^^^^^^^
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:191:1
+  --> $DIR/naked-functions.rs:179:1
    |
 LL | #[inline]
    | ^^^^^^^^^
@@ -302,7 +275,7 @@ LL | #[inline]
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:199:1
+  --> $DIR/naked-functions.rs:187:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
@@ -311,7 +284,7 @@ LL | #[inline(always)]
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:207:1
+  --> $DIR/naked-functions.rs:195:1
    |
 LL | #[inline(never)]
    | ^^^^^^^^^^^^^^^^
@@ -320,7 +293,7 @@ LL | #[inline(never)]
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:215:1
+  --> $DIR/naked-functions.rs:203:1
    |
 LL | #[inline]
    | ^^^^^^^^^
@@ -329,7 +302,7 @@ LL | #[inline]
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:218:1
+  --> $DIR/naked-functions.rs:206:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
@@ -338,7 +311,7 @@ LL | #[inline(always)]
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:221:1
+  --> $DIR/naked-functions.rs:209:1
    |
 LL | #[inline(never)]
    | ^^^^^^^^^^^^^^^^
@@ -346,5 +319,5 @@ LL | #[inline(never)]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-error: aborting due to 8 previous errors; 25 warnings emitted
+error: aborting due to 8 previous errors; 23 warnings emitted
 
diff --git a/src/test/ui/associated-consts/assoc-const.rs b/src/test/ui/associated-consts/assoc-const.rs
new file mode 100644 (file)
index 0000000..cd4b42f
--- /dev/null
@@ -0,0 +1,21 @@
+#![feature(associated_const_equality)]
+
+pub trait Foo {
+  const N: usize;
+}
+
+pub struct Bar;
+
+impl Foo for Bar {
+  const N: usize = 3;
+}
+
+const TEST:usize = 3;
+
+
+fn foo<F: Foo<N=3>>() {}
+//~^ ERROR associated const equality is incomplete
+fn bar<F: Foo<N={TEST}>>() {}
+//~^ ERROR associated const equality is incomplete
+
+fn main() {}
diff --git a/src/test/ui/associated-consts/assoc-const.stderr b/src/test/ui/associated-consts/assoc-const.stderr
new file mode 100644 (file)
index 0000000..ccaa6fa
--- /dev/null
@@ -0,0 +1,14 @@
+error: associated const equality is incomplete
+  --> $DIR/assoc-const.rs:16:15
+   |
+LL | fn foo<F: Foo<N=3>>() {}
+   |               ^^^ cannot yet relate associated const
+
+error: associated const equality is incomplete
+  --> $DIR/assoc-const.rs:18:15
+   |
+LL | fn bar<F: Foo<N={TEST}>>() {}
+   |               ^^^^^^^^ cannot yet relate associated const
+
+error: aborting due to 2 previous errors
+
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 1a19883ae1550285f845fb929d0a08e78ef6f23f..ce93e4b5d4b2dc9526f36e0d9d2875d6c54d5087 100644 (file)
@@ -8,9 +8,6 @@
 // check-pass
 // dont-check-compiler-stdout - don't check for any AST change.
 
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
 enum V {
     A(i32),
     B { f: [i64; 3 + 4] }
@@ -27,12 +24,6 @@ macro_rules! call_println {
 }
 
 fn main() {
-    #[cfg(any(target_arch = "x86",
-        target_arch = "x86_64",
-        target_arch = "arm",
-        target_arch = "aarch64"))]
-    unsafe { llvm_asm!(""::::); }
-
     let x: (i32) = 35;
     let y = x as i64<> + 5;
 
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);
+}
index 9bfb0f28028cb823a1e336e5c8ec61dfb71a558c..ac5f99970c8148398b7d105253eccad924fee621 100644 (file)
@@ -2,23 +2,17 @@ error[E0623]: lifetime mismatch
   --> $DIR/issue-76547.rs:20:13
    |
 LL | async fn fut(bufs: &mut [&mut [u8]]) {
-   |                          ---------   -
-   |                          |           |
-   |                          |           this `async fn` implicitly returns an `impl Future<Output = ()>`
-   |                          this parameter and the returned future are declared with different lifetimes...
+   |                    ---------------- these two types are declared with different lifetimes...
 LL |     ListFut(bufs).await
-   |             ^^^^ ...but data from `bufs` is held across an await point here
+   |             ^^^^ ...but data from `bufs` flows into `bufs` here
 
 error[E0623]: lifetime mismatch
   --> $DIR/issue-76547.rs:34:14
    |
 LL | async fn fut2(bufs: &mut [&mut [u8]]) -> i32 {
-   |                           ---------      ---
-   |                           |              |
-   |                           |              this `async fn` implicitly returns an `impl Future<Output = i32>`
-   |                           this parameter and the returned future are declared with different lifetimes...
+   |                     ---------------- these two types are declared with different lifetimes...
 LL |     ListFut2(bufs).await
-   |              ^^^^ ...but data from `bufs` is held across an await point here
+   |              ^^^^ ...but data from `bufs` flows into `bufs` here
 
 error: aborting due to 2 previous errors
 
index ac29cca9d3f602a8ac4c4f3da8320929823f481f..8f602a1492ad2ff02765b189b8ebc33f45a7c556 100644 (file)
@@ -2,14 +2,12 @@ error[E0623]: lifetime mismatch
   --> $DIR/issue-63388-1.rs:14:9
    |
 LL |         &'a self, foo: &dyn Foo
-   |         -------- this parameter and the returned future are declared with different lifetimes...
+   |                        -------- this parameter and the return type are declared with different lifetimes...
 LL |     ) -> &dyn Foo
    |          --------
-   |          |
-   |          this `async fn` implicitly returns an `impl Future<Output = &dyn Foo>`
 LL |     {
 LL |         foo
-   |         ^^^ ...but data from `foo` is held across an await point here
+   |         ^^^ ...but data from `foo` is returned here
 
 error: aborting due to previous error
 
index 464f283095dad52c8bd420e12b4b1afa36bf273e..149692a2c6998e29981b192df521a48fa354c480 100644 (file)
@@ -4,9 +4,8 @@ error[E0623]: lifetime mismatch
 LL | async fn async_ret_impl_trait3<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> + 'b {
    |                                                      ------     ^^^^^^^^^^^^^^^^^^^
    |                                                      |          |
-   |                                                      |          ...but data from `a` is held across an await point here
-   |                                                      |          this `async fn` implicitly returns an `impl Future<Output = impl Trait<'a> + 'b>`
-   |                                                      this parameter and the returned future are declared with different lifetimes...
+   |                                                      |          ...but data from `a` is returned here
+   |                                                      this parameter and the return type are declared with different lifetimes...
 
 error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds
   --> $DIR/ret-impl-trait-one.rs:16:65
diff --git a/src/test/ui/autoref-autoderef/deref-into-array.rs b/src/test/ui/autoref-autoderef/deref-into-array.rs
new file mode 100644 (file)
index 0000000..855a82d
--- /dev/null
@@ -0,0 +1,17 @@
+// check-pass
+
+struct Test<T>([T; 1]);
+
+impl<T> std::ops::Deref for Test<T> {
+    type Target = [T; 1];
+
+    fn deref(&self) -> &[T; 1] {
+        &self.0
+    }
+}
+
+fn main() {
+    let out = Test([(); 1]);
+    let blah = out.len();
+    println!("{}", blah);
+}
diff --git a/src/test/ui/borrowck/borrowck-asm.rs b/src/test/ui/borrowck/borrowck-asm.rs
deleted file mode 100644 (file)
index 0d202c1..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-// ignore-s390x
-// ignore-emscripten
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-powerpc64le
-// ignore-riscv64
-// ignore-sparc
-// ignore-sparc64
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-#[cfg(any(target_arch = "x86",
-            target_arch = "x86_64",
-            target_arch = "arm",
-            target_arch = "aarch64",
-            target_arch = "mips",
-            target_arch = "mips64"))]
-mod test_cases {
-    fn is_move() {
-        let y: &mut isize;
-        let x = &mut 0isize;
-        unsafe {
-            llvm_asm!("nop" : : "r"(x));
-        }
-        let z = x;  //~ ERROR use of moved value: `x`
-    }
-
-    fn in_is_read() {
-        let mut x = 3;
-        let y = &mut x;
-        unsafe {
-            llvm_asm!("nop" : : "r"(x)); //~ ERROR cannot use
-        }
-        let z = y;
-    }
-
-    fn out_is_assign() {
-        let x = 3;
-        unsafe {
-            llvm_asm!("nop" : "=r"(x));  //~ ERROR cannot assign twice
-        }
-        let mut a = &mut 3;
-        let b = &*a;
-        unsafe {
-            llvm_asm!("nop" : "=r"(a));  // OK, Shallow write to `a`
-        }
-        let c = b;
-        let d = *a;
-    }
-
-    fn rw_is_assign() {
-        let x = 3;
-        unsafe {
-            llvm_asm!("nop" : "+r"(x));  //~ ERROR cannot assign twice
-        }
-    }
-
-    fn indirect_is_not_init() {
-        let x: i32;
-        unsafe {
-            llvm_asm!("nop" : "=*r"(x)); //~ ERROR use of possibly-uninitialized variable
-        }
-    }
-
-    fn rw_is_read() {
-        let mut x = &mut 3;
-        let y = &*x;
-        unsafe {
-            llvm_asm!("nop" : "+r"(x));  //~ ERROR cannot assign to `x` because it is borrowed
-        }
-        let z = y;
-    }
-
-    fn two_moves() {
-        let x = &mut 2;
-        unsafe {
-            llvm_asm!("nop" : : "r"(x), "r"(x) );    //~ ERROR use of moved value
-        }
-    }
-}
-
-fn main() {}
diff --git a/src/test/ui/borrowck/borrowck-asm.stderr b/src/test/ui/borrowck/borrowck-asm.stderr
deleted file mode 100644 (file)
index ff5847d..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-error[E0382]: use of moved value: `x`
-  --> $DIR/borrowck-asm.rs:26:17
-   |
-LL |         let x = &mut 0isize;
-   |             - move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait
-LL |         unsafe {
-LL |             llvm_asm!("nop" : : "r"(x));
-   |                                     - value moved here
-LL |         }
-LL |         let z = x;
-   |                 ^ value used here after move
-
-error[E0503]: cannot use `x` because it was mutably borrowed
-  --> $DIR/borrowck-asm.rs:33:37
-   |
-LL |         let y = &mut x;
-   |                 ------ borrow of `x` occurs here
-LL |         unsafe {
-LL |             llvm_asm!("nop" : : "r"(x));
-   |                                     ^ use of borrowed `x`
-LL |         }
-LL |         let z = y;
-   |                 - borrow later used here
-
-error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/borrowck-asm.rs:41:36
-   |
-LL |         let x = 3;
-   |             -
-   |             |
-   |             first assignment to `x`
-   |             help: consider making this binding mutable: `mut x`
-LL |         unsafe {
-LL |             llvm_asm!("nop" : "=r"(x));
-   |                                    ^ cannot assign twice to immutable variable
-
-error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/borrowck-asm.rs:55:36
-   |
-LL |         let x = 3;
-   |             -
-   |             |
-   |             first assignment to `x`
-   |             help: consider making this binding mutable: `mut x`
-LL |         unsafe {
-LL |             llvm_asm!("nop" : "+r"(x));
-   |                                    ^ cannot assign twice to immutable variable
-
-error[E0381]: use of possibly-uninitialized variable: `x`
-  --> $DIR/borrowck-asm.rs:62:37
-   |
-LL |             llvm_asm!("nop" : "=*r"(x));
-   |                                     ^ use of possibly-uninitialized `x`
-
-error[E0506]: cannot assign to `x` because it is borrowed
-  --> $DIR/borrowck-asm.rs:70:36
-   |
-LL |         let y = &*x;
-   |                 --- borrow of `x` occurs here
-LL |         unsafe {
-LL |             llvm_asm!("nop" : "+r"(x));
-   |                                    ^ assignment to borrowed `x` occurs here
-LL |         }
-LL |         let z = y;
-   |                 - borrow later used here
-
-error[E0382]: use of moved value: `x`
-  --> $DIR/borrowck-asm.rs:78:45
-   |
-LL |         let x = &mut 2;
-   |             - move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
-LL |         unsafe {
-LL |             llvm_asm!("nop" : : "r"(x), "r"(x) );
-   |                                     -       ^ value used here after move
-   |                                     |
-   |                                     value moved here
-
-error: aborting due to 7 previous errors
-
-Some errors have detailed explanations: E0381, E0382, E0384, E0503, E0506.
-For more information about an error, try `rustc --explain E0381`.
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/const-generics/deref-into-array-generic.rs b/src/test/ui/const-generics/deref-into-array-generic.rs
new file mode 100644 (file)
index 0000000..7d75af1
--- /dev/null
@@ -0,0 +1,27 @@
+// check-pass
+
+struct Test<T, const N: usize>([T; N]);
+
+impl<T: Copy + Default, const N: usize> Default for Test<T, N> {
+    fn default() -> Self {
+        Self([T::default(); N])
+    }
+}
+
+impl<T, const N: usize> std::ops::Deref for Test<T, N> {
+    type Target = [T; N];
+
+    fn deref(&self) -> &[T; N] {
+        &self.0
+    }
+}
+
+fn test() -> Test<u64, 16> {
+    let test = Test::default();
+    println!("{}", test.len());
+    test
+}
+
+fn main() {
+    test();
+}
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
deleted file mode 100644 (file)
index 56b88a4..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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
deleted file mode 100644 (file)
index eaa12b4..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-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/in-signature.rs b/src/test/ui/const-generics/generic_arg_infer/in-signature.rs
new file mode 100644 (file)
index 0000000..1f60b22
--- /dev/null
@@ -0,0 +1,61 @@
+#![crate_type = "rlib"]
+#![feature(generic_arg_infer)]
+
+struct Foo<const N: usize>;
+struct Bar<T, const N: usize>(T);
+
+fn arr_fn() -> [u8; _] {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+    [0; 3]
+}
+
+fn ty_fn() -> Bar<i32, _> {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+    Bar::<i32, 3>(0)
+}
+
+fn ty_fn_mixed() -> Bar<_, _> {
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
+    Bar::<i32, 3>(0)
+}
+
+const ARR_CT: [u8; _] = [0; 3];
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+static ARR_STATIC: [u8; _] = [0; 3];
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
+const TY_CT: Bar<i32, _> = Bar::<i32, 3>(0);
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+static TY_STATIC: Bar<i32, _> = Bar::<i32, 3>(0);
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
+const TY_CT_MIXED: Bar<_, _> = Bar::<i32, 3>(0);
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+static TY_STATIC_MIXED: Bar<_, _> = Bar::<i32, 3>(0);
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
+trait ArrAssocConst {
+    const ARR: [u8; _];
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+}
+trait TyAssocConst {
+    const ARR: Bar<i32, _>;
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+}
+trait TyAssocConstMixed {
+    const ARR: Bar<_, _>;
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
+}
+
+trait AssocTy {
+    type Assoc;
+}
+impl AssocTy for i8 {
+    type Assoc = [u8; _];
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
+}
+impl AssocTy for i16 {
+    type Assoc = Bar<i32, _>;
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
+}
+impl AssocTy for i32 {
+    type Assoc = Bar<_, _>;
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
+}
diff --git a/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr b/src/test/ui/const-generics/generic_arg_infer/in-signature.stderr
new file mode 100644 (file)
index 0000000..7581cf4
--- /dev/null
@@ -0,0 +1,119 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/in-signature.rs:7:21
+   |
+LL | fn arr_fn() -> [u8; _] {
+   |                -----^-
+   |                |    |
+   |                |    not allowed in type signatures
+   |                help: replace with the correct return type: `[u8; 3]`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/in-signature.rs:12:24
+   |
+LL | fn ty_fn() -> Bar<i32, _> {
+   |               ---------^-
+   |               |        |
+   |               |        not allowed in type signatures
+   |               help: replace with the correct return type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
+  --> $DIR/in-signature.rs:17:25
+   |
+LL | fn ty_fn_mixed() -> Bar<_, _> {
+   |                     ----^--^-
+   |                     |   |  |
+   |                     |   |  not allowed in type signatures
+   |                     |   not allowed in type signatures
+   |                     help: replace with the correct return type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:22:15
+   |
+LL | const ARR_CT: [u8; _] = [0; 3];
+   |               ^^^^^^^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
+  --> $DIR/in-signature.rs:24:20
+   |
+LL | static ARR_STATIC: [u8; _] = [0; 3];
+   |                    ^^^^^^^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:26:14
+   |
+LL | const TY_CT: Bar<i32, _> = Bar::<i32, 3>(0);
+   |              ^^^^^^^^^^^
+   |              |
+   |              not allowed in type signatures
+   |              help: replace with the correct type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
+  --> $DIR/in-signature.rs:28:19
+   |
+LL | static TY_STATIC: Bar<i32, _> = Bar::<i32, 3>(0);
+   |                   ^^^^^^^^^^^
+   |                   |
+   |                   not allowed in type signatures
+   |                   help: replace with the correct type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:30:20
+   |
+LL | const TY_CT_MIXED: Bar<_, _> = Bar::<i32, 3>(0);
+   |                    ^^^^^^^^^
+   |                    |
+   |                    not allowed in type signatures
+   |                    help: replace with the correct type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
+  --> $DIR/in-signature.rs:32:25
+   |
+LL | static TY_STATIC_MIXED: Bar<_, _> = Bar::<i32, 3>(0);
+   |                         ^^^^^^^^^
+   |                         |
+   |                         not allowed in type signatures
+   |                         help: replace with the correct type: `Bar<i32, 3_usize>`
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:35:21
+   |
+LL |     const ARR: [u8; _];
+   |                     ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:39:25
+   |
+LL |     const ARR: Bar<i32, _>;
+   |                         ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
+  --> $DIR/in-signature.rs:43:20
+   |
+LL |     const ARR: Bar<_, _>;
+   |                    ^  ^ not allowed in type signatures
+   |                    |
+   |                    not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
+  --> $DIR/in-signature.rs:51:23
+   |
+LL |     type Assoc = [u8; _];
+   |                       ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
+  --> $DIR/in-signature.rs:55:27
+   |
+LL |     type Assoc = Bar<i32, _>;
+   |                           ^ not allowed in type signatures
+
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
+  --> $DIR/in-signature.rs:59:22
+   |
+LL |     type Assoc = Bar<_, _>;
+   |                      ^  ^ not allowed in type signatures
+   |                      |
+   |                      not allowed in type signatures
+
+error: aborting due to 15 previous errors
+
+For more information about this error, try `rustc --explain E0121`.
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/const-generics/issues/issue-92186.rs b/src/test/ui/const-generics/issues/issue-92186.rs
new file mode 100644 (file)
index 0000000..9ced466
--- /dev/null
@@ -0,0 +1,12 @@
+// check-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+pub struct Foo<const N: usize>;
+pub trait Bar<T> {}
+
+impl<T> Bar<T> for Foo<{ 1 }> {}
+impl<T> Bar<T> for Foo<{ 2 }> {}
+
+fn main() {}
index 11c3481f15afa18e15234864f83315d800b34478..a6825b84589438743dae5df33014ae25dab58d16 100644 (file)
@@ -4,7 +4,7 @@ error: comparison operators cannot be chained
 LL |     foo<BAR + 3>();
    |        ^       ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<BAR + 3>();
    |        ++
@@ -15,7 +15,7 @@ error: comparison operators cannot be chained
 LL |     foo<BAR + BAR>();
    |        ^         ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<BAR + BAR>();
    |        ++
@@ -26,7 +26,7 @@ error: comparison operators cannot be chained
 LL |     foo<3 + 3>();
    |        ^     ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<3 + 3>();
    |        ++
@@ -37,7 +37,7 @@ error: comparison operators cannot be chained
 LL |     foo<BAR - 3>();
    |        ^       ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<BAR - 3>();
    |        ++
@@ -48,7 +48,7 @@ error: comparison operators cannot be chained
 LL |     foo<BAR - BAR>();
    |        ^         ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<BAR - BAR>();
    |        ++
@@ -59,7 +59,7 @@ error: comparison operators cannot be chained
 LL |     foo<100 - BAR>();
    |        ^         ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<100 - BAR>();
    |        ++
@@ -70,7 +70,7 @@ error: comparison operators cannot be chained
 LL |     foo<bar<i32>()>();
    |        ^   ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<bar<i32>()>();
    |        ++
@@ -87,7 +87,7 @@ error: comparison operators cannot be chained
 LL |     foo<bar::<i32>()>();
    |        ^            ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<bar::<i32>()>();
    |        ++
@@ -98,7 +98,7 @@ error: comparison operators cannot be chained
 LL |     foo<bar::<i32>() + BAR>();
    |        ^                  ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<bar::<i32>() + BAR>();
    |        ++
@@ -109,7 +109,7 @@ error: comparison operators cannot be chained
 LL |     foo<bar::<i32>() - BAR>();
    |        ^                  ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<bar::<i32>() - BAR>();
    |        ++
@@ -120,7 +120,7 @@ error: comparison operators cannot be chained
 LL |     foo<BAR - bar::<i32>()>();
    |        ^                  ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<BAR - bar::<i32>()>();
    |        ++
@@ -131,7 +131,7 @@ error: comparison operators cannot be chained
 LL |     foo<BAR - bar::<i32>()>();
    |        ^                  ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     foo::<BAR - bar::<i32>()>();
    |        ++
index 19e0f38d320c4e915bdd9c1c76e10881fb866aeb..b126b24853ff72a0213b9a26b8116accc9b8bb23 100644 (file)
@@ -7,8 +7,9 @@ trait Foo<const N: usize> {
 const T: usize = 42;
 
 impl Foo<N = 3> for Bar {
-//~^ ERROR cannot constrain an associated constant to a value
+//~^ ERROR this trait takes 1 generic argument but 0 generic arguments were supplied
 //~| ERROR associated type bindings are not allowed here
+//~| ERROR associated const equality is incomplete
     fn do_x(&self) -> [u8; 3] {
         [0u8; 3]
     }
index bbca92ad63a91ab7a0d0ae15859c8211ff534053..59ba054aa11277dc10b5ad0a4d3da9a2befced58 100644 (file)
@@ -1,11 +1,27 @@
-error: cannot constrain an associated constant to a value
+error[E0658]: associated const equality is incomplete
   --> $DIR/issue-89013-no-kw.rs:9:10
    |
 LL | impl Foo<N = 3> for Bar {
-   |          -^^^-
-   |          |   |
-   |          |   ...cannot be constrained to this value
-   |          this associated constant...
+   |          ^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+  --> $DIR/issue-89013-no-kw.rs:9:6
+   |
+LL | impl Foo<N = 3> for Bar {
+   |      ^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `N`
+  --> $DIR/issue-89013-no-kw.rs:1:7
+   |
+LL | trait Foo<const N: usize> {
+   |       ^^^       -
+help: add missing generic argument
+   |
+LL | impl Foo<N, N = 3> for Bar {
+   |          ++
 
 error[E0229]: associated type bindings are not allowed here
   --> $DIR/issue-89013-no-kw.rs:9:10
@@ -13,6 +29,7 @@ error[E0229]: associated type bindings are not allowed here
 LL | impl Foo<N = 3> for Bar {
    |          ^^^^^ associated type not allowed here
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0229`.
+Some errors have detailed explanations: E0107, E0229, E0658.
+For more information about an error, try `rustc --explain E0107`.
index ca1158a2f6d16140cccb9e3578ffa4862be26a90..9431779faf8590771e3ed30287c1f60d3333136e 100644 (file)
@@ -8,8 +8,9 @@ trait Foo<const N: usize> {
 
 impl Foo<N = const 3> for Bar {
 //~^ ERROR expected lifetime, type, or constant, found keyword `const`
-//~| ERROR cannot constrain an associated constant to a value
+//~| ERROR this trait takes 1 generic
 //~| ERROR associated type bindings are not allowed here
+//~| ERROR associated const equality is incomplete
     fn do_x(&self) -> [u8; 3] {
         [0u8; 3]
     }
index 85379d3f06e4b46722a0a2d5ed9aac717fb74580..9d4739926700bbb296e317fbb5a343ef0b04504b 100644 (file)
@@ -10,14 +10,30 @@ LL - impl Foo<N = const 3> for Bar {
 LL + impl Foo<N = 3> for Bar {
    | 
 
-error: cannot constrain an associated constant to a value
+error[E0658]: associated const equality is incomplete
   --> $DIR/issue-89013.rs:9:10
    |
 LL | impl Foo<N = const 3> for Bar {
-   |          -^^^^^^^^^-
-   |          |         |
-   |          |         ...cannot be constrained to this value
-   |          this associated constant...
+   |          ^^^^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied
+  --> $DIR/issue-89013.rs:9:6
+   |
+LL | impl Foo<N = const 3> for Bar {
+   |      ^^^ expected 1 generic argument
+   |
+note: trait defined here, with 1 generic parameter: `N`
+  --> $DIR/issue-89013.rs:1:7
+   |
+LL | trait Foo<const N: usize> {
+   |       ^^^       -
+help: add missing generic argument
+   |
+LL | impl Foo<N, N = const 3> for Bar {
+   |          ++
 
 error[E0229]: associated type bindings are not allowed here
   --> $DIR/issue-89013.rs:9:10
@@ -25,6 +41,7 @@ error[E0229]: associated type bindings are not allowed here
 LL | impl Foo<N = const 3> for Bar {
    |          ^^^^^^^^^^^ associated type not allowed here
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0229`.
+Some errors have detailed explanations: E0107, E0229, E0658.
+For more information about an error, try `rustc --explain E0107`.
index 565c9ba1ff1f67eb1658d0d5bf7230237dfda587..4d6b752867f1b0bd23c00e779a99483c6c70803d 100644 (file)
@@ -15,9 +15,20 @@ LL |     let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data
    |            |
    |            expected due to this
    |
-   = note: expected struct `A<'a, u16, {2u32}, {3u32}>`
-              found struct `A<'b, u32, {2u32}, {3u32}>`
+   = note: expected struct `A<'a, u16, _, _>`
+              found struct `A<'b, u32, _, _>`
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/types-mismatch-const-args.rs:18:41
+   |
+LL |     let _: A<'a, u16, {4u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
+   |            --------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `A<'a, u16, 4_u32, _>`
+              found struct `A<'b, u32, 2_u32, _>`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index ec9221d2486ae6dee0e3c4d9fb74d18f69eb1272..8b60238cb0c030469a4c04ab9b03968c67500072 100644 (file)
@@ -20,6 +20,17 @@ LL |     let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data
    = note: expected struct `A<'a, u16, _, _>`
               found struct `A<'b, u32, _, _>`
 
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+  --> $DIR/types-mismatch-const-args.rs:18:41
+   |
+LL |     let _: A<'a, u16, {4u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
+   |            --------------------------   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `A<'a, u16, 4_u32, _>`
+              found struct `A<'b, u32, 2_u32, _>`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index c2092c4268e803a234a4a9bdcce9333b4ae99ae9..43ef28b268f56becba15ecfd8504385455a74b3d 100644 (file)
@@ -15,6 +15,8 @@ fn a<'a, 'b>() {
     //~^ ERROR mismatched types
     let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
     //~^ ERROR mismatched types
+    let _: A<'a, u16, {4u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData };
+    //~^ ERROR mismatched types
 }
 
 pub fn main() {}
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..3d7e171
--- /dev/null
@@ -0,0 +1,23 @@
+#![allow(unused)]
+#![feature(const_fn_trait_bound, const_trait_impl, inline_const, negative_impls)]
+
+const fn f<T: ~const Drop>(x: T) {}
+
+struct UnconstDrop;
+
+impl Drop for UnconstDrop {
+    fn drop(&mut self) {}
+}
+
+struct NonDrop;
+
+impl !Drop for NonDrop {}
+
+fn main() {
+    const {
+        f(UnconstDrop);
+        //~^ ERROR the trait bound `UnconstDrop: Drop` is not satisfied
+        f(NonDrop);
+        //~^ ERROR the trait bound `NonDrop: 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..5f912c6
--- /dev/null
@@ -0,0 +1,35 @@
+error[E0277]: the trait bound `UnconstDrop: Drop` is not satisfied
+  --> $DIR/const-block-const-bound.rs:18: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[E0277]: the trait bound `NonDrop: Drop` is not satisfied
+  --> $DIR/const-block-const-bound.rs:20:11
+   |
+LL |         f(NonDrop);
+   |         - ^^^^^^^ the trait `Drop` is not implemented for `NonDrop`
+   |         |
+   |         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`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 1bb22a1301abf9b72f35788fc0b1b15de342fd40..6971170337d41e6689ad17b01602963891026557 100644 (file)
@@ -1,24 +1,13 @@
 // compile-flags: -Zunleash-the-miri-inside-of-you
 // only-x86_64
-#![feature(llvm_asm)]
 #![allow(const_err)]
-#![allow(deprecated)] // llvm_asm!
 
 use std::arch::asm;
 
 fn main() {}
 
 // Make sure we catch executing inline assembly.
-static TEST_BAD1: () = {
-    unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
-    //~^ ERROR could not evaluate static initializer
-    //~| NOTE inline assembly is not supported
-    //~| NOTE in this expansion of llvm_asm!
-    //~| NOTE in this expansion of llvm_asm!
-};
-
-// Make sure we catch executing inline assembly.
-static TEST_BAD2: () = {
+static TEST_BAD: () = {
     unsafe { asm!("nop"); }
     //~^ ERROR could not evaluate static initializer
     //~| NOTE inline assembly is not supported
index 34ac808ed1702415d796ce08090d9140ec6a9b21..595b859cbcebb1454150011d265a460b68341b90 100644 (file)
@@ -1,13 +1,5 @@
 error[E0080]: could not evaluate static initializer
-  --> $DIR/inline_asm.rs:13:14
-   |
-LL |     unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inline assembly is not supported
-   |
-   = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0080]: could not evaluate static initializer
-  --> $DIR/inline_asm.rs:22:14
+  --> $DIR/inline_asm.rs:11:14
    |
 LL |     unsafe { asm!("nop"); }
    |              ^^^^^^^^^^^ inline assembly is not supported
@@ -15,17 +7,11 @@ LL |     unsafe { asm!("nop"); }
 warning: skipping const checks
    |
 help: skipping check that does not even have a feature gate
-  --> $DIR/inline_asm.rs:13:14
-   |
-LL |     unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check that does not even have a feature gate
-  --> $DIR/inline_asm.rs:22:14
+  --> $DIR/inline_asm.rs:11:14
    |
 LL |     unsafe { asm!("nop"); }
    |              ^^^^^^^^^^^
-   = note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 2 previous errors; 1 warning emitted
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0080`.
index 72607629d3c10dc6ee43ffecafe9b52ff9669b05..2a44e56a3302c87054e9f145b4cc9e9d49521df2 100644 (file)
@@ -5,6 +5,12 @@ LL |     Void(Void),
    |     ^^^^^^^^^^
    |
    = note: `-W dead-code` implied by `-W unused`
+note: `Foo` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
+  --> $DIR/derive-uninhabited-enum-38885.rs:10:10
+   |
+LL | #[derive(Debug)]
+   |          ^^^^^
+   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: 1 warning emitted
 
index 226007f3647b15299c34bf22f17b395ad572d6be..67bb574315a72331ccffe78954b15eab4418a34e 100644 (file)
@@ -15,18 +15,39 @@ error: field is never read: `f`
    |
 LL | struct B { f: () }
    |            ^^^^^
+   |
+note: `B` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
+  --> $DIR/clone-debug-dead-code.rs:9:10
+   |
+LL | #[derive(Clone)]
+   |          ^^^^^
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: field is never read: `f`
   --> $DIR/clone-debug-dead-code.rs:14:12
    |
 LL | struct C { f: () }
    |            ^^^^^
+   |
+note: `C` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
+  --> $DIR/clone-debug-dead-code.rs:13:10
+   |
+LL | #[derive(Debug)]
+   |          ^^^^^
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: field is never read: `f`
   --> $DIR/clone-debug-dead-code.rs:18:12
    |
 LL | struct D { f: () }
    |            ^^^^^
+   |
+note: `D` has derived impls for the traits `Clone` and `Debug`, but these are intentionally ignored during dead code analysis
+  --> $DIR/clone-debug-dead-code.rs:17:10
+   |
+LL | #[derive(Debug,Clone)]
+   |          ^^^^^ ^^^^^
+   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: field is never read: `f`
   --> $DIR/clone-debug-dead-code.rs:21:12
index 609a5b0de6b7e2c3ca7e374f5fd338b5e290672c..f787c416c2d63cd19c63e3295edb5eef3d4f7675 100644 (file)
@@ -16,7 +16,7 @@
 
 type E = _::AssocTy;
 //~^ ERROR missing angle brackets in associated item path
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures for type aliases
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for type aliases
 
 type F = &'static (u8)::AssocTy;
 //~^ ERROR missing angle brackets in associated item path
@@ -49,37 +49,37 @@ macro_rules! ty {
 
 trait K<A, B> {}
 fn foo<X: K<_, _>>(x: X) {}
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn bar<F>(_: F) where F: Fn() -> _ {}
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn baz<F: Fn() -> _>(_: F) {}
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 struct L<F>(F) where F: Fn() -> _;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
 struct M<F> where F: Fn() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
     a: F,
 }
 enum N<F> where F: Fn() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for enums
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for enums
     Foo(F),
 }
 
 union O<F> where F: Fn() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for unions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for unions
     foo: F,
 }
 
 trait P<F> where F: Fn() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for traits
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for traits
 }
 
 trait Q {
     fn foo<F>(_: F) where F: Fn() -> _ {}
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 }
 
 fn main() {}
index 11514a28b2ca591394f48eb58de8c0ed388bcaec..2326af934d014d509809643d24a0b50f2c1df214 100644 (file)
@@ -81,7 +81,7 @@ error[E0223]: ambiguous associated type
 LL | type D = (u8, u8)::AssocTy;
    |          ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(u8, u8) as Trait>::AssocTy`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for type aliases
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases
   --> $DIR/bad-assoc-ty.rs:17:10
    |
 LL | type E = _::AssocTy;
@@ -136,7 +136,7 @@ error[E0223]: ambiguous associated type
 LL | type I = ty!()::AssocTy;
    |          ^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<u8 as Trait>::AssocTy`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/bad-assoc-ty.rs:51:13
    |
 LL | fn foo<X: K<_, _>>(x: X) {}
@@ -149,7 +149,7 @@ help: use type parameters instead
 LL | fn foo<X: K<T, T>, T>(x: X) {}
    |             ~  ~ +++
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/bad-assoc-ty.rs:54:34
    |
 LL | fn bar<F>(_: F) where F: Fn() -> _ {}
@@ -160,7 +160,7 @@ help: use type parameters instead
 LL | fn bar<F, T>(_: F) where F: Fn() -> T {}
    |         +++                         ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/bad-assoc-ty.rs:57:19
    |
 LL | fn baz<F: Fn() -> _>(_: F) {}
@@ -171,7 +171,7 @@ help: use type parameters instead
 LL | fn baz<F: Fn() -> T, T>(_: F) {}
    |                   ~+++
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/bad-assoc-ty.rs:60:33
    |
 LL | struct L<F>(F) where F: Fn() -> _;
@@ -182,7 +182,7 @@ help: use type parameters instead
 LL | struct L<F, T>(F) where F: Fn() -> T;
    |           +++                      ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/bad-assoc-ty.rs:62:30
    |
 LL | struct M<F> where F: Fn() -> _ {
@@ -193,7 +193,7 @@ help: use type parameters instead
 LL | struct M<F, T> where F: Fn() -> T {
    |           +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for enums
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for enums
   --> $DIR/bad-assoc-ty.rs:66:28
    |
 LL | enum N<F> where F: Fn() -> _ {
@@ -204,7 +204,7 @@ help: use type parameters instead
 LL | enum N<F, T> where F: Fn() -> T {
    |         +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for unions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for unions
   --> $DIR/bad-assoc-ty.rs:71:29
    |
 LL | union O<F> where F: Fn() -> _ {
@@ -215,7 +215,7 @@ help: use type parameters instead
 LL | union O<F, T> where F: Fn() -> T {
    |          +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for traits
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for traits
   --> $DIR/bad-assoc-ty.rs:76:29
    |
 LL | trait P<F> where F: Fn() -> _ {
@@ -226,7 +226,7 @@ help: use type parameters instead
 LL | trait P<F, T> where F: Fn() -> T {
    |          +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/bad-assoc-ty.rs:81:38
    |
 LL |     fn foo<F>(_: F) where F: Fn() -> _ {}
index fb6b6a5673d90ec59711df4b53a715fb5b5ee7d6..a70dda8386f087ef1ab460614255b8780035228a 100644 (file)
@@ -3,6 +3,10 @@ enum Hey<A, B> {
     B(B),
 }
 
+struct Foo {
+    bar: Option<i32>,
+}
+
 fn f() {}
 
 fn a() -> Option<()> {
@@ -40,4 +44,8 @@ fn main() {
     let _: Hey<i32, bool> = false;
     //~^ ERROR mismatched types
     //~| HELP try wrapping
+    let bar = 1i32;
+    let _ = Foo { bar };
+    //~^ ERROR mismatched types
+    //~| HELP try wrapping
 }
index e77949687fcb2035bed74253e028ea6a0ae479ac..0dfd8f5c128f6a0f614b4eb1c9f9da0944a80ed0 100644 (file)
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:9:5
+  --> $DIR/compatible-variants.rs:13:5
    |
 LL |   fn a() -> Option<()> {
    |             ---------- expected `Option<()>` because of return type
@@ -21,7 +21,7 @@ LL +     Some(())
    |
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:17:5
+  --> $DIR/compatible-variants.rs:21:5
    |
 LL | fn b() -> Result<(), ()> {
    |           -------------- expected `Result<(), ()>` because of return type
@@ -37,7 +37,7 @@ LL +     Ok(())
    |
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:23:25
+  --> $DIR/compatible-variants.rs:27:25
    |
 LL |     let _: Option<()> = while false {};
    |            ----------   ^^^^^^^^^^^^^^ expected enum `Option`, found `()`
@@ -52,7 +52,7 @@ LL |     let _: Option<()> = Some(while false {});
    |                         +++++              +
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:27:9
+  --> $DIR/compatible-variants.rs:31:9
    |
 LL |         while false {}
    |         ^^^^^^^^^^^^^^ expected enum `Option`, found `()`
@@ -69,7 +69,7 @@ LL +         Some(())
    |
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:31:31
+  --> $DIR/compatible-variants.rs:35:31
    |
 LL |     let _: Result<i32, i32> = 1;
    |            ----------------   ^ expected enum `Result`, found integer
@@ -86,7 +86,7 @@ LL |     let _: Result<i32, i32> = Err(1);
    |                               ++++ +
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:34:26
+  --> $DIR/compatible-variants.rs:38:26
    |
 LL |     let _: Option<i32> = 1;
    |            -----------   ^ expected enum `Option`, found integer
@@ -101,7 +101,7 @@ LL |     let _: Option<i32> = Some(1);
    |                          +++++ +
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:37:28
+  --> $DIR/compatible-variants.rs:41:28
    |
 LL |     let _: Hey<i32, i32> = 1;
    |            -------------   ^ expected enum `Hey`, found integer
@@ -118,7 +118,7 @@ LL |     let _: Hey<i32, i32> = Hey::B(1);
    |                            +++++++ +
 
 error[E0308]: mismatched types
-  --> $DIR/compatible-variants.rs:40:29
+  --> $DIR/compatible-variants.rs:44:29
    |
 LL |     let _: Hey<i32, bool> = false;
    |            --------------   ^^^^^ expected enum `Hey`, found `bool`
@@ -132,6 +132,19 @@ help: try wrapping the expression in `Hey::B`
 LL |     let _: Hey<i32, bool> = Hey::B(false);
    |                             +++++++     +
 
-error: aborting due to 8 previous errors
+error[E0308]: mismatched types
+  --> $DIR/compatible-variants.rs:48:19
+   |
+LL |     let _ = Foo { bar };
+   |                   ^^^ expected enum `Option`, found `i32`
+   |
+   = note: expected enum `Option<i32>`
+              found type `i32`
+help: try wrapping the expression in `Some`
+   |
+LL |     let _ = Foo { bar: Some(bar) };
+   |                   ++++++++++   +
+
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
index d2938435ece31b0ae435d0b714ddfaa9ee51193d..d0249efd094ffd5790382203e31222f1ee2bd88c 100644 (file)
@@ -4,7 +4,7 @@ error: comparison operators cannot be chained
 LL |     (0..13).collect<Vec<i32>>();
    |                    ^   ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     (0..13).collect::<Vec<i32>>();
    |                    ++
@@ -15,7 +15,7 @@ error: comparison operators cannot be chained
 LL |     Vec<i32>::new();
    |        ^   ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     Vec::<i32>::new();
    |        ++
@@ -26,7 +26,7 @@ error: comparison operators cannot be chained
 LL |     (0..13).collect<Vec<i32>();
    |                    ^   ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     (0..13).collect::<Vec<i32>();
    |                    ++
@@ -37,7 +37,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, fo
 LL |     let x = std::collections::HashMap<i128, i128>::new();
    |                                           ^ expected one of 8 possible tokens
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     let x = std::collections::HashMap::<i128, i128>::new();
    |                                      ++
@@ -48,7 +48,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
 LL |         std::collections::HashMap<i128, i128>::new()
    |                                       ^ expected one of 8 possible tokens
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |         std::collections::HashMap::<i128, i128>::new()
    |                                  ++
@@ -59,7 +59,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
 LL |         std::collections::HashMap<i128, i128>::new();
    |                                       ^ expected one of 8 possible tokens
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |         std::collections::HashMap::<i128, i128>::new();
    |                                  ++
@@ -70,7 +70,7 @@ error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found
 LL |         std::collections::HashMap<i128, i128>::new(1, 2);
    |                                       ^ expected one of 8 possible tokens
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |         std::collections::HashMap::<i128, i128>::new(1, 2);
    |                                  ++
index cc0c2df72ea7ccbf3c90fb041c9c033950861951..023d7e011bf3a0e7521495c838abcdfefabc4026 100644 (file)
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/E0121.rs:1:13
    |
 LL | fn foo() -> _ { 5 }
@@ -7,7 +7,7 @@ LL | fn foo() -> _ { 5 }
    |             not allowed in type signatures
    |             help: replace with the correct return type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/E0121.rs:3:13
    |
 LL | static BAR: _ = "test";
diff --git a/src/test/ui/error-codes/E0660.rs b/src/test/ui/error-codes/E0660.rs
deleted file mode 100644 (file)
index 43af240..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    let a;
-    llvm_asm!("nop" "nop");
-    //~^ ERROR E0660
-    llvm_asm!("nop" "nop" : "=r"(a));
-    //~^ ERROR E0660
-}
diff --git a/src/test/ui/error-codes/E0660.stderr b/src/test/ui/error-codes/E0660.stderr
deleted file mode 100644 (file)
index d9d2f35..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0660]: malformed inline assembly
-  --> $DIR/E0660.rs:6:5
-   |
-LL |     llvm_asm!("nop" "nop");
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0660]: malformed inline assembly
-  --> $DIR/E0660.rs:8:5
-   |
-LL |     llvm_asm!("nop" "nop" : "=r"(a));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0660`.
diff --git a/src/test/ui/error-codes/E0661.rs b/src/test/ui/error-codes/E0661.rs
deleted file mode 100644 (file)
index 854675c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    let a; //~ ERROR type annotations needed
-    llvm_asm!("nop" : "r"(a));
-    //~^ ERROR E0661
-}
diff --git a/src/test/ui/error-codes/E0661.stderr b/src/test/ui/error-codes/E0661.stderr
deleted file mode 100644 (file)
index 73745ef..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0661]: output operand constraint lacks '=' or '+'
-  --> $DIR/E0661.rs:8:23
-   |
-LL |     llvm_asm!("nop" : "r"(a));
-   |                       ^^^
-
-error[E0282]: type annotations needed
-  --> $DIR/E0661.rs:7:9
-   |
-LL |     let a;
-   |         ^ consider giving `a` a type
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0282, E0661.
-For more information about an error, try `rustc --explain E0282`.
diff --git a/src/test/ui/error-codes/E0662.rs b/src/test/ui/error-codes/E0662.rs
deleted file mode 100644 (file)
index 679a88c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    llvm_asm!("xor %eax, %eax"
-              :
-              : "=test"("a") //~ ERROR E0662
-             );
-}
diff --git a/src/test/ui/error-codes/E0662.stderr b/src/test/ui/error-codes/E0662.stderr
deleted file mode 100644 (file)
index f6695d7..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0662]: input operand constraint contains '='
-  --> $DIR/E0662.rs:9:17
-   |
-LL |               : "=test"("a")
-   |                 ^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0662`.
diff --git a/src/test/ui/error-codes/E0663.rs b/src/test/ui/error-codes/E0663.rs
deleted file mode 100644 (file)
index b82f1ad..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    llvm_asm!("xor %eax, %eax"
-              :
-              : "+test"("a") //~ ERROR E0663
-             );
-}
diff --git a/src/test/ui/error-codes/E0663.stderr b/src/test/ui/error-codes/E0663.stderr
deleted file mode 100644 (file)
index 5f8dede..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0663]: input operand constraint contains '+'
-  --> $DIR/E0663.rs:9:17
-   |
-LL |               : "+test"("a")
-   |                 ^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0663`.
diff --git a/src/test/ui/error-codes/E0664.rs b/src/test/ui/error-codes/E0664.rs
deleted file mode 100644 (file)
index d2730f0..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    llvm_asm!("mov $$0x200, %eax"
-              :
-              :
-              : "{eax}" //~ ERROR E0664
-             );
-}
diff --git a/src/test/ui/error-codes/E0664.stderr b/src/test/ui/error-codes/E0664.stderr
deleted file mode 100644 (file)
index 5e6836f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0664]: clobber should not be surrounded by braces
-  --> $DIR/E0664.rs:10:17
-   |
-LL |               : "{eax}"
-   |                 ^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0664`.
index 5237a9ff3961a060c3d459f0e985bddc2bad9a16..2cd8731141af752a8b65559c9155948f6b47eeb2 100644 (file)
@@ -1,6 +1,6 @@
 // check-pass
 
-#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete
+#![feature(let_chains)]
 
 #[cfg(FALSE)]
 fn foo() {
diff --git a/src/test/ui/expr/if/attrs/let-chains-attr.stderr b/src/test/ui/expr/if/attrs/let-chains-attr.stderr
deleted file mode 100644 (file)
index 8b98747..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/let-chains-attr.rs:3:12
-   |
-LL | #![feature(let_chains)]
-   |            ^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-
-warning: 1 warning emitted
-
diff --git a/src/test/ui/feature-gates/feature-gate-asm.rs b/src/test/ui/feature-gates/feature-gate-asm.rs
deleted file mode 100644 (file)
index 556219b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// only-x86_64
-
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    unsafe {
-        llvm_asm!("");
-        //~^ ERROR prefer using the new asm! syntax instead
-    }
-}
diff --git a/src/test/ui/feature-gates/feature-gate-asm.stderr b/src/test/ui/feature-gates/feature-gate-asm.stderr
deleted file mode 100644 (file)
index 72ba70d..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: use of unstable library feature 'llvm_asm': prefer using the new asm! syntax instead
-  --> $DIR/feature-gate-asm.rs:7:9
-   |
-LL |         llvm_asm!("");
-   |         ^^^^^^^^
-   |
-   = note: see issue #70173 <https://github.com/rust-lang/rust/issues/70173> for more information
-   = help: add `#![feature(llvm_asm)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-asm2.rs b/src/test/ui/feature-gates/feature-gate-asm2.rs
deleted file mode 100644 (file)
index 712e3a5..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// only-x86_64
-
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    unsafe {
-        println!("{:?}", llvm_asm!(""));
-        //~^ ERROR prefer using the new asm! syntax instead
-    }
-}
diff --git a/src/test/ui/feature-gates/feature-gate-asm2.stderr b/src/test/ui/feature-gates/feature-gate-asm2.stderr
deleted file mode 100644 (file)
index 0297fec..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: use of unstable library feature 'llvm_asm': prefer using the new asm! syntax instead
-  --> $DIR/feature-gate-asm2.rs:7:26
-   |
-LL |         println!("{:?}", llvm_asm!(""));
-   |                          ^^^^^^^^
-   |
-   = note: see issue #70173 <https://github.com/rust-lang/rust/issues/70173> for more information
-   = help: add `#![feature(llvm_asm)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-associated_const_equality.rs b/src/test/ui/feature-gates/feature-gate-associated_const_equality.rs
new file mode 100644 (file)
index 0000000..b51ead2
--- /dev/null
@@ -0,0 +1,16 @@
+pub trait TraitWAssocConst {
+  const A: usize;
+}
+pub struct Demo {}
+
+impl TraitWAssocConst for Demo {
+  const A: usize = 32;
+}
+
+fn foo<A: TraitWAssocConst<A=32>>() {}
+//~^ ERROR associated const equality
+//~| ERROR associated const equality
+
+fn main() {
+  foo::<Demo>();
+}
diff --git a/src/test/ui/feature-gates/feature-gate-associated_const_equality.stderr b/src/test/ui/feature-gates/feature-gate-associated_const_equality.stderr
new file mode 100644 (file)
index 0000000..f4db49c
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0658]: associated const equality is incomplete
+  --> $DIR/feature-gate-associated_const_equality.rs:10:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {}
+   |                            ^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
+
+error: associated const equality is incomplete
+  --> $DIR/feature-gate-associated_const_equality.rs:10:28
+   |
+LL | fn foo<A: TraitWAssocConst<A=32>>() {}
+   |                            ^^^^ cannot yet relate associated const
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
index f26514939800a0023316753110d62027106f54df..d005dc3ad456dc4c16afbd64794da7b4bf1a1d19 100644 (file)
@@ -1,7 +1,9 @@
 #[cfg(target_abi = "x")] //~ ERROR `cfg(target_abi)` is experimental
-#[cfg_attr(target_abi = "x", x)] //~ ERROR `cfg(target_abi)` is experimental
 struct Foo(u64, u64);
 
+#[cfg_attr(target_abi = "x", x)] //~ ERROR `cfg(target_abi)` is experimental
+struct Bar(u64, u64);
+
 #[cfg(not(any(all(target_abi = "x"))))] //~ ERROR `cfg(target_abi)` is experimental
 fn foo() {}
 
index ed8cbcbe4f017ffb4cbfdf9b631101a4399ef609..013705d4886deae884ce52fe6cb6d5292b5300a5 100644 (file)
@@ -1,23 +1,23 @@
 error[E0658]: `cfg(target_abi)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-abi.rs:2:12
+  --> $DIR/feature-gate-cfg-target-abi.rs:1:7
    |
-LL | #[cfg_attr(target_abi = "x", x)]
-   |            ^^^^^^^^^^^^^^^^
+LL | #[cfg(target_abi = "x")]
+   |       ^^^^^^^^^^^^^^^^
    |
    = note: see issue #80970 <https://github.com/rust-lang/rust/issues/80970> for more information
    = help: add `#![feature(cfg_target_abi)]` to the crate attributes to enable
 
 error[E0658]: `cfg(target_abi)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-abi.rs:1:7
+  --> $DIR/feature-gate-cfg-target-abi.rs:4:12
    |
-LL | #[cfg(target_abi = "x")]
-   |       ^^^^^^^^^^^^^^^^
+LL | #[cfg_attr(target_abi = "x", x)]
+   |            ^^^^^^^^^^^^^^^^
    |
    = note: see issue #80970 <https://github.com/rust-lang/rust/issues/80970> for more information
    = help: add `#![feature(cfg_target_abi)]` to the crate attributes to enable
 
 error[E0658]: `cfg(target_abi)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-abi.rs:5:19
+  --> $DIR/feature-gate-cfg-target-abi.rs:7:19
    |
 LL | #[cfg(not(any(all(target_abi = "x"))))]
    |                   ^^^^^^^^^^^^^^^^
@@ -26,7 +26,7 @@ LL | #[cfg(not(any(all(target_abi = "x"))))]
    = help: add `#![feature(cfg_target_abi)]` to the crate attributes to enable
 
 error[E0658]: `cfg(target_abi)` is experimental and subject to change
-  --> $DIR/feature-gate-cfg-target-abi.rs:9:10
+  --> $DIR/feature-gate-cfg-target-abi.rs:11:10
    |
 LL |     cfg!(target_abi = "x");
    |          ^^^^^^^^^^^^^^^^
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
    |
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.rs
deleted file mode 100644 (file)
index 33f9c53..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// gate-test-raw_dylib
-// only-windows-gnu
-#[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: kind="raw-dylib" is unstable
-//~| WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
-extern "C" {}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-gnu.stderr
deleted file mode 100644 (file)
index 14dfadf..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
-  --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1
-   |
-LL | #[link(name = "foo", kind = "raw-dylib")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0658]: kind="raw-dylib" is unstable
-  --> $DIR/feature-gate-raw-dylib-windows-gnu.rs:3:1
-   |
-LL | #[link(name = "foo", kind = "raw-dylib")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.rs
deleted file mode 100644 (file)
index 49de24e..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-// gate-test-raw_dylib
-// only-windows-msvc
-#[link(name = "foo", kind = "raw-dylib")]
-//~^ ERROR: kind="raw-dylib" is unstable
-extern "C" {}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib-windows-msvc.stderr
deleted file mode 100644 (file)
index 1198808..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: kind="raw-dylib" is unstable
-  --> $DIR/feature-gate-raw-dylib-windows-msvc.rs:3:1
-   |
-LL | #[link(name = "foo", kind = "raw-dylib")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib.rs b/src/test/ui/feature-gates/feature-gate-raw-dylib.rs
new file mode 100644 (file)
index 0000000..995d9ce
--- /dev/null
@@ -0,0 +1,6 @@
+// only-windows
+#[link(name = "foo", kind = "raw-dylib")]
+//~^ ERROR: kind="raw-dylib" is unstable
+extern "C" {}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-raw-dylib.stderr b/src/test/ui/feature-gates/feature-gate-raw-dylib.stderr
new file mode 100644 (file)
index 0000000..bb64af3
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: kind="raw-dylib" is unstable
+  --> $DIR/feature-gate-raw-dylib.rs:2:1
+   |
+LL | #[link(name = "foo", kind = "raw-dylib")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+   = help: add `#![feature(raw_dylib)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
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
 
index 1ddf8508cc8ccf9e42649de3cc076d8715d05ba6..ed382406efacf7d8a9cbee69cc593760bca33275 100644 (file)
@@ -1,6 +1,7 @@
 //~ NOTE not a function
-//~^ NOTE not a foreign function or static
-//~^^ NOTE not a function or static
+//~| NOTE not a foreign function or static
+//~| NOTE not a function or static
+//~| NOTE not an `extern` block
 // This test enumerates as many compiler-builtin ungated attributes as
 // possible (that is, all the mutually compatible ones), and checks
 // that we get "expected" (*) warnings for each in the various weird
@@ -59,9 +60,9 @@
 #![proc_macro_derive()] //~ WARN `#[proc_macro_derive]` only has an effect
 #![doc = "2400"]
 #![cold] //~ WARN attribute should be applied to a function
-//~^ WARN
-// see issue-43106-gating-of-builtin-attrs-error.rs
-#![link()]
+//~^ WARN this was previously accepted
+#![link()] //~ WARN attribute should be applied to an `extern` block
+//~^ WARN this was previously accepted
 #![link_name = "1900"]
 //~^ WARN attribute should be applied to a foreign function
 //~^^ WARN this was previously accepted by the compiler
@@ -547,22 +548,38 @@ mod inner { #![link_section="1800"] }
 }
 
 
-// Note that this is a `check-pass` test, so it
-// will never invoke the linker. These are here nonetheless to point
-// out that we allow them at non-crate-level (though I do not know
-// whether they have the same effect here as at crate-level).
+// Note that this is a `check-pass` test, so it will never invoke the linker.
 
 #[link()]
+//~^ WARN attribute should be applied to an `extern` block
+//~| WARN this was previously accepted
 mod link {
+    //~^ NOTE not an `extern` block
+
     mod inner { #![link()] }
+    //~^ WARN attribute should be applied to an `extern` block
+    //~| WARN this was previously accepted
+    //~| NOTE not an `extern` block
 
     #[link()] fn f() { }
+    //~^ WARN attribute should be applied to an `extern` block
+    //~| WARN this was previously accepted
+    //~| NOTE not an `extern` block
 
     #[link()] struct S;
+    //~^ WARN attribute should be applied to an `extern` block
+    //~| WARN this was previously accepted
+    //~| NOTE not an `extern` block
 
     #[link()] type T = S;
+    //~^ WARN attribute should be applied to an `extern` block
+    //~| WARN this was previously accepted
+    //~| NOTE not an `extern` block
 
     #[link()] impl S { }
+    //~^ WARN attribute should be applied to an `extern` block
+    //~| WARN this was previously accepted
+    //~| NOTE not an `extern` block
 }
 
 struct StructForDeprecated;
@@ -594,16 +611,22 @@ mod inner { #![must_use] }
 }
 
 #[windows_subsystem = "windows"]
+//~^ WARN crate-level attribute should be an inner attribute
 mod windows_subsystem {
     mod inner { #![windows_subsystem="windows"] }
+    //~^ WARN crate-level attribute should be in the root module
 
     #[windows_subsystem = "windows"] fn f() { }
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[windows_subsystem = "windows"] struct S;
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[windows_subsystem = "windows"] type T = S;
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[windows_subsystem = "windows"] impl S { }
+    //~^ WARN crate-level attribute should be an inner attribute
 }
 
 // BROKEN USES OF CRATE-LEVEL BUILT-IN ATTRIBUTES
@@ -686,16 +709,22 @@ mod inner { #![no_main] }
 }
 
 #[no_builtins]
+//~^ WARN crate-level attribute should be an inner attribute
 mod no_builtins {
     mod inner { #![no_builtins] }
+    //~^ WARN crate-level attribute should be in the root module
 
     #[no_builtins] fn f() { }
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[no_builtins] struct S;
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[no_builtins] type T = S;
+    //~^ WARN crate-level attribute should be an inner attribute
 
     #[no_builtins] impl S { }
+    //~^ WARN crate-level attribute should be an inner attribute
 }
 
 #[recursion_limit="0200"]
index b98374bfa80ccc4de89cad9b00452b583b3f00c5..bd3e33320c38452741e34239f31c6251da0f3b7f 100644 (file)
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:9
    |
 LL | #![warn(x5400)]
    |         ^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:39:28
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:28
    |
 LL | #![warn(unused_attributes, unknown_lints)]
    |                            ^^^^^^^^^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:10
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:10
    |
 LL | #![allow(x5300)]
    |          ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:11
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:11
    |
 LL | #![forbid(x5200)]
    |           ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:49:9
    |
 LL | #![deny(x5100)]
    |         ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:104:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:8
    |
 LL | #[warn(x5400)]
    |        ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:107:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:108:25
    |
 LL |     mod inner { #![warn(x5400)] }
    |                         ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:110:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:12
    |
 LL |     #[warn(x5400)] fn f() { }
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:113:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:114:12
    |
 LL |     #[warn(x5400)] struct S;
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:117:12
    |
 LL |     #[warn(x5400)] type T = S;
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:120:12
    |
 LL |     #[warn(x5400)] impl S { }
    |            ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:123:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:9
    |
 LL | #[allow(x5300)]
    |         ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:126:26
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:127:26
    |
 LL |     mod inner { #![allow(x5300)] }
    |                          ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:129:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:13
    |
 LL |     #[allow(x5300)] fn f() { }
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:132:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:133:13
    |
 LL |     #[allow(x5300)] struct S;
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:136:13
    |
 LL |     #[allow(x5300)] type T = S;
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:139:13
    |
 LL |     #[allow(x5300)] impl S { }
    |             ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:142:10
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:10
    |
 LL | #[forbid(x5200)]
    |          ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:145:27
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:146:27
    |
 LL |     mod inner { #![forbid(x5200)] }
    |                           ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:148:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:14
    |
 LL |     #[forbid(x5200)] fn f() { }
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:151:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:152:14
    |
 LL |     #[forbid(x5200)] struct S;
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:155:14
    |
 LL |     #[forbid(x5200)] type T = S;
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:158:14
    |
 LL |     #[forbid(x5200)] impl S { }
    |              ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:161:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:8
    |
 LL | #[deny(x5100)]
    |        ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:164:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:165:25
    |
 LL |     mod inner { #![deny(x5100)] }
    |                         ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:167:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:12
    |
 LL |     #[deny(x5100)] fn f() { }
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:170:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:171:12
    |
 LL |     #[deny(x5100)] struct S;
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:174:12
    |
 LL |     #[deny(x5100)] type T = S;
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:12
    |
 LL |     #[deny(x5100)] impl S { }
    |            ^^^^^
 
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:399:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:400:17
    |
 LL |     mod inner { #![macro_escape] }
    |                 ^^^^^^^^^^^^^^^^
@@ -181,13 +181,13 @@ LL |     mod inner { #![macro_escape] }
    = help: try an outer attribute: `#[macro_use]`
 
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:396:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:397:1
    |
 LL | #[macro_escape]
    | ^^^^^^^^^^^^^^^
 
 warning: use of deprecated attribute `crate_id`: no longer used.
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:83:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:84:1
    |
 LL | #![crate_id = "10"]
    | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute
@@ -195,31 +195,31 @@ LL | #![crate_id = "10"]
    = note: `#[warn(deprecated)]` on by default
 
 warning: use of deprecated attribute `no_start`: no longer used.
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:93:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:94:1
    |
 LL | #![no_start]
    | ^^^^^^^^^^^^ help: remove this attribute
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:197:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:1
    |
 LL | #[macro_export]
    | ^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:39:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:9
    |
 LL | #![warn(unused_attributes, unknown_lints)]
    |         ^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on items
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:265:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:283:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:284:1
    |
 LL |   #[no_mangle]
    |   ^^^^^^^^^^^^
@@ -236,31 +236,31 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:323:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:324:1
    |
 LL | #[should_panic]
    | ^^^^^^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:1
    |
 LL | #[ignore]
    | ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:1
    |
 LL | #[reexport_test_harness_main = "2900"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:416:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:1
    |
 LL | #[no_std]
    | ^^^^^^^^^
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:453:1
    |
 LL |   #[cold]
    |   ^^^^^^^
@@ -277,7 +277,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:481:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:1
    |
 LL |   #[link_name = "1900"]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -294,7 +294,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:520:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:521:1
    |
 LL |   #[link_section = "1800"]
    |   ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -310,70 +310,107 @@ LL | | }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:553:1
+   |
+LL |   #[link()]
+   |   ^^^^^^^^^
+...
+LL | / mod link {
+LL | |
+LL | |
+LL | |     mod inner { #![link()] }
+...  |
+LL | |
+LL | | }
+   | |_- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:613:1
+   |
+LL | #[windows_subsystem = "windows"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:1
    |
 LL | #[crate_name = "0900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:630:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:653:1
    |
 LL | #[crate_type = "0800"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:1
    |
 LL | #[feature(x0600)]
    | ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:692:1
    |
 LL | #[no_main]
    | ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:711:1
+   |
+LL | #[no_builtins]
+   | ^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:730:1
    |
 LL | #[recursion_limit="0200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:1
    |
 LL | #[type_length_limit="0100"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:52:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1
    |
 LL | #![should_panic]
    | ^^^^^^^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1
    |
 LL | #![ignore]
    | ^^^^^^^^^^
 
 warning: `#[proc_macro_derive]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1
    |
 LL | #![proc_macro_derive()]
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:61:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
    |
 LL | #![cold]
    | ^^^^^^^^
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1
+   |
+LL | #![link()]
+   | ^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1
    |
 LL | #![link_name = "1900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -381,7 +418,7 @@ LL | #![link_name = "1900"]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:68:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1
    |
 LL | #![link_section = "1800"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -389,109 +426,109 @@ LL | #![link_section = "1800"]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:184:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:5
    |
 LL |     #[macro_use] fn f() { }
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:187:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:5
    |
 LL |     #[macro_use] struct S;
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5
    |
 LL |     #[macro_use] type T = S;
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:193:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:194:5
    |
 LL |     #[macro_use] impl S { }
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:200:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:17
    |
 LL |     mod inner { #![macro_export] }
    |                 ^^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:203:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:5
    |
 LL |     #[macro_export] fn f() { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:206:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:207:5
    |
 LL |     #[macro_export] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:210:5
    |
 LL |     #[macro_export] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:213:5
    |
 LL |     #[macro_export] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:252:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:253:5
    |
 LL |     #[path = "3800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:255:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:256:5
    |
 LL |     #[path = "3800"]  struct S;
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:259:5
    |
 LL |     #[path = "3800"] type T = S;
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:261:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:262:5
    |
 LL |     #[path = "3800"] impl S { }
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on items
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:268:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:17
    |
 LL |     mod inner { #![automatically_derived] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on items
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:271:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5
    |
 LL |     #[automatically_derived] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on items
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:274:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5
    |
 LL |     #[automatically_derived] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on items
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:277:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:278:5
    |
 LL |     #[automatically_derived] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:288:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:289:17
    |
 LL |     mod inner { #![no_mangle] }
    |     ------------^^^^^^^^^^^^^-- not a free function, impl method or static
@@ -499,7 +536,7 @@ LL |     mod inner { #![no_mangle] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:295:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:296:5
    |
 LL |     #[no_mangle] struct S;
    |     ^^^^^^^^^^^^ --------- not a free function, impl method or static
@@ -507,7 +544,7 @@ LL |     #[no_mangle] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:300:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:301:5
    |
 LL |     #[no_mangle] type T = S;
    |     ^^^^^^^^^^^^ ----------- not a free function, impl method or static
@@ -515,7 +552,7 @@ LL |     #[no_mangle] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:305:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:306:5
    |
 LL |     #[no_mangle] impl S { }
    |     ^^^^^^^^^^^^ ---------- not a free function, impl method or static
@@ -523,7 +560,7 @@ LL |     #[no_mangle] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:311:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:312:9
    |
 LL |         #[no_mangle] fn foo();
    |         ^^^^^^^^^^^^ --------- not a free function, impl method or static
@@ -531,7 +568,7 @@ LL |         #[no_mangle] fn foo();
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:316:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:317:9
    |
 LL |         #[no_mangle] fn bar() {}
    |         ^^^^^^^^^^^^ ----------- not a free function, impl method or static
@@ -539,163 +576,163 @@ LL |         #[no_mangle] fn bar() {}
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:326:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:327:17
    |
 LL |     mod inner { #![should_panic] }
    |                 ^^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:331:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5
    |
 LL |     #[should_panic] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:334:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5
    |
 LL |     #[should_panic] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:337:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:5
    |
 LL |     #[should_panic] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:345:17
    |
 LL |     mod inner { #![ignore] }
    |                 ^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:349:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5
    |
 LL |     #[ignore] struct S;
    |     ^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:352:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5
    |
 LL |     #[ignore] type T = S;
    |     ^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:356:5
    |
 LL |     #[ignore] impl S { }
    |     ^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:363:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5
    |
 LL |     #[no_implicit_prelude] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:366:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5
    |
 LL |     #[no_implicit_prelude] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:369:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5
    |
 LL |     #[no_implicit_prelude] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:372:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:5
    |
 LL |     #[no_implicit_prelude] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:17
    |
 LL |     mod inner { #![reexport_test_harness_main="2900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:382:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:5
    |
 LL |     #[reexport_test_harness_main = "2900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5
    |
 LL |     #[reexport_test_harness_main = "2900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:388:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5
    |
 LL |     #[reexport_test_harness_main = "2900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:5
    |
 LL |     #[reexport_test_harness_main = "2900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:403:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5
    |
 LL |     #[macro_escape] fn f() { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:406:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:5
    |
 LL |     #[macro_escape] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:409:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:410:5
    |
 LL |     #[macro_escape] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:412:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:413:5
    |
 LL |     #[macro_escape] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:419:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:17
    |
 LL |     mod inner { #![no_std] }
    |                 ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:422:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5
    |
 LL |     #[no_std] fn f() { }
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:425:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5
    |
 LL |     #[no_std] struct S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:428:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:429:5
    |
 LL |     #[no_std] type T = S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:431:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:432:5
    |
 LL |     #[no_std] impl S { }
    |     ^^^^^^^^^
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:17
    |
 LL |     mod inner { #![cold] }
    |     ------------^^^^^^^^-- not a function
@@ -703,7 +740,7 @@ LL |     mod inner { #![cold] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:465:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:5
    |
 LL |     #[cold] struct S;
    |     ^^^^^^^ --------- not a function
@@ -711,7 +748,7 @@ LL |     #[cold] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:470:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5
    |
 LL |     #[cold] type T = S;
    |     ^^^^^^^ ----------- not a function
@@ -719,7 +756,7 @@ LL |     #[cold] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:476:5
    |
 LL |     #[cold] impl S { }
    |     ^^^^^^^ ---------- not a function
@@ -727,7 +764,7 @@ LL |     #[cold] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -737,13 +774,13 @@ LL |     extern "C" { }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 help: try `#[link(name = "1900")]` instead
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:487:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:488:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:494:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:17
    |
 LL |     mod inner { #![link_name="1900"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static
@@ -751,7 +788,7 @@ LL |     mod inner { #![link_name="1900"] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:500:5
    |
 LL |     #[link_name = "1900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static
@@ -759,7 +796,7 @@ LL |     #[link_name = "1900"] fn f() { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:504:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5
    |
 LL |     #[link_name = "1900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static
@@ -767,7 +804,7 @@ LL |     #[link_name = "1900"] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:509:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:510:5
    |
 LL |     #[link_name = "1900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static
@@ -775,7 +812,7 @@ LL |     #[link_name = "1900"] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:514:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5
    |
 LL |     #[link_name = "1900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static
@@ -783,7 +820,7 @@ LL |     #[link_name = "1900"] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:526:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:527:17
    |
 LL |     mod inner { #![link_section="1800"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static
@@ -791,7 +828,7 @@ LL |     mod inner { #![link_section="1800"] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:533:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:534:5
    |
 LL |     #[link_section = "1800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static
@@ -799,7 +836,7 @@ LL |     #[link_section = "1800"] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:538:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:539:5
    |
 LL |     #[link_section = "1800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static
@@ -807,200 +844,300 @@ LL |     #[link_section = "1800"] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:543:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:544:5
    |
 LL |     #[link_section = "1800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:17
+   |
+LL |     mod inner { #![link()] }
+   |     ------------^^^^^^^^^^-- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:564:5
+   |
+LL |     #[link()] fn f() { }
+   |     ^^^^^^^^^ ---------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:569:5
+   |
+LL |     #[link()] struct S;
+   |     ^^^^^^^^^ --------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:574:5
+   |
+LL |     #[link()] type T = S;
+   |     ^^^^^^^^^ ----------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+warning: attribute should be applied to an `extern` block
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:579:5
+   |
+LL |     #[link()] impl S { }
+   |     ^^^^^^^^^ ---------- not an `extern` block
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:616:17
+   |
+LL |     mod inner { #![windows_subsystem="windows"] }
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:5
+   |
+LL |     #[windows_subsystem = "windows"] fn f() { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:622:5
+   |
+LL |     #[windows_subsystem = "windows"] struct S;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:625:5
+   |
+LL |     #[windows_subsystem = "windows"] type T = S;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:628:5
+   |
+LL |     #[windows_subsystem = "windows"] impl S { }
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be in the root module
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:637:17
    |
 LL |     mod inner { #![crate_name="0900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:5
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:643:5
    |
 LL |     #[crate_name = "0900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5
    |
 LL |     #[crate_name = "0900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:5
    |
 LL |     #[crate_name = "0900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:633:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:17
    |
 LL |     mod inner { #![crate_type="0800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:636:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:5
    |
 LL |     #[crate_type = "0800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:639:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:662:5
    |
 LL |     #[crate_type = "0800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:642:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:5
    |
 LL |     #[crate_type = "0800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:645:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:5
    |
 LL |     #[crate_type = "0800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:17
    |
 LL |     mod inner { #![feature(x0600)] }
    |                 ^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:678:5
    |
 LL |     #[feature(x0600)] fn f() { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:658:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5
    |
 LL |     #[feature(x0600)] struct S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:661:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5
    |
 LL |     #[feature(x0600)] type T = S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:664:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:5
    |
 LL |     #[feature(x0600)] impl S { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:672:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:695:17
    |
 LL |     mod inner { #![no_main] }
    |                 ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:675:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:5
    |
 LL |     #[no_main] fn f() { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:678:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:5
    |
 LL |     #[no_main] struct S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5
    |
 LL |     #[no_main] type T = S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5
    |
 LL |     #[no_main] impl S { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:714:17
+   |
+LL |     mod inner { #![no_builtins] }
+   |                 ^^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:5
+   |
+LL |     #[no_builtins] fn f() { }
+   |     ^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5
+   |
+LL |     #[no_builtins] struct S;
+   |     ^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:5
+   |
+LL |     #[no_builtins] type T = S;
+   |     ^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5
+   |
+LL |     #[no_builtins] impl S { }
+   |     ^^^^^^^^^^^^^^
+
+warning: crate-level attribute should be in the root module
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:17
    |
 LL |     mod inner { #![recursion_limit="0200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:5
    |
 LL |     #[recursion_limit="0200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:5
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:752:17
    |
 LL |     mod inner { #![type_length_limit="0100"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:5
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5
    |
 LL |     #[type_length_limit="0100"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:5
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:735:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:89:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:90:12
    |
 LL | #![feature(rust1)]
    |            ^^^^^
    |
    = note: `#[warn(stable_features)]` on by default
 
-warning: 148 warnings emitted
+warning: 167 warnings emitted
 
index 550974bf7788157aa72a0a3d3197e43c4ef100bd..fcef6f1b60ecf6864a930bcdd576bfacd70be504 100644 (file)
@@ -8,7 +8,7 @@ fn returns_i32() -> i32 {
 }
 
 fn returns_fn_ptr() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types [E0121]
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
 //~| NOTE not allowed in type signatures
 //~| HELP replace with the correct return type
 //~| SUGGESTION fn() -> i32
@@ -16,7 +16,7 @@ fn returns_fn_ptr() -> _ {
 }
 
 fn returns_closure() -> _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types [E0121]
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types [E0121]
 //~| NOTE not allowed in type signatures
 //~| HELP consider using an `Fn`, `FnMut`, or `FnOnce` trait bound
 //~| NOTE for more information on `Fn` traits and closure types, see
index 96d0f02b01af4478c4c88ac656f0b7aefb2cee65..2ca4ae982d96f30bca872b276ae28812a37b36f7 100644 (file)
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-80179.rs:10:24
    |
 LL | fn returns_fn_ptr() -> _ {
@@ -7,7 +7,7 @@ LL | fn returns_fn_ptr() -> _ {
    |                        not allowed in type signatures
    |                        help: replace with the correct return type: `fn() -> i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-80179.rs:18:25
    |
 LL | fn returns_closure() -> _ {
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() {}
diff --git a/src/test/ui/generic-associated-types/issue-92096.migrate.stderr b/src/test/ui/generic-associated-types/issue-92096.migrate.stderr
new file mode 100644 (file)
index 0000000..72ade57
--- /dev/null
@@ -0,0 +1,18 @@
+error[E0311]: the parameter type `C` may not live long enough
+  --> $DIR/issue-92096.rs:20:33
+   |
+LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
+   |                 -               ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |                 |
+   |                 help: consider adding an explicit lifetime bound...: `C: 'a`
+
+error[E0311]: the parameter type `C` may not live long enough
+  --> $DIR/issue-92096.rs:20:33
+   |
+LL | fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
+   |                 -               ^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `C` will meet its required lifetime bounds
+   |                 |
+   |                 help: consider adding an explicit lifetime bound...: `C: 'a`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/generic-associated-types/issue-92096.rs b/src/test/ui/generic-associated-types/issue-92096.rs
new file mode 100644 (file)
index 0000000..066132a
--- /dev/null
@@ -0,0 +1,29 @@
+// edition:2018
+// [nll] check-pass
+// revisions: migrate nll
+// Explicitly testing nll with revision, so ignore compare-mode=nll
+// ignore-compare-mode-nll
+
+#![cfg_attr(nll, feature(nll))]
+#![feature(generic_associated_types)]
+
+use std::future::Future;
+
+trait Client {
+    type Connecting<'a>: Future + Send
+    where
+        Self: 'a;
+
+    fn connect(&'_ self) -> Self::Connecting<'_>;
+}
+
+fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send
+//[migrate]~^ ERROR the parameter
+//[migrate]~| ERROR the parameter
+where
+    C: Client + Send + Sync,
+{
+    async move { c.connect().await }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-92280.rs b/src/test/ui/generic-associated-types/issue-92280.rs
new file mode 100644 (file)
index 0000000..db26493
--- /dev/null
@@ -0,0 +1,26 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+#![allow(non_camel_case_types)]
+
+trait HasAssoc {
+    type Assoc;
+}
+
+trait Iterate<S: HasAssoc> {
+    type Iter<'a>
+    where
+        Self: 'a;
+}
+
+struct KeySegment_Broken<T> {
+    key: T,
+}
+impl<S: HasAssoc> Iterate<S> for KeySegment_Broken<S::Assoc> {
+    type Iter<'a>
+    where
+        Self: 'a,
+    = ();
+}
+
+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() {}
index da11ba204cb53870306fe67ca8d4b60231e2afc4..28c9afaa52c2299dbe987b84268e7e12628e5719 100644 (file)
@@ -87,7 +87,7 @@ LL |     let r = R { i };
 help: consider dereferencing the borrow
    |
 LL |     let r = R { i: *i };
-   |                 ~~~~~
+   |                 ++++
 
 error[E0308]: mismatched types
   --> $DIR/deref-suggestion.rs:46:20
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 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 6880e1a46293f99a204fcccada17fa1ff91ffd10..45a30857413b9df442e2b60a246e9e27603d923e 100644 (file)
@@ -4,7 +4,7 @@ macro_rules! suite {
             const A = "A".$fn();
             //~^ ERROR the name `A` is defined multiple times
             //~| ERROR missing type for `const` item
-            //~| ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+            //~| ERROR the placeholder `_` is not allowed within types on item signatures for constants
         )*
     }
 }
index 34c2073db0485f05a44b956f35609ad5c345816f..e5ab65169ce3bfad4818c90857a3d7f79b640207 100644 (file)
@@ -30,7 +30,7 @@ LL | | }
    |
    = note: this error originates in the macro `suite` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/issue-69396-const-no-type-in-macro.rs:4:19
    |
 LL |               const A = "A".$fn();
index 825fed5c722e0b57cdc3bcd48e685ce28f8dba82..780a6419c5f305ba60b94c10e04ce4e361a696f7 100644 (file)
@@ -2,7 +2,6 @@
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
 #![allow(non_snake_case)]
-#![allow(deprecated)] // llvm_asm!
 // ignore-pretty unreported
 
 #![feature(box_syntax)]
@@ -13,7 +12,6 @@ impl bomb for S { fn boom(&self, _: Ident) { } }
 
 pub struct Ident { name: usize }
 
-// macro_rules! int3 { () => ( unsafe { llvm_asm!( "int3" ); } ) }
 macro_rules! int3 { () => ( { } ) }
 
 fn Ident_new() -> Ident {
index a547f5af4b082e411f1692368ddbf8c13f6ce585..3b5683a7748fa86ff795d874ff069ac8cd88305a 100644 (file)
@@ -9,6 +9,12 @@ note: the lint level is defined here
    |
 LL | #![deny(dead_code)]
    |         ^^^^^^^^^
+note: `Enum` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis
+  --> $DIR/unused-variant.rs:3:10
+   |
+LL | #[derive(Clone)]
+   |          ^^^^^
+   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
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() {}
diff --git a/src/test/ui/llvm-asm/asm-src-loc-codegen-units.rs b/src/test/ui/llvm-asm/asm-src-loc-codegen-units.rs
deleted file mode 100644 (file)
index d178c65..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// build-fail
-// dont-check-compiler-stderr
-// compile-flags: -C codegen-units=2
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    unsafe {
-        llvm_asm!("nowayisthisavalidinstruction"); //~ ERROR instruction
-    }
-}
diff --git a/src/test/ui/llvm-asm/asm-src-loc.rs b/src/test/ui/llvm-asm/asm-src-loc.rs
deleted file mode 100644 (file)
index 4506c12..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// build-fail
-// dont-check-compiler-stderr
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    unsafe {
-        llvm_asm!("nowayisthisavalidinstruction"); //~ ERROR instruction
-    }
-}
diff --git a/src/test/ui/llvm-asm/inline-asm-bad-constraint.rs b/src/test/ui/llvm-asm/inline-asm-bad-constraint.rs
deleted file mode 100644 (file)
index 6a2ce11..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-// Test that the compiler will catch invalid inline assembly constraints.
-
-// build-fail
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-extern "C" {
-    fn foo(a: usize);
-}
-
-fn main() {
-    bad_register_constraint();
-    bad_input();
-    wrong_size_output();
-}
-
-// Issue #54130
-fn bad_register_constraint() {
-    let rax: u64;
-    unsafe {
-        llvm_asm!("" :"={rax"(rax)) //~ ERROR E0668
-    };
-    println!("Accumulator is: {}", rax);
-}
-
-// Issue #54376
-fn bad_input() {
-    unsafe {
-        llvm_asm!("callq $0" : : "0"(foo)) //~ ERROR E0668
-    };
-}
-
-fn wrong_size_output() {
-    let rax: u64 = 0;
-    unsafe {
-        llvm_asm!("addb $1, $0" : "={rax}"((0i32, rax))); //~ ERROR E0668
-    }
-    println!("rax: {}", rax);
-}
diff --git a/src/test/ui/llvm-asm/inline-asm-bad-constraint.stderr b/src/test/ui/llvm-asm/inline-asm-bad-constraint.stderr
deleted file mode 100644 (file)
index a624829..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-error[E0668]: malformed inline assembly
-  --> $DIR/inline-asm-bad-constraint.rs:23:9
-   |
-LL |         llvm_asm!("" :"={rax"(rax))
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0668]: malformed inline assembly
-  --> $DIR/inline-asm-bad-constraint.rs:31:9
-   |
-LL |         llvm_asm!("callq $0" : : "0"(foo))
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0668]: malformed inline assembly
-  --> $DIR/inline-asm-bad-constraint.rs:38:9
-   |
-LL |         llvm_asm!("addb $1, $0" : "={rax}"((0i32, rax)));
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0668`.
diff --git a/src/test/ui/llvm-asm/inline-asm-bad-operand.rs b/src/test/ui/llvm-asm/inline-asm-bad-operand.rs
deleted file mode 100644 (file)
index 1746c48..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-// Test that the compiler will catch passing invalid values to inline assembly
-// operands.
-
-// build-fail
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-#[repr(C)]
-struct MyPtr(usize);
-
-fn main() {
-    issue_37433();
-    issue_37437();
-    issue_40187();
-    issue_54067();
-    multiple_errors();
-}
-
-fn issue_37433() {
-    unsafe {
-        llvm_asm!("" :: "r"("")); //~ ERROR E0669
-    }
-
-    unsafe {
-        let target = MyPtr(0);
-        llvm_asm!("ret" : : "{rdi}"(target)); //~ ERROR E0669
-    }
-}
-
-fn issue_37437() {
-    let hello: &str = "hello";
-    // this should fail...
-    unsafe { llvm_asm!("" :: "i"(hello)) }; //~ ERROR E0669
-    // but this should succeed.
-    unsafe { llvm_asm!("" :: "r"(hello.as_ptr())) };
-}
-
-fn issue_40187() {
-    let arr: [u8; 1] = [0; 1];
-    unsafe {
-        llvm_asm!("movups $1, %xmm0"::"m"(arr)); //~ ERROR E0669
-    }
-}
-
-fn issue_54067() {
-    let addr: Option<u32> = Some(123);
-    unsafe {
-        llvm_asm!("mov sp, $0"::"r"(addr)); //~ ERROR E0669
-    }
-}
-
-fn multiple_errors() {
-    let addr: (u32, u32) = (1, 2);
-    unsafe {
-        llvm_asm!("mov sp, $0"::"r"(addr), //~ ERROR E0669
-                                "r"("hello e0669")); //~ ERROR E0669
-    }
-}
diff --git a/src/test/ui/llvm-asm/inline-asm-bad-operand.stderr b/src/test/ui/llvm-asm/inline-asm-bad-operand.stderr
deleted file mode 100644 (file)
index 8bb8a7a..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-error[E0669]: invalid value for constraint in inline assembly
-  --> $DIR/inline-asm-bad-operand.rs:23:29
-   |
-LL |         llvm_asm!("" :: "r"(""));
-   |                             ^^
-
-error[E0669]: invalid value for constraint in inline assembly
-  --> $DIR/inline-asm-bad-operand.rs:28:37
-   |
-LL |         llvm_asm!("ret" : : "{rdi}"(target));
-   |                                     ^^^^^^
-
-error[E0669]: invalid value for constraint in inline assembly
-  --> $DIR/inline-asm-bad-operand.rs:35:34
-   |
-LL |     unsafe { llvm_asm!("" :: "i"(hello)) };
-   |                                  ^^^^^
-
-error[E0669]: invalid value for constraint in inline assembly
-  --> $DIR/inline-asm-bad-operand.rs:43:43
-   |
-LL |         llvm_asm!("movups $1, %xmm0"::"m"(arr));
-   |                                           ^^^
-
-error[E0669]: invalid value for constraint in inline assembly
-  --> $DIR/inline-asm-bad-operand.rs:50:37
-   |
-LL |         llvm_asm!("mov sp, $0"::"r"(addr));
-   |                                     ^^^^
-
-error[E0669]: invalid value for constraint in inline assembly
-  --> $DIR/inline-asm-bad-operand.rs:57:37
-   |
-LL |         llvm_asm!("mov sp, $0"::"r"(addr),
-   |                                     ^^^^
-
-error[E0669]: invalid value for constraint in inline assembly
-  --> $DIR/inline-asm-bad-operand.rs:58:37
-   |
-LL | ...                   "r"("hello e0669"));
-   |                           ^^^^^^^^^^^^^
-
-error: aborting due to 7 previous errors
-
-For more information about this error, try `rustc --explain E0669`.
diff --git a/src/test/ui/llvm-asm/issue-14936.rs b/src/test/ui/llvm-asm/issue-14936.rs
deleted file mode 100644 (file)
index 46e5a2a..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// build-pass
-#![allow(unused_macros)]
-#![allow(dead_code)]
-#![allow(deprecated)] // llvm_asm!
-#![feature(llvm_asm)]
-
-type History = Vec<&'static str>;
-
-fn wrap<A>(x:A, which: &'static str, history: &mut History) -> A {
-    history.push(which);
-    x
-}
-
-macro_rules! demo {
-    ( $output_constraint:tt ) => {
-        {
-            let mut x: isize = 0;
-            let y: isize = 1;
-
-            let mut history: History = vec![];
-            unsafe {
-                llvm_asm!("mov ($1), $0"
-                          : $output_constraint (*wrap(&mut x, "out", &mut history))
-                          : "r"(&wrap(y, "in", &mut history))
-                          :: "volatile");
-            }
-            assert_eq!((x,y), (1,1));
-            let b: &[_] = &["out", "in"];
-            assert_eq!(history, b);
-        }
-    }
-}
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn main() {
-    fn out_write_only_expr_then_in_expr() {
-        demo!("=r")
-    }
-
-    fn out_read_write_expr_then_in_expr() {
-        demo!("+r")
-    }
-
-    out_write_only_expr_then_in_expr();
-    out_read_write_expr_then_in_expr();
-}
-
-#[cfg(all(not(target_arch = "x86"), not(target_arch = "x86_64")))]
-pub fn main() {}
diff --git a/src/test/ui/llvm-asm/issue-23458.rs b/src/test/ui/llvm-asm/issue-23458.rs
deleted file mode 100644 (file)
index d640828..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-// compile-flags: -Ccodegen-units=1
-// build-fail
-// only-x86_64
-
-fn main() {
-    unsafe {
-        llvm_asm!("int $3"); //~ ERROR too few operands for instruction
-                             //~| ERROR invalid operand in inline asm
-    }
-}
diff --git a/src/test/ui/llvm-asm/issue-23458.stderr b/src/test/ui/llvm-asm/issue-23458.stderr
deleted file mode 100644 (file)
index 69e458f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-error: invalid operand in inline asm: 'int $3'
-  --> $DIR/issue-23458.rs:9:9
-   |
-LL |         llvm_asm!("int $3");
-   |         ^
-
-error: too few operands for instruction
-  --> $DIR/issue-23458.rs:9:9
-   |
-LL |         llvm_asm!("int $3");
-   |         ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:1:2
-   |
-LL |     int 
-   |     ^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/test/ui/llvm-asm/issue-33264.rs b/src/test/ui/llvm-asm/issue-33264.rs
deleted file mode 100644 (file)
index 8ebf0cf..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-// build-pass
-// only-x86_64
-
-#![allow(dead_code, non_upper_case_globals)]
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-#[repr(C)]
-pub struct D32x4(f32,f32,f32,f32);
-
-impl D32x4 {
-    fn add(&self, vec: Self) -> Self {
-        unsafe {
-            let ret: Self;
-            llvm_asm!("
-                      movaps $1, %xmm1
-                      movaps $2, %xmm2
-                      addps %xmm1, %xmm2
-                      movaps $xmm1, $0
-                      "
-                      : "=r"(ret)
-                      : "1"(self), "2"(vec)
-                      : "xmm1", "xmm2"
-                      );
-            ret
-        }
-    }
-}
-
-fn main() { }
diff --git a/src/test/ui/llvm-asm/issue-37366.rs b/src/test/ui/llvm-asm/issue-37366.rs
deleted file mode 100644 (file)
index acc2f3e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-// check-pass
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-macro_rules! interrupt_handler {
-    () => {
-        unsafe fn _interrupt_handler() {
-            llvm_asm!("pop  eax" :::: "intel");
-        }
-    }
-}
-interrupt_handler!{}
-
-fn main() {}
diff --git a/src/test/ui/llvm-asm/issue-37433.rs b/src/test/ui/llvm-asm/issue-37433.rs
deleted file mode 100644 (file)
index 1c362e8..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// build-fail
-// ignore-emscripten no llvm_asm! support
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    unsafe {
-        llvm_asm!("" :: "r"(""));
-        //~^ ERROR: invalid value for constraint in inline assembly
-    }
-}
diff --git a/src/test/ui/llvm-asm/issue-37433.stderr b/src/test/ui/llvm-asm/issue-37433.stderr
deleted file mode 100644 (file)
index 44a8eb3..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0669]: invalid value for constraint in inline assembly
-  --> $DIR/issue-37433.rs:9:29
-   |
-LL |         llvm_asm!("" :: "r"(""));
-   |                             ^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0669`.
diff --git a/src/test/ui/llvm-asm/issue-51431.rs b/src/test/ui/llvm-asm/issue-51431.rs
deleted file mode 100644 (file)
index 706b714..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// build-fail
-// ignore-emscripten no llvm_asm! support
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    unsafe {
-        llvm_asm! {"mov $0,$1"::"0"("bx"),"1"(0x00)}
-        //~^ ERROR: invalid value for constraint in inline assembly
-    }
-}
diff --git a/src/test/ui/llvm-asm/issue-51431.stderr b/src/test/ui/llvm-asm/issue-51431.stderr
deleted file mode 100644 (file)
index 35c8c1b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0669]: invalid value for constraint in inline assembly
-  --> $DIR/issue-51431.rs:9:37
-   |
-LL |         llvm_asm! {"mov $0,$1"::"0"("bx"),"1"(0x00)}
-   |                                     ^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0669`.
diff --git a/src/test/ui/llvm-asm/issue-53787-inline-assembler-macro.rs b/src/test/ui/llvm-asm/issue-53787-inline-assembler-macro.rs
deleted file mode 100644 (file)
index d9fe7ca..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// Regression test for Issue #53787: Fix ICE when creating a label in inline assembler with macros.
-
-// build-fail
-// ignore-emscripten
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-macro_rules! fake_jump {
-    ($id:expr) => {
-        unsafe {
-            llvm_asm!(
-            "
-            jmp $0
-            lea eax, [ebx]
-            xor eax, 0xDEADBEEF
-            retn
-            $0:
-            "::"0"($id)::"volatile", "intel");
-        }
-    };
-}
-
-fn main() {
-    fake_jump!("FirstFunc"); //~ ERROR invalid value for constraint in inline assembly
-    println!("Hello, world!");
-}
diff --git a/src/test/ui/llvm-asm/issue-53787-inline-assembler-macro.stderr b/src/test/ui/llvm-asm/issue-53787-inline-assembler-macro.stderr
deleted file mode 100644 (file)
index fd755e3..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0669]: invalid value for constraint in inline assembly
-  --> $DIR/issue-53787-inline-assembler-macro.rs:25:16
-   |
-LL |     fake_jump!("FirstFunc");
-   |                ^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0669`.
diff --git a/src/test/ui/llvm-asm/issue-54067.rs b/src/test/ui/llvm-asm/issue-54067.rs
deleted file mode 100644 (file)
index 6e931b9..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// check-pass
-// ignore-emscripten no llvm_asm! support
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-pub fn boot(addr: Option<u32>) {
-    unsafe {
-        llvm_asm!("mov sp, $0"::"r" (addr));
-    }
-}
-
-fn main() {}
diff --git a/src/test/ui/llvm-asm/issue-62046.rs b/src/test/ui/llvm-asm/issue-62046.rs
deleted file mode 100644 (file)
index 38b5f1a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// build-fail
-// ignore-emscripten no asm! support
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    unsafe {
-        llvm_asm!("nop" : "+r"("r15"));
-        //~^ malformed inline assembly
-    }
-}
diff --git a/src/test/ui/llvm-asm/issue-62046.stderr b/src/test/ui/llvm-asm/issue-62046.stderr
deleted file mode 100644 (file)
index ae271af..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0668]: malformed inline assembly
-  --> $DIR/issue-62046.rs:9:9
-   |
-LL |         llvm_asm!("nop" : "+r"("r15"));
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0668`.
diff --git a/src/test/ui/llvm-asm/issue-69092.rs b/src/test/ui/llvm-asm/issue-69092.rs
deleted file mode 100644 (file)
index ea1b80c..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// build-fail
-// ignore-emscripten no asm! support
-// The error message differs slightly between LLVM versions
-// min-llvm-version: 13.0
-// Regression test for #69092
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    unsafe { llvm_asm!(".ascii \"Xen\0\""); }
-    //~^ ERROR: expected string
-}
diff --git a/src/test/ui/llvm-asm/issue-69092.stderr b/src/test/ui/llvm-asm/issue-69092.stderr
deleted file mode 100644 (file)
index 28c5fbb..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error: expected string
-  --> $DIR/issue-69092.rs:11:14
-   |
-LL |     unsafe { llvm_asm!(".ascii \"Xen\0\""); }
-   |              ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:1:9
-   |
-LL |     .ascii "Xen
-   |            ^
-
-error: aborting due to previous error
-
diff --git a/src/test/ui/llvm-asm/llvm-asm-bad-clobber.rs b/src/test/ui/llvm-asm/llvm-asm-bad-clobber.rs
deleted file mode 100644 (file)
index c15009f..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// ignore-android
-// ignore-arm
-// ignore-aarch64
-// ignore-s390x
-// ignore-emscripten
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-powerpc64le
-// ignore-riscv64
-// ignore-sparc
-// ignore-sparc64
-// ignore-mips
-// ignore-mips64
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-#[cfg(any(target_arch = "x86",
-          target_arch = "x86_64"))]
-
-pub fn main() {
-    unsafe {
-        // clobber formatted as register input/output
-        llvm_asm!("xor %eax, %eax" : : : "{eax}");
-        //~^ ERROR clobber should not be surrounded by braces
-    }
-}
diff --git a/src/test/ui/llvm-asm/llvm-asm-bad-clobber.stderr b/src/test/ui/llvm-asm/llvm-asm-bad-clobber.stderr
deleted file mode 100644 (file)
index bb72a14..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0664]: clobber should not be surrounded by braces
-  --> $DIR/llvm-asm-bad-clobber.rs:24:42
-   |
-LL |         llvm_asm!("xor %eax, %eax" : : : "{eax}");
-   |                                          ^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0664`.
diff --git a/src/test/ui/llvm-asm/llvm-asm-concat-src.rs b/src/test/ui/llvm-asm/llvm-asm-concat-src.rs
deleted file mode 100644 (file)
index 722eb07..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-// run-pass
-// pretty-expanded FIXME #23616
-// ignore-emscripten no asm
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-pub fn main() {
-    unsafe { llvm_asm!(concat!("", "")) };
-}
diff --git a/src/test/ui/llvm-asm/llvm-asm-in-bad-modifier.rs b/src/test/ui/llvm-asm/llvm-asm-in-bad-modifier.rs
deleted file mode 100644 (file)
index 1bccb0b..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// ignore-s390x
-// ignore-emscripten
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-powerpc64le
-// ignore-riscv64
-// ignore-sparc
-// ignore-sparc64
-// ignore-mips
-// ignore-mips64
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn foo(x: isize) { println!("{}", x); }
-
-#[cfg(any(target_arch = "x86",
-          target_arch = "x86_64",
-          target_arch = "arm",
-          target_arch = "aarch64"))]
-pub fn main() {
-    let x: isize;
-    let y: isize;
-    unsafe {
-        llvm_asm!("mov $1, $0" : "=r"(x) : "=r"(5)); //~ ERROR operand constraint contains '='
-        llvm_asm!("mov $1, $0" : "=r"(y) : "+r"(5)); //~ ERROR operand constraint contains '+'
-    }
-    foo(x);
-    foo(y);
-}
-
-#[cfg(not(any(target_arch = "x86",
-              target_arch = "x86_64",
-              target_arch = "arm",
-              target_arch = "aarch64")))]
-pub fn main() {}
diff --git a/src/test/ui/llvm-asm/llvm-asm-in-bad-modifier.stderr b/src/test/ui/llvm-asm/llvm-asm-in-bad-modifier.stderr
deleted file mode 100644 (file)
index f6c618e..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-error[E0662]: input operand constraint contains '='
-  --> $DIR/llvm-asm-in-bad-modifier.rs:25:44
-   |
-LL |         llvm_asm!("mov $1, $0" : "=r"(x) : "=r"(5));
-   |                                            ^^^^
-
-error[E0663]: input operand constraint contains '+'
-  --> $DIR/llvm-asm-in-bad-modifier.rs:26:44
-   |
-LL |         llvm_asm!("mov $1, $0" : "=r"(y) : "+r"(5));
-   |                                            ^^^^
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0662, E0663.
-For more information about an error, try `rustc --explain E0662`.
diff --git a/src/test/ui/llvm-asm/llvm-asm-in-moved.rs b/src/test/ui/llvm-asm/llvm-asm-in-moved.rs
deleted file mode 100644 (file)
index f7b0fe5..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-// run-pass
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-#![allow(dead_code)]
-
-use std::cell::Cell;
-
-#[repr(C)]
-struct NoisyDrop<'a>(&'a Cell<&'static str>);
-impl<'a> Drop for NoisyDrop<'a> {
-    fn drop(&mut self) {
-        self.0.set("destroyed");
-    }
-}
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn main() {
-    let status = Cell::new("alive");
-    {
-        let _y: Box<NoisyDrop>;
-        let x = Box::new(NoisyDrop(&status));
-        unsafe {
-            llvm_asm!("mov $1, $0" : "=r"(_y) : "r"(x));
-        }
-        assert_eq!(status.get(), "alive");
-    }
-    assert_eq!(status.get(), "destroyed");
-}
-
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-fn main() {}
diff --git a/src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs b/src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs
deleted file mode 100644 (file)
index 2429b51..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-// run-pass
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-unsafe fn next_power_of_2(n: u32) -> u32 {
-    let mut tmp = n;
-    llvm_asm!("dec $0" : "+rm"(tmp) :: "cc");
-    let mut shift = 1_u32;
-    while shift <= 16 {
-        llvm_asm!(
-            "shr %cl, $2
-            or $2, $0
-            shl $$1, $1"
-            : "+&rm"(tmp), "+{ecx}"(shift) : "r"(tmp) : "cc"
-        );
-    }
-    llvm_asm!("inc $0" : "+rm"(tmp) :: "cc");
-    return tmp;
-}
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-pub fn main() {
-    unsafe {
-        assert_eq!(64, next_power_of_2(37));
-        assert_eq!(2147483648, next_power_of_2(2147483647));
-    }
-
-    let mut y: isize = 5;
-    let x: isize;
-    unsafe {
-        // Treat the output as initialization.
-        llvm_asm!(
-            "shl $2, $1
-            add $3, $1
-            mov $1, $0"
-            : "=r"(x), "+r"(y) : "i"(3_usize), "ir"(7_usize) : "cc"
-        );
-    }
-    assert_eq!(x, 47);
-    assert_eq!(y, 47);
-
-    let mut x = x + 1;
-    assert_eq!(x, 48);
-
-    unsafe {
-        // Assignment to mutable.
-        // Early clobber "&":
-        // Forbids the use of a single register by both operands.
-        llvm_asm!("shr $$2, $1; add $1, $0" : "+&r"(x) : "r"(x) : "cc");
-    }
-    assert_eq!(x, 60);
-}
-
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-pub fn main() {}
diff --git a/src/test/ui/llvm-asm/llvm-asm-indirect-memory.rs b/src/test/ui/llvm-asm/llvm-asm-indirect-memory.rs
deleted file mode 100644 (file)
index 441c62b..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-// run-pass
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn read(ptr: &u32) -> u32 {
-    let out: u32;
-    unsafe {
-        llvm_asm!("mov $1, $0" : "=r" (out) : "*m" (ptr));
-    }
-    out
-}
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn write(ptr: &mut u32, val: u32) {
-    unsafe {
-        llvm_asm!("mov $1, $0" : "=*m" (ptr) : "r" (val));
-    }
-}
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-fn replace(ptr: &mut u32, val: u32) -> u32 {
-    let out: u32;
-    unsafe {
-        llvm_asm!("mov $0, $1; mov $2, $0" : "+*m" (ptr), "=&r" (out) : "r" (val));
-    }
-    out
-}
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-pub fn main() {
-    let a = 1;
-    assert_eq!(read(&a), 1);
-    let mut b = 2;
-    write(&mut b, 3);
-    assert_eq!(b, 3);
-    let mut c = 4;
-    assert_eq!(replace(&mut c, 5), 4);
-    assert_eq!(c, 5);
-}
-
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-pub fn main() {}
diff --git a/src/test/ui/llvm-asm/llvm-asm-literal-escaping.rs b/src/test/ui/llvm-asm/llvm-asm-literal-escaping.rs
deleted file mode 100644 (file)
index ecd0c2f..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// build-pass
-// only-x86_64
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    unsafe {
-        // "nop" :: "r"(x) : "eax" : "volatile"
-        let x = 10;
-        llvm_asm!("\x6Eop" :: "\x72"(x) : "\x65ax" : "\x76olatile");
-    }
-}
diff --git a/src/test/ui/llvm-asm/llvm-asm-misplaced-option.rs b/src/test/ui/llvm-asm/llvm-asm-misplaced-option.rs
deleted file mode 100644 (file)
index 04f0972..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// check-pass
-// ignore-android
-// ignore-arm
-// ignore-aarch64
-// ignore-s390x
-// ignore-emscripten
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-powerpc64le
-// ignore-riscv64
-// ignore-sparc
-// ignore-sparc64
-// ignore-mips
-// ignore-mips64
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-#[cfg(any(target_arch = "x86",
-          target_arch = "x86_64"))]
-fn main() {
-    // assignment not dead
-    let mut x: isize = 0;
-    unsafe {
-        // extra colon
-        llvm_asm!("mov $1, $0" : "=r"(x) : "r"(5_usize), "0"(x) : : "cc");
-        //~^ WARNING unrecognized option
-    }
-    assert_eq!(x, 5);
-
-    unsafe {
-        // comma in place of a colon
-        llvm_asm!("add $2, $1; mov $1, $0" : "=r"(x) : "r"(x), "r"(8_usize) : "cc", "volatile");
-        //~^ WARNING expected a clobber, found an option
-    }
-    assert_eq!(x, 13);
-}
diff --git a/src/test/ui/llvm-asm/llvm-asm-misplaced-option.stderr b/src/test/ui/llvm-asm/llvm-asm-misplaced-option.stderr
deleted file mode 100644 (file)
index d1250d9..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-warning: unrecognized option
-  --> $DIR/llvm-asm-misplaced-option.rs:26:69
-   |
-LL |         llvm_asm!("mov $1, $0" : "=r"(x) : "r"(5_usize), "0"(x) : : "cc");
-   |                                                                     ^^^^
-
-warning: expected a clobber, found an option
-  --> $DIR/llvm-asm-misplaced-option.rs:33:85
-   |
-LL |         llvm_asm!("add $2, $1; mov $1, $0" : "=r"(x) : "r"(x), "r"(8_usize) : "cc", "volatile");
-   |                                                                                     ^^^^^^^^^^
-
-warning: 2 warnings emitted
-
diff --git a/src/test/ui/llvm-asm/llvm-asm-out-assign-imm.rs b/src/test/ui/llvm-asm/llvm-asm-out-assign-imm.rs
deleted file mode 100644 (file)
index 7f51b50..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// ignore-s390x
-// ignore-emscripten
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-powerpc64le
-// ignore-riscv64
-// ignore-sparc
-// ignore-sparc64
-// ignore-mips
-// ignore-mips64
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn foo(x: isize) { println!("{}", x); }
-
-#[cfg(any(target_arch = "x86",
-          target_arch = "x86_64",
-          target_arch = "arm",
-          target_arch = "aarch64"))]
-pub fn main() {
-    let x: isize;
-    x = 1;
-    foo(x);
-    unsafe {
-        llvm_asm!("mov $1, $0" : "=r"(x) : "r"(5));
-        //~^ ERROR cannot assign twice to immutable variable `x`
-    }
-    foo(x);
-}
-
-#[cfg(not(any(target_arch = "x86",
-              target_arch = "x86_64",
-              target_arch = "arm",
-              target_arch = "aarch64")))]
-pub fn main() {}
diff --git a/src/test/ui/llvm-asm/llvm-asm-out-assign-imm.stderr b/src/test/ui/llvm-asm/llvm-asm-out-assign-imm.stderr
deleted file mode 100644 (file)
index 390c032..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0384]: cannot assign twice to immutable variable `x`
-  --> $DIR/llvm-asm-out-assign-imm.rs:26:39
-   |
-LL |     let x: isize;
-   |         - help: consider making this binding mutable: `mut x`
-LL |     x = 1;
-   |     ----- first assignment to `x`
-...
-LL |         llvm_asm!("mov $1, $0" : "=r"(x) : "r"(5));
-   |                                       ^ cannot assign twice to immutable variable
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0384`.
diff --git a/src/test/ui/llvm-asm/llvm-asm-out-assign.rs b/src/test/ui/llvm-asm/llvm-asm-out-assign.rs
deleted file mode 100644 (file)
index c5f4a9a..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// run-pass
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!s
-
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-pub fn main() {
-    let x: isize;
-    unsafe {
-        // Treat the output as initialization.
-        llvm_asm!("mov $1, $0" : "=r"(x) : "r"(5_usize));
-    }
-    assert_eq!(x, 5);
-
-    let mut x = x + 1;
-    assert_eq!(x, 6);
-
-    unsafe {
-        // Assignment to mutable.
-        llvm_asm!("mov $1, $0" : "=r"(x) : "r"(x + 7));
-    }
-    assert_eq!(x, 13);
-}
-
-#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
-pub fn main() {}
diff --git a/src/test/ui/llvm-asm/llvm-asm-out-no-modifier.rs b/src/test/ui/llvm-asm/llvm-asm-out-no-modifier.rs
deleted file mode 100644 (file)
index c74d156..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-// ignore-s390x
-// ignore-emscripten
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-powerpc64le
-// ignore-riscv64
-// ignore-sparc
-// ignore-sparc64
-// ignore-mips
-// ignore-mips64
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn foo(x: isize) { println!("{}", x); }
-
-#[cfg(any(target_arch = "x86",
-          target_arch = "x86_64",
-          target_arch = "arm",
-          target_arch = "aarch64"))]
-pub fn main() {
-    let x: isize;
-    unsafe {
-        llvm_asm!("mov $1, $0" : "r"(x) : "r"(5)); //~ ERROR output operand constraint lacks '='
-    }
-    foo(x);
-}
-
-#[cfg(not(any(target_arch = "x86",
-              target_arch = "x86_64",
-              target_arch = "arm",
-              target_arch = "aarch64")))]
-pub fn main() {}
diff --git a/src/test/ui/llvm-asm/llvm-asm-out-no-modifier.stderr b/src/test/ui/llvm-asm/llvm-asm-out-no-modifier.stderr
deleted file mode 100644 (file)
index f426170..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0661]: output operand constraint lacks '=' or '+'
-  --> $DIR/llvm-asm-out-no-modifier.rs:24:34
-   |
-LL |         llvm_asm!("mov $1, $0" : "r"(x) : "r"(5));
-   |                                  ^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0661`.
diff --git a/src/test/ui/llvm-asm/llvm-asm-out-read-uninit.rs b/src/test/ui/llvm-asm/llvm-asm-out-read-uninit.rs
deleted file mode 100644 (file)
index 161add7..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-// ignore-s390x
-// ignore-emscripten
-// ignore-powerpc
-// ignore-powerpc64
-// ignore-powerpc64le
-// ignore-riscv64
-// ignore-sparc
-// ignore-sparc64
-// ignore-mips
-// ignore-mips64
-
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn foo(x: isize) { println!("{}", x); }
-
-#[cfg(any(target_arch = "x86",
-          target_arch = "x86_64",
-          target_arch = "arm",
-          target_arch = "aarch64"))]
-pub fn main() {
-    let x: isize;
-    unsafe {
-        llvm_asm!("mov $1, $0" : "=r"(x) : "r"(x));
-        //~^ ERROR use of possibly-uninitialized variable: `x`
-    }
-    foo(x);
-}
-
-#[cfg(not(any(target_arch = "x86",
-              target_arch = "x86_64",
-              target_arch = "arm",
-              target_arch = "aarch64")))]
-pub fn main() {}
diff --git a/src/test/ui/llvm-asm/llvm-asm-out-read-uninit.stderr b/src/test/ui/llvm-asm/llvm-asm-out-read-uninit.stderr
deleted file mode 100644 (file)
index 7e57dc4..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0381]: use of possibly-uninitialized variable: `x`
-  --> $DIR/llvm-asm-out-read-uninit.rs:24:48
-   |
-LL |         llvm_asm!("mov $1, $0" : "=r"(x) : "r"(x));
-   |                                                ^ use of possibly-uninitialized `x`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0381`.
diff --git a/src/test/ui/llvm-asm/llvm-asm-parse-errors.rs b/src/test/ui/llvm-asm/llvm-asm-parse-errors.rs
deleted file mode 100644 (file)
index cdd0b94..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
-fn main() {
-    llvm_asm!(); //~ ERROR requires a string literal as an argument
-    llvm_asm!("nop" : struct); //~ ERROR expected string literal
-    llvm_asm!("mov %eax, $$0x2" : struct); //~ ERROR expected string literal
-    llvm_asm!("mov %eax, $$0x2" : "={eax}" struct); //~ ERROR expected `(`
-    llvm_asm!("mov %eax, $$0x2" : "={eax}"(struct)); //~ ERROR expected expression
-    llvm_asm!("in %dx, %al" : "={al}"(result) : struct); //~ ERROR expected string literal
-    llvm_asm!("in %dx, %al" : "={al}"(result) : "{dx}" struct); //~ ERROR expected `(`
-    llvm_asm!("in %dx, %al" : "={al}"(result) : "{dx}"(struct)); //~ ERROR expected expression
-    llvm_asm!("mov $$0x200, %eax" : : : struct); //~ ERROR expected string literal
-    llvm_asm!("mov eax, 2" : "={eax}"(foo) : : : struct); //~ ERROR expected string literal
-    llvm_asm!(123); //~ ERROR inline assembly must be a string literal
-}
diff --git a/src/test/ui/llvm-asm/llvm-asm-parse-errors.stderr b/src/test/ui/llvm-asm/llvm-asm-parse-errors.stderr
deleted file mode 100644 (file)
index 715d05b..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-error: macro requires a string literal as an argument
-  --> $DIR/llvm-asm-parse-errors.rs:5:5
-   |
-LL |     llvm_asm!();
-   |     ^^^^^^^^^^^ string literal required
-
-error: expected string literal
-  --> $DIR/llvm-asm-parse-errors.rs:6:23
-   |
-LL |     llvm_asm!("nop" : struct);
-   |                       ^^^^^^ not a string literal
-
-error: expected string literal
-  --> $DIR/llvm-asm-parse-errors.rs:7:35
-   |
-LL |     llvm_asm!("mov %eax, $$0x2" : struct);
-   |                                   ^^^^^^ not a string literal
-
-error: expected `(`, found keyword `struct`
-  --> $DIR/llvm-asm-parse-errors.rs:8:44
-   |
-LL |     llvm_asm!("mov %eax, $$0x2" : "={eax}" struct);
-   |                                            ^^^^^^ expected `(`
-
-error: expected expression, found keyword `struct`
-  --> $DIR/llvm-asm-parse-errors.rs:9:44
-   |
-LL |     llvm_asm!("mov %eax, $$0x2" : "={eax}"(struct));
-   |                                            ^^^^^^ expected expression
-
-error: expected string literal
-  --> $DIR/llvm-asm-parse-errors.rs:10:49
-   |
-LL |     llvm_asm!("in %dx, %al" : "={al}"(result) : struct);
-   |                                                 ^^^^^^ not a string literal
-
-error: expected `(`, found keyword `struct`
-  --> $DIR/llvm-asm-parse-errors.rs:11:56
-   |
-LL |     llvm_asm!("in %dx, %al" : "={al}"(result) : "{dx}" struct);
-   |                                                        ^^^^^^ expected `(`
-
-error: expected expression, found keyword `struct`
-  --> $DIR/llvm-asm-parse-errors.rs:12:56
-   |
-LL |     llvm_asm!("in %dx, %al" : "={al}"(result) : "{dx}"(struct));
-   |                                                        ^^^^^^ expected expression
-
-error: expected string literal
-  --> $DIR/llvm-asm-parse-errors.rs:13:41
-   |
-LL |     llvm_asm!("mov $$0x200, %eax" : : : struct);
-   |                                         ^^^^^^ not a string literal
-
-error: expected string literal
-  --> $DIR/llvm-asm-parse-errors.rs:14:50
-   |
-LL |     llvm_asm!("mov eax, 2" : "={eax}"(foo) : : : struct);
-   |                                                  ^^^^^^ not a string literal
-
-error: inline assembly must be a string literal
-  --> $DIR/llvm-asm-parse-errors.rs:15:15
-   |
-LL |     llvm_asm!(123);
-   |               ^^^
-
-error: aborting due to 11 previous errors
-
index abe1f2aaf153bcf8aade5d44d5919c68628d4c55..35003a79ad703daf9145cd0cd7030b4305277352 100644 (file)
@@ -14,8 +14,20 @@ fn $fnname($arg: $ty) -> Option<$ty> $body
 
 }
 
+macro_rules! qpath {
+    (path, <$type:ty as $trait:path>::$name:ident) => {
+        <$type as $trait>::$name
+    };
+
+    (ty, <$type:ty as $trait:ty>::$name:ident) => {
+        <$type as $trait>::$name
+    };
+}
+
 pub fn main() {
+    let _: qpath!(path, <str as ToOwned>::Owned);
+    let _: qpath!(ty, <str as ToOwned>::Owned);
+
     assert!(overly_complicated!(f, x, Option<usize>, { return Some(x); },
                                Some(8), Some(y), y) == 8)
-
 }
index 3bab95083b6d9cb1d2087c5afcfd3b5f2998a65a..98f64aa6f8025a212c2f18e189dca42e68adbc9b 100644 (file)
@@ -3,11 +3,9 @@
 // test that errors in a (selection) of macros don't kill compilation
 // immediately, so that we get more errors listed at a time.
 
-#![feature(llvm_asm)]
 #![feature(trace_macros, concat_idents)]
 #![feature(stmt_expr_attributes, arbitrary_enum_discriminant)]
 #![feature(derive_default_enum)]
-#![allow(deprecated)] // llvm_asm!
 
 use std::arch::asm;
 
index 9a360206e6eea4ae3743303ca81322900de756dc..79e8db9c1d429866e509112373a21be657bcd857 100644 (file)
@@ -1,41 +1,41 @@
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:16:5
+  --> $DIR/macros-nonfatal-errors.rs:14:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:21:36
+  --> $DIR/macros-nonfatal-errors.rs:19:36
    |
 LL | struct DefaultInnerAttrTupleStruct(#[default] ());
    |                                    ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:25:1
+  --> $DIR/macros-nonfatal-errors.rs:23:1
    |
 LL | #[default]
    | ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:29:1
+  --> $DIR/macros-nonfatal-errors.rs:27:1
    |
 LL | #[default]
    | ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:39:11
+  --> $DIR/macros-nonfatal-errors.rs:37:11
    |
 LL |     Foo = #[default] 0,
    |           ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:40:14
+  --> $DIR/macros-nonfatal-errors.rs:38:14
    |
 LL |     Bar([u8; #[default] 1]),
    |              ^^^^^^^^^^
 
 error: no default declared
-  --> $DIR/macros-nonfatal-errors.rs:45:10
+  --> $DIR/macros-nonfatal-errors.rs:43:10
    |
 LL | #[derive(Default)]
    |          ^^^^^^^
@@ -44,7 +44,7 @@ LL | #[derive(Default)]
    = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: multiple declared defaults
-  --> $DIR/macros-nonfatal-errors.rs:51:10
+  --> $DIR/macros-nonfatal-errors.rs:49:10
    |
 LL | #[derive(Default)]
    |          ^^^^^^^
@@ -62,7 +62,7 @@ LL |     Baz,
    = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: `#[default]` attribute does not accept a value
-  --> $DIR/macros-nonfatal-errors.rs:63:5
+  --> $DIR/macros-nonfatal-errors.rs:61:5
    |
 LL |     #[default = 1]
    |     ^^^^^^^^^^^^^^
@@ -70,7 +70,7 @@ LL |     #[default = 1]
    = help: try using `#[default]`
 
 error: multiple `#[default]` attributes
-  --> $DIR/macros-nonfatal-errors.rs:71:5
+  --> $DIR/macros-nonfatal-errors.rs:69:5
    |
 LL |     #[default]
    |     ---------- `#[default]` used here
@@ -81,13 +81,13 @@ LL |     Foo,
    |
    = note: only one `#[default]` attribute is needed
 help: try removing this
-  --> $DIR/macros-nonfatal-errors.rs:70:5
+  --> $DIR/macros-nonfatal-errors.rs:68:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
 
 error: multiple `#[default]` attributes
-  --> $DIR/macros-nonfatal-errors.rs:81:5
+  --> $DIR/macros-nonfatal-errors.rs:79:5
    |
 LL |     #[default]
    |     ---------- `#[default]` used here
@@ -99,7 +99,7 @@ LL |     Foo,
    |
    = note: only one `#[default]` attribute is needed
 help: try removing these
-  --> $DIR/macros-nonfatal-errors.rs:78:5
+  --> $DIR/macros-nonfatal-errors.rs:76:5
    |
 LL |     #[default]
    |     ^^^^^^^^^^
@@ -109,7 +109,7 @@ LL |     #[default]
    |     ^^^^^^^^^^
 
 error: the `#[default]` attribute may only be used on unit enum variants
-  --> $DIR/macros-nonfatal-errors.rs:88:5
+  --> $DIR/macros-nonfatal-errors.rs:86:5
    |
 LL |     Foo {},
    |     ^^^
@@ -117,7 +117,7 @@ LL |     Foo {},
    = help: consider a manual implementation of `Default`
 
 error: default variant must be exhaustive
-  --> $DIR/macros-nonfatal-errors.rs:96:5
+  --> $DIR/macros-nonfatal-errors.rs:94:5
    |
 LL |     #[non_exhaustive]
    |     ----------------- declared `#[non_exhaustive]` here
@@ -127,43 +127,37 @@ LL |     Foo,
    = help: consider a manual implementation of `Default`
 
 error: asm template must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:101:10
+  --> $DIR/macros-nonfatal-errors.rs:99:10
    |
 LL |     asm!(invalid);
    |          ^^^^^^^
 
-error: inline assembly must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:102:15
-   |
-LL |     llvm_asm!(invalid);
-   |               ^^^^^^^
-
 error: concat_idents! requires ident args
-  --> $DIR/macros-nonfatal-errors.rs:104:5
+  --> $DIR/macros-nonfatal-errors.rs:102:5
    |
 LL |     concat_idents!("not", "idents");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:106:17
+  --> $DIR/macros-nonfatal-errors.rs:104:17
    |
 LL |     option_env!(invalid);
    |                 ^^^^^^^
 
 error: expected string literal
-  --> $DIR/macros-nonfatal-errors.rs:107:10
+  --> $DIR/macros-nonfatal-errors.rs:105:10
    |
 LL |     env!(invalid);
    |          ^^^^^^^
 
 error: expected string literal
-  --> $DIR/macros-nonfatal-errors.rs:108:10
+  --> $DIR/macros-nonfatal-errors.rs:106:10
    |
 LL |     env!(foo, abr, baz);
    |          ^^^
 
 error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined
-  --> $DIR/macros-nonfatal-errors.rs:109:5
+  --> $DIR/macros-nonfatal-errors.rs:107:5
    |
 LL |     env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -171,7 +165,7 @@ LL |     env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST");
    = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: format argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:111:13
+  --> $DIR/macros-nonfatal-errors.rs:109:13
    |
 LL |     format!(invalid);
    |             ^^^^^^^
@@ -182,19 +176,19 @@ LL |     format!("{}", invalid);
    |             +++++
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:113:14
+  --> $DIR/macros-nonfatal-errors.rs:111:14
    |
 LL |     include!(invalid);
    |              ^^^^^^^
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:115:18
+  --> $DIR/macros-nonfatal-errors.rs:113:18
    |
 LL |     include_str!(invalid);
    |                  ^^^^^^^
 
 error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
-  --> $DIR/macros-nonfatal-errors.rs:116:5
+  --> $DIR/macros-nonfatal-errors.rs:114:5
    |
 LL |     include_str!("i'd be quite surprised if a file with this name existed");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -202,13 +196,13 @@ LL |     include_str!("i'd be quite surprised if a file with this name existed")
    = note: this error originates in the macro `include_str` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: argument must be a string literal
-  --> $DIR/macros-nonfatal-errors.rs:117:20
+  --> $DIR/macros-nonfatal-errors.rs:115:20
    |
 LL |     include_bytes!(invalid);
    |                    ^^^^^^^
 
 error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2)
-  --> $DIR/macros-nonfatal-errors.rs:118:5
+  --> $DIR/macros-nonfatal-errors.rs:116:5
    |
 LL |     include_bytes!("i'd be quite surprised if a file with this name existed");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -216,10 +210,16 @@ LL |     include_bytes!("i'd be quite surprised if a file with this name existed
    = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: trace_macros! accepts only `true` or `false`
-  --> $DIR/macros-nonfatal-errors.rs:120:5
+  --> $DIR/macros-nonfatal-errors.rs:118:5
    |
 LL |     trace_macros!(invalid);
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
+error: cannot find macro `llvm_asm` in this scope
+  --> $DIR/macros-nonfatal-errors.rs:100:5
+   |
+LL |     llvm_asm!(invalid);
+   |     ^^^^^^^^
+
 error: aborting due to 27 previous errors
 
index 820dcdb939499e83233b97129061e5979491c469..004ab386b3ff071d6a10b72f2c0337d023eee37d 100644 (file)
@@ -589,7 +589,7 @@ trait Trait<'a>: Sized
         stringify_item!(
             pub trait Trait<T> = Sized where T: 'a;
         ),
-        "", // FIXME
+        "pub trait Trait<T> = Sized where T: 'a;",
     );
 
     // ItemKind::Impl
diff --git a/src/test/ui/mir/mir_let_chains_drop_order.rs b/src/test/ui/mir/mir_let_chains_drop_order.rs
new file mode 100644 (file)
index 0000000..01f943c
--- /dev/null
@@ -0,0 +1,93 @@
+// run-pass
+// needs-unwind
+// ignore-wasm32-bare compiled with panic=abort by default
+
+// See `mir_drop_order.rs` for more information
+
+#![feature(let_chains)]
+
+use std::cell::RefCell;
+use std::panic;
+
+pub struct DropLogger<'a, T> {
+    extra: T,
+    id: usize,
+    log: &'a panic::AssertUnwindSafe<RefCell<Vec<usize>>>
+}
+
+impl<'a, T> Drop for DropLogger<'a, T> {
+    fn drop(&mut self) {
+        self.log.0.borrow_mut().push(self.id);
+    }
+}
+
+struct InjectedFailure;
+
+#[allow(unreachable_code)]
+fn main() {
+    let log = panic::AssertUnwindSafe(RefCell::new(vec![]));
+    let d = |id, extra| DropLogger { extra, id: id, log: &log };
+    let get = || -> Vec<_> {
+        let mut m = log.0.borrow_mut();
+        let n = m.drain(..);
+        n.collect()
+    };
+
+    {
+        let _x = (
+            d(
+                0,
+                d(
+                    1,
+                    if let Some(_) = d(2, Some(true)).extra && let DropLogger { .. } = d(3, None) {
+                        None
+                    } else {
+                        Some(true)
+                    }
+                ).extra
+            ),
+            d(4, None),
+            &d(5, None),
+            d(6, None),
+            if let DropLogger { .. } = d(7, None) && let DropLogger { .. } = d(8, None) {
+                d(9, None)
+            }
+            else {
+                // 10 is not constructed
+                d(10, None)
+            }
+        );
+        assert_eq!(get(), vec![3, 8, 7, 1, 2]);
+    }
+    assert_eq!(get(), vec![0, 4, 6, 9, 5]);
+
+    let _ = std::panic::catch_unwind(|| {
+        (
+            d(
+                11,
+                d(
+                    12,
+                    if let Some(_) = d(13, Some(true)).extra
+                        && let DropLogger { .. } = d(14, None)
+                    {
+                        None
+                    } else {
+                        Some(true)
+                    }
+                ).extra
+            ),
+            d(15, None),
+            &d(16, None),
+            d(17, None),
+            if let DropLogger { .. } = d(18, None) && let DropLogger { .. } = d(19, None) {
+                d(20, None)
+            }
+            else {
+                // 10 is not constructed
+                d(21, None)
+            },
+            panic::panic_any(InjectedFailure)
+        );
+    });
+    assert_eq!(get(), vec![14, 19, 20, 17, 15, 11, 18, 16, 12, 13]);
+}
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 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
 
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 e725aa5d73d1f97d00f6f2a0c924826ffc1c7922..23f245a51681b559cdfc627ae0a7cd7fd1420030 100644 (file)
@@ -117,9 +117,9 @@ pub fn inside_block() {
 
 pub fn cast_then_try() -> Result<u64,u64> {
     Err(0u64) as Result<u64,u64>?;
-    //~^ ERROR: casts cannot be followed by ?
+    //~^ ERROR: casts cannot be followed by `?`
     Err(0u64): Result<u64,u64>?;
-    //~^ ERROR: casts cannot be followed by ?
+    //~^ ERROR: casts cannot be followed by `?`
     Ok(1)
 }
 
index 19b68556d79ad27cfb40022ee21d2bdc66367df5..e96b67da3364df8b9204fb8ff2a6c75515a1a8b5 100644 (file)
@@ -265,7 +265,7 @@ help: try surrounding the expression in parentheses
 LL | static bar2: &[i32] = &((&[1i32,2,3]: &[i32; 3])[0..1]);
    |                         +                      +
 
-error: casts cannot be followed by ?
+error: casts cannot be followed by `?`
   --> $DIR/issue-35813-postfix-after-cast.rs:119:5
    |
 LL |     Err(0u64) as Result<u64,u64>?;
@@ -276,7 +276,7 @@ help: try surrounding the expression in parentheses
 LL |     (Err(0u64) as Result<u64,u64>)?;
    |     +                            +
 
-error: casts cannot be followed by ?
+error: casts cannot be followed by `?`
   --> $DIR/issue-35813-postfix-after-cast.rs:121:5
    |
 LL |     Err(0u64): Result<u64,u64>?;
index 25f7ba4d1f88e8920b6beb754c9fb3d3ad97b24c..9fa8086c2c9bf4af8b6fe37ae05539cbae98d8a0 100644 (file)
@@ -1,4 +1,3 @@
 fn f(t:for<>t?)
-//~^ ERROR: expected parameter name
-//~| ERROR: expected one of
-//~| ERROR: expected one of
+//~^ ERROR: expected one of
+//~| ERROR: invalid `?` in type
index 77f0896e9c155d54462a4c5e416b14eb99b1c304..9261067c22158c032256790ebe7e93eaf29065fe 100644 (file)
@@ -1,17 +1,13 @@
-error: expected parameter name, found `?`
+error: invalid `?` in type
   --> $DIR/issue-84148-1.rs:1:14
    |
 LL | fn f(t:for<>t?)
-   |              ^ expected parameter name
-
-error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
-  --> $DIR/issue-84148-1.rs:1:14
+   |              ^ `?` is only allowed on expressions, not types
    |
-LL | fn f(t:for<>t?)
-   |              ^
-   |              |
-   |              expected one of `(`, `)`, `+`, `,`, `::`, or `<`
-   |              help: missing `,`
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+   |
+LL | fn f(t:Option<for<>t>)
+   |        +++++++      ~
 
 error: expected one of `->`, `where`, or `{`, found `<eof>`
   --> $DIR/issue-84148-1.rs:1:15
@@ -19,5 +15,5 @@ error: expected one of `->`, `where`, or `{`, found `<eof>`
 LL | fn f(t:for<>t?)
    |               ^ expected one of `->`, `where`, or `{`
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
index 257a3fd67207ec2bd1a045fc7d88117eb787d5fe..2f6a7facfb271d8653c41957b67b06666a93f9bf 100644 (file)
@@ -1,4 +1,3 @@
 // error-pattern: this file contains an unclosed delimiter
-// error-pattern: expected parameter name
-// error-pattern: expected one of
+// error-pattern: invalid `?` in type
 fn f(t:for<>t?
index 396208316df677e32a085508eba833fd14217089..71d543f9b73447804f775612ac98fc8050996fcf 100644 (file)
@@ -1,31 +1,27 @@
 error: this file contains an unclosed delimiter
-  --> $DIR/issue-84148-2.rs:4:16
+  --> $DIR/issue-84148-2.rs:3:16
    |
 LL | fn f(t:for<>t?
    |     -          ^
    |     |
    |     unclosed delimiter
 
-error: expected parameter name, found `?`
-  --> $DIR/issue-84148-2.rs:4:14
+error: invalid `?` in type
+  --> $DIR/issue-84148-2.rs:3:14
    |
 LL | fn f(t:for<>t?
-   |              ^ expected parameter name
-
-error: expected one of `(`, `)`, `+`, `,`, `::`, or `<`, found `?`
-  --> $DIR/issue-84148-2.rs:4:14
+   |              ^ `?` is only allowed on expressions, not types
    |
-LL | fn f(t:for<>t?
-   |              ^
-   |              |
-   |              expected one of `(`, `)`, `+`, `,`, `::`, or `<`
-   |              help: missing `,`
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+   |
+LL | fn f(t:Option<for<>t>
+   |        +++++++      ~
 
 error: expected one of `->`, `where`, or `{`, found `<eof>`
-  --> $DIR/issue-84148-2.rs:4:16
+  --> $DIR/issue-84148-2.rs:3:16
    |
 LL | fn f(t:for<>t?
    |                ^ expected one of `->`, `where`, or `{`
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
index 06be3cdcc1a9528dd58d472dcedb5a477f5e7dc7..1453e6cb5cd7c654a71af7d82449103c42901d32 100644 (file)
@@ -1,7 +1,9 @@
 #[cfg(FALSE)]
 fn syntax() {
-    bar::<Item = 42>(); //~ ERROR cannot constrain an associated constant to a value
-    bar::<Item = { 42 }>(); //~ ERROR cannot constrain an associated constant to a value
+    bar::<Item = 42>();
+    //~^ ERROR associated const equality is incomplete
+    bar::<Item = { 42 }>();
+    //~^ ERROR associated const equality is incomplete
 }
 
 fn main() {}
index c6733b33faa58072d1cff7a65dba2549687aec34..2d36ce4e98632d950f7e1793cc06fe40a2ba2156 100644 (file)
@@ -1,20 +1,21 @@
-error: cannot constrain an associated constant to a value
+error[E0658]: associated const equality is incomplete
   --> $DIR/recover-assoc-const-constraint.rs:3:11
    |
 LL |     bar::<Item = 42>();
-   |           ----^^^--
-   |           |      |
-   |           |      ...cannot be constrained to this value
-   |           this associated constant...
+   |           ^^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
 
-error: cannot constrain an associated constant to a value
-  --> $DIR/recover-assoc-const-constraint.rs:4:11
+error[E0658]: associated const equality is incomplete
+  --> $DIR/recover-assoc-const-constraint.rs:5:11
    |
 LL |     bar::<Item = { 42 }>();
-   |           ----^^^------
-   |           |      |
-   |           |      ...cannot be constrained to this value
-   |           this associated constant...
+   |           ^^^^^^^^^^^^^
+   |
+   = note: see issue #92827 <https://github.com/rust-lang/rust/issues/92827> for more information
+   = help: add `#![feature(associated_const_equality)]` to the crate attributes to enable
 
 error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0658`.
index e3ce6cd39bc24f1199612d4daae23d0ca5692f3e..68636f6b907ef7448d2dc922408ff2f544a424d8 100644 (file)
@@ -1,6 +1,3 @@
-fn f<T>() {}
-struct X;
-
 fn main() {
     false == false == false;
     //~^ ERROR comparison operators cannot be chained
@@ -12,15 +9,26 @@ fn main() {
 
     f<X>();
     //~^ ERROR comparison operators cannot be chained
-    //~| HELP use `::<...>` instead of `<...>` to specify type or const arguments
+    //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
 
     f<Result<Option<X>, Option<Option<X>>>(1, 2);
     //~^ ERROR comparison operators cannot be chained
-    //~| HELP use `::<...>` instead of `<...>` to specify type or const arguments
+    //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+
+    let _ = f<u8, i8>();
+    //~^ ERROR expected one of
+    //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+
+    let _ = f<'_, i8>();
+    //~^ ERROR expected one of
+    //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+
+    f<'_>();
+    //~^ comparison operators cannot be chained
+    //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
 
-    use std::convert::identity;
-    let _ = identity<u8>;
+    let _ = f<u8>;
     //~^ ERROR comparison operators cannot be chained
-    //~| HELP use `::<...>` instead of `<...>` to specify type or const arguments
+    //~| HELP use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
     //~| HELP or use `(...)` if you meant to specify fn arguments
 }
index 74429cb438c73452a401b3efc6186902c0a18c2f..cde6f8c674f4b5c53c61a5e43c70f046456a7f83 100644 (file)
@@ -1,5 +1,5 @@
 error: comparison operators cannot be chained
-  --> $DIR/require-parens-for-chained-comparison.rs:5:11
+  --> $DIR/require-parens-for-chained-comparison.rs:2:11
    |
 LL |     false == false == false;
    |           ^^       ^^
@@ -10,7 +10,7 @@ LL |     false == false && false == false;
    |                    ++++++++
 
 error: comparison operators cannot be chained
-  --> $DIR/require-parens-for-chained-comparison.rs:9:11
+  --> $DIR/require-parens-for-chained-comparison.rs:6:11
    |
 LL |     false == 0 < 2;
    |           ^^   ^
@@ -21,35 +21,68 @@ LL |     false == (0 < 2);
    |              +     +
 
 error: comparison operators cannot be chained
-  --> $DIR/require-parens-for-chained-comparison.rs:13:6
+  --> $DIR/require-parens-for-chained-comparison.rs:10:6
    |
 LL |     f<X>();
    |      ^ ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     f::<X>();
    |      ++
 
 error: comparison operators cannot be chained
-  --> $DIR/require-parens-for-chained-comparison.rs:17:6
+  --> $DIR/require-parens-for-chained-comparison.rs:14:6
    |
 LL |     f<Result<Option<X>, Option<Option<X>>>(1, 2);
    |      ^      ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     f::<Result<Option<X>, Option<Option<X>>>(1, 2);
    |      ++
 
+error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,`
+  --> $DIR/require-parens-for-chained-comparison.rs:18:17
+   |
+LL |     let _ = f<u8, i8>();
+   |                 ^ expected one of 8 possible tokens
+   |
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+   |
+LL |     let _ = f::<u8, i8>();
+   |              ++
+
+error: expected one of `.`, `:`, `;`, `?`, `else`, `for`, `loop`, `while`, `{`, or an operator, found `,`
+  --> $DIR/require-parens-for-chained-comparison.rs:22:17
+   |
+LL |     let _ = f<'_, i8>();
+   |                 ^ expected one of 10 possible tokens
+   |
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+   |
+LL |     let _ = f::<'_, i8>();
+   |              ++
+
+error: comparison operators cannot be chained
+  --> $DIR/require-parens-for-chained-comparison.rs:26:6
+   |
+LL |     f<'_>();
+   |      ^  ^
+   |
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+   |
+LL |     f::<'_>();
+   |      ++
+
 error: comparison operators cannot be chained
-  --> $DIR/require-parens-for-chained-comparison.rs:22:21
+  --> $DIR/require-parens-for-chained-comparison.rs:30:14
    |
-LL |     let _ = identity<u8>;
-   |                     ^  ^
+LL |     let _ = f<u8>;
+   |              ^  ^
    |
-   = help: use `::<...>` instead of `<...>` to specify type or const arguments
+   = help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    = help: or use `(...)` if you meant to specify fn arguments
 
-error: aborting due to 5 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/parser/trailing-question-in-type.fixed b/src/test/ui/parser/trailing-question-in-type.fixed
new file mode 100644 (file)
index 0000000..6ea2448
--- /dev/null
@@ -0,0 +1,10 @@
+// run-rustfix
+
+fn foo() -> Option<i32> { //~ ERROR invalid `?` in type
+    let x: Option<i32> = Some(1); //~ ERROR invalid `?` in type
+    x
+}
+
+fn main() {
+    let _: Option<i32> = foo();
+}
diff --git a/src/test/ui/parser/trailing-question-in-type.rs b/src/test/ui/parser/trailing-question-in-type.rs
new file mode 100644 (file)
index 0000000..b1c5083
--- /dev/null
@@ -0,0 +1,10 @@
+// run-rustfix
+
+fn foo() -> i32? { //~ ERROR invalid `?` in type
+    let x: i32? = Some(1); //~ ERROR invalid `?` in type
+    x
+}
+
+fn main() {
+    let _: Option<i32> = foo();
+}
diff --git a/src/test/ui/parser/trailing-question-in-type.stderr b/src/test/ui/parser/trailing-question-in-type.stderr
new file mode 100644 (file)
index 0000000..a3cd419
--- /dev/null
@@ -0,0 +1,24 @@
+error: invalid `?` in type
+  --> $DIR/trailing-question-in-type.rs:3:16
+   |
+LL | fn foo() -> i32? {
+   |                ^ `?` is only allowed on expressions, not types
+   |
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+   |
+LL | fn foo() -> Option<i32> {
+   |             +++++++   ~
+
+error: invalid `?` in type
+  --> $DIR/trailing-question-in-type.rs:4:15
+   |
+LL |     let x: i32? = Some(1);
+   |               ^ `?` is only allowed on expressions, not types
+   |
+help: if you meant to express that the type might not contain a value, use the `Option` wrapper type
+   |
+LL |     let x: Option<i32> = Some(1);
+   |            +++++++   ~
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/pattern/issue-82290.rs b/src/test/ui/pattern/issue-82290.rs
deleted file mode 100644 (file)
index d8da0ac..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-// check-pass
-
-#![feature(let_chains)] //~ WARN the feature `let_chains` is incomplete
-
-fn main() {
-    if true && let x = 1 { //~ WARN irrefutable `let` pattern
-        let _ = x;
-    }
-}
diff --git a/src/test/ui/pattern/issue-82290.stderr b/src/test/ui/pattern/issue-82290.stderr
deleted file mode 100644 (file)
index 0a3cf2c..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/issue-82290.rs:3:12
-   |
-LL | #![feature(let_chains)]
-   |            ^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-
-warning: irrefutable `let` pattern
-  --> $DIR/issue-82290.rs:6:16
-   |
-LL |     if true && let x = 1 {
-   |                ^^^^^^^^^
-   |
-   = note: `#[warn(irrefutable_let_patterns)]` on by default
-   = note: this pattern will always match, so the `let` is useless
-   = help: consider removing `let`
-
-warning: 2 warnings emitted
-
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 379491f3126b06e0e978a035e74a87f492284454..a259aa2e6ec0c5d145d31a9c4040a353ac6f510a 100644 (file)
@@ -4,6 +4,4 @@
 fn main() {
     let _ = #[cfg_eval] #[cfg(FALSE)] 0;
     //~^ ERROR removing an expression is not supported in this position
-    //~| ERROR removing an expression is not supported in this position
-    //~| ERROR removing an expression is not supported in this position
 }
index 010ac006b0bee3b8e69eb8135c234d9d9d98190e..df8b6d5f382a19f73755e5594f0380c8bd992be0 100644 (file)
@@ -4,17 +4,5 @@ error: removing an expression is not supported in this position
 LL |     let _ = #[cfg_eval] #[cfg(FALSE)] 0;
    |                         ^^^^^^^^^^^^^
 
-error: removing an expression is not supported in this position
-  --> $DIR/cfg-eval-fail.rs:5:25
-   |
-LL |     let _ = #[cfg_eval] #[cfg(FALSE)] 0;
-   |                         ^^^^^^^^^^^^^
-
-error: removing an expression is not supported in this position
-  --> $DIR/cfg-eval-fail.rs:5:25
-   |
-LL |     let _ = #[cfg_eval] #[cfg(FALSE)] 0;
-   |                         ^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to previous error
 
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`.
index 2a2c0be52630b7002c83a1ea0830f190ef21e7ae..34d2d84da934ff6b28a8389ec1b285b981ea2c9d 100644 (file)
@@ -8,36 +8,36 @@ fn _if_let_guard() {
         //~^ ERROR `if let` guards are experimental
 
         () if (let 0 = 1) => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if (((let 0 = 1))) => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if true && let 0 = 1 => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if let 0 = 1 && true => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if (let 0 = 1) && true => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if true && (let 0 = 1) => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
 
         () if (let 0 = 1) && (let 0 = 1) => {}
-        //~^ ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
 
         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
-        //~^ ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
-        //~| ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
+        //~| ERROR `let` expressions in this position are unstable
 
         () if let Range { start: _, end: _ } = (true..true) && false => {}
-        //~^ ERROR `let` expressions in this position are experimental
+        //~^ ERROR `let` expressions in this position are unstable
         _ => {}
     }
 }
@@ -52,9 +52,9 @@ macro_rules! use_expr {
         }
     }
     use_expr!((let 0 = 1 && 0 == 0));
-    //~^ ERROR `let` expressions in this position are experimental
+    //~^ ERROR `let` expressions in this position are unstable
     use_expr!((let 0 = 1));
-    //~^ ERROR `let` expressions in this position are experimental
+    //~^ ERROR `let` expressions in this position are unstable
     match () {
         #[cfg(FALSE)]
         () if let 0 = 1 => {}
index bedcdcb019ba9272d96dab525018a6fc8542f5d6..0cda6ba9a99279d51a57289b6a20633331d3e526 100644 (file)
@@ -27,7 +27,7 @@ LL |         () if let 0 = 1 => {}
    = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:10:16
    |
 LL |         () if (let 0 = 1) => {}
@@ -35,9 +35,8 @@ LL |         () if (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:13:18
    |
 LL |         () if (((let 0 = 1))) => {}
@@ -45,9 +44,8 @@ LL |         () if (((let 0 = 1))) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:16:23
    |
 LL |         () if true && let 0 = 1 => {}
@@ -55,9 +53,8 @@ LL |         () if true && let 0 = 1 => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:19:15
    |
 LL |         () if let 0 = 1 && true => {}
@@ -65,9 +62,8 @@ LL |         () if let 0 = 1 && true => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:22:16
    |
 LL |         () if (let 0 = 1) && true => {}
@@ -75,9 +71,8 @@ LL |         () if (let 0 = 1) && true => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:25:24
    |
 LL |         () if true && (let 0 = 1) => {}
@@ -85,9 +80,8 @@ LL |         () if true && (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:28:16
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
@@ -95,9 +89,8 @@ LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:28:31
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
@@ -105,9 +98,8 @@ LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:15
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -115,9 +107,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:28
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -125,9 +116,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:42
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -135,9 +125,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:55
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -145,9 +134,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:68
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
@@ -155,9 +143,8 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:39:15
    |
 LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
@@ -165,9 +152,8 @@ LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:54:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
@@ -175,9 +161,8 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:56:16
    |
 LL |     use_expr!((let 0 = 1));
@@ -185,7 +170,6 @@ LL |     use_expr!((let 0 = 1));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
 error: aborting due to 19 previous errors
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs b/src/test/ui/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
new file mode 100644 (file)
index 0000000..708bcdd
--- /dev/null
@@ -0,0 +1,15 @@
+// run-pass
+
+#![feature(let_chains)]
+
+fn main() {
+    let first = Some(1);
+    let second = Some(2);
+    let mut n = 0;
+    if let x = first && let y = second && 1 == 1 {
+        assert_eq!(x, first);
+        assert_eq!(y, second);
+        n = 1;
+    }
+    assert_eq!(n, 1);
+}
index 710fdd57ed7b3739c734254f32fec2410ee91385..69bc189dd3579cd795fe0730b7cfb283826ce4f3 100644 (file)
@@ -1,4 +1,4 @@
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 // compile-flags: -Z unpretty=expanded
 
 fn main() {
index 6052ea95d0f85fe37666e2688ad1082b5f0ecb44..e737ef26e9b3819822566c628bd3f2314be4e9b7 100644 (file)
@@ -4,7 +4,7 @@
 use ::std::prelude::rust_2015::*;
 #[macro_use]
 extern crate std;
-// build-pass (FIXME(62277): could be check-pass?)
+// check-pass
 // compile-flags: -Z unpretty=expanded
 
 fn main() { if let 0 = 1 {} }
diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.rs
new file mode 100644 (file)
index 0000000..a7e108d
--- /dev/null
@@ -0,0 +1,20 @@
+fn and_chain() {
+    let z;
+    if true && { z = 3; true} && z == 3 {}
+    //~^ ERROR use of possibly-uninitialized
+}
+
+fn and_chain_2() {
+    let z;
+    true && { z = 3; true} && z == 3;
+    //~^ ERROR use of possibly-uninitialized
+}
+
+fn or_chain() {
+    let z;
+    if false || { z = 3; false} || z == 3 {}
+    //~^ ERROR use of possibly-uninitialized
+}
+
+fn main() {
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr b/src/test/ui/rfc-2497-if-let-chains/chains-without-let.stderr
new file mode 100644 (file)
index 0000000..3c47040
--- /dev/null
@@ -0,0 +1,21 @@
+error[E0381]: use of possibly-uninitialized variable: `z`
+  --> $DIR/chains-without-let.rs:3:34
+   |
+LL |     if true && { z = 3; true} && z == 3 {}
+   |                                  ^ use of possibly-uninitialized `z`
+
+error[E0381]: use of possibly-uninitialized variable: `z`
+  --> $DIR/chains-without-let.rs:9:31
+   |
+LL |     true && { z = 3; true} && z == 3;
+   |                               ^ use of possibly-uninitialized `z`
+
+error[E0381]: use of possibly-uninitialized variable: `z`
+  --> $DIR/chains-without-let.rs:15:36
+   |
+LL |     if false || { z = 3; false} || z == 3 {}
+   |                                    ^ use of possibly-uninitialized `z`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0381`.
index b0b3464c61017b4cadf9717fdef21f40a510194d..5b2693d07a7905eb5944555a93943d9c0c7bfd7f 100644 (file)
@@ -18,7 +18,6 @@
 // To that end, we check some positions which is not part of the language above.
 
 #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
-//~^ WARN the feature `let_chains` is incomplete
 
 #![allow(irrefutable_let_patterns)]
 
index 1433a16d7274a57e4b074a51036f75440ccbd83c..4c830554d435c9c6949956575d2f5542a54891fc 100644 (file)
@@ -1,5 +1,5 @@
 error: expressions must be enclosed in braces to be used as const generic arguments
-  --> $DIR/disallowed-positions.rs:233:9
+  --> $DIR/disallowed-positions.rs:232:9
    |
 LL |         true && let 1 = 1
    |         ^^^^^^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL |         { true && let 1 = 1 }
    |         +                   +
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:30:9
+  --> $DIR/disallowed-positions.rs:29:9
    |
 LL |     if &let 0 = 0 {}
    |         ^^^^^^^^^
@@ -19,7 +19,7 @@ LL |     if &let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:33:9
+  --> $DIR/disallowed-positions.rs:32:9
    |
 LL |     if !let 0 = 0 {}
    |         ^^^^^^^^^
@@ -28,7 +28,7 @@ LL |     if !let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:34:9
+  --> $DIR/disallowed-positions.rs:33:9
    |
 LL |     if *let 0 = 0 {}
    |         ^^^^^^^^^
@@ -37,7 +37,7 @@ LL |     if *let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:36:9
+  --> $DIR/disallowed-positions.rs:35:9
    |
 LL |     if -let 0 = 0 {}
    |         ^^^^^^^^^
@@ -46,7 +46,7 @@ LL |     if -let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:44:9
+  --> $DIR/disallowed-positions.rs:43:9
    |
 LL |     if (let 0 = 0)? {}
    |         ^^^^^^^^^
@@ -55,7 +55,7 @@ LL |     if (let 0 = 0)? {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:48:16
+  --> $DIR/disallowed-positions.rs:47:16
    |
 LL |     if true || let 0 = 0 {}
    |                ^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     if true || let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:49:17
+  --> $DIR/disallowed-positions.rs:48:17
    |
 LL |     if (true || let 0 = 0) {}
    |                 ^^^^^^^^^
@@ -73,7 +73,7 @@ LL |     if (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:50:25
+  --> $DIR/disallowed-positions.rs:49:25
    |
 LL |     if true && (true || let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -82,7 +82,7 @@ LL |     if true && (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:51:25
+  --> $DIR/disallowed-positions.rs:50:25
    |
 LL |     if true || (true && let 0 = 0) {}
    |                         ^^^^^^^^^
@@ -91,7 +91,7 @@ LL |     if true || (true && let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:54:12
+  --> $DIR/disallowed-positions.rs:53:12
    |
 LL |     if x = let 0 = 0 {}
    |            ^^^^^^^^^
@@ -100,7 +100,7 @@ LL |     if x = let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:57:15
+  --> $DIR/disallowed-positions.rs:56:15
    |
 LL |     if true..(let 0 = 0) {}
    |               ^^^^^^^^^
@@ -109,7 +109,7 @@ LL |     if true..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:59:11
+  --> $DIR/disallowed-positions.rs:58:11
    |
 LL |     if ..(let 0 = 0) {}
    |           ^^^^^^^^^
@@ -118,7 +118,7 @@ LL |     if ..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:61:9
+  --> $DIR/disallowed-positions.rs:60:9
    |
 LL |     if (let 0 = 0).. {}
    |         ^^^^^^^^^
@@ -127,7 +127,7 @@ LL |     if (let 0 = 0).. {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:65:8
+  --> $DIR/disallowed-positions.rs:64:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +136,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:69:8
+  --> $DIR/disallowed-positions.rs:68:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +145,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:76:8
+  --> $DIR/disallowed-positions.rs:75:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,7 +154,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:84:8
+  --> $DIR/disallowed-positions.rs:83:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +163,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:90:19
+  --> $DIR/disallowed-positions.rs:89:19
    |
 LL |     if let true = let true = true {}
    |                   ^^^^^^^^^^^^^^^
@@ -172,7 +172,7 @@ LL |     if let true = let true = true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:94:12
+  --> $DIR/disallowed-positions.rs:93:12
    |
 LL |     while &let 0 = 0 {}
    |            ^^^^^^^^^
@@ -181,7 +181,7 @@ LL |     while &let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:97:12
+  --> $DIR/disallowed-positions.rs:96:12
    |
 LL |     while !let 0 = 0 {}
    |            ^^^^^^^^^
@@ -190,7 +190,7 @@ LL |     while !let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:98:12
+  --> $DIR/disallowed-positions.rs:97:12
    |
 LL |     while *let 0 = 0 {}
    |            ^^^^^^^^^
@@ -199,7 +199,7 @@ LL |     while *let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:100:12
+  --> $DIR/disallowed-positions.rs:99:12
    |
 LL |     while -let 0 = 0 {}
    |            ^^^^^^^^^
@@ -208,7 +208,7 @@ LL |     while -let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:108:12
+  --> $DIR/disallowed-positions.rs:107:12
    |
 LL |     while (let 0 = 0)? {}
    |            ^^^^^^^^^
@@ -217,7 +217,7 @@ LL |     while (let 0 = 0)? {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:112:19
+  --> $DIR/disallowed-positions.rs:111:19
    |
 LL |     while true || let 0 = 0 {}
    |                   ^^^^^^^^^
@@ -226,7 +226,7 @@ LL |     while true || let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:113:20
+  --> $DIR/disallowed-positions.rs:112:20
    |
 LL |     while (true || let 0 = 0) {}
    |                    ^^^^^^^^^
@@ -235,7 +235,7 @@ LL |     while (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:114:28
+  --> $DIR/disallowed-positions.rs:113:28
    |
 LL |     while true && (true || let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -244,7 +244,7 @@ LL |     while true && (true || let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:115:28
+  --> $DIR/disallowed-positions.rs:114:28
    |
 LL |     while true || (true && let 0 = 0) {}
    |                            ^^^^^^^^^
@@ -253,7 +253,7 @@ LL |     while true || (true && let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:118:15
+  --> $DIR/disallowed-positions.rs:117:15
    |
 LL |     while x = let 0 = 0 {}
    |               ^^^^^^^^^
@@ -262,7 +262,7 @@ LL |     while x = let 0 = 0 {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:121:18
+  --> $DIR/disallowed-positions.rs:120:18
    |
 LL |     while true..(let 0 = 0) {}
    |                  ^^^^^^^^^
@@ -271,7 +271,7 @@ LL |     while true..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:123:14
+  --> $DIR/disallowed-positions.rs:122:14
    |
 LL |     while ..(let 0 = 0) {}
    |              ^^^^^^^^^
@@ -280,7 +280,7 @@ LL |     while ..(let 0 = 0) {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:125:12
+  --> $DIR/disallowed-positions.rs:124:12
    |
 LL |     while (let 0 = 0).. {}
    |            ^^^^^^^^^
@@ -289,7 +289,7 @@ LL |     while (let 0 = 0).. {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:129:11
+  --> $DIR/disallowed-positions.rs:128:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -298,7 +298,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:133:11
+  --> $DIR/disallowed-positions.rs:132:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -307,7 +307,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:140:11
+  --> $DIR/disallowed-positions.rs:139:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -316,7 +316,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:148:11
+  --> $DIR/disallowed-positions.rs:147:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -325,7 +325,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:154:22
+  --> $DIR/disallowed-positions.rs:153:22
    |
 LL |     while let true = let true = true {}
    |                      ^^^^^^^^^^^^^^^
@@ -334,7 +334,7 @@ LL |     while let true = let true = true {}
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:168:6
+  --> $DIR/disallowed-positions.rs:167:6
    |
 LL |     &let 0 = 0;
    |      ^^^^^^^^^
@@ -343,7 +343,7 @@ LL |     &let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:170:6
+  --> $DIR/disallowed-positions.rs:169:6
    |
 LL |     !let 0 = 0;
    |      ^^^^^^^^^
@@ -352,7 +352,7 @@ LL |     !let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:171:6
+  --> $DIR/disallowed-positions.rs:170:6
    |
 LL |     *let 0 = 0;
    |      ^^^^^^^^^
@@ -361,7 +361,7 @@ LL |     *let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:173:6
+  --> $DIR/disallowed-positions.rs:172:6
    |
 LL |     -let 0 = 0;
    |      ^^^^^^^^^
@@ -370,7 +370,7 @@ LL |     -let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:181:6
+  --> $DIR/disallowed-positions.rs:180:6
    |
 LL |     (let 0 = 0)?;
    |      ^^^^^^^^^
@@ -379,7 +379,7 @@ LL |     (let 0 = 0)?;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:185:13
+  --> $DIR/disallowed-positions.rs:184:13
    |
 LL |     true || let 0 = 0;
    |             ^^^^^^^^^
@@ -388,7 +388,7 @@ LL |     true || let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:186:14
+  --> $DIR/disallowed-positions.rs:185:14
    |
 LL |     (true || let 0 = 0);
    |              ^^^^^^^^^
@@ -397,7 +397,7 @@ LL |     (true || let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:187:22
+  --> $DIR/disallowed-positions.rs:186:22
    |
 LL |     true && (true || let 0 = 0);
    |                      ^^^^^^^^^
@@ -406,7 +406,7 @@ LL |     true && (true || let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:190:9
+  --> $DIR/disallowed-positions.rs:189:9
    |
 LL |     x = let 0 = 0;
    |         ^^^^^^^^^
@@ -415,7 +415,7 @@ LL |     x = let 0 = 0;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:192:12
+  --> $DIR/disallowed-positions.rs:191:12
    |
 LL |     true..(let 0 = 0);
    |            ^^^^^^^^^
@@ -424,7 +424,7 @@ LL |     true..(let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:193:8
+  --> $DIR/disallowed-positions.rs:192:8
    |
 LL |     ..(let 0 = 0);
    |        ^^^^^^^^^
@@ -433,7 +433,7 @@ LL |     ..(let 0 = 0);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:194:6
+  --> $DIR/disallowed-positions.rs:193:6
    |
 LL |     (let 0 = 0)..;
    |      ^^^^^^^^^
@@ -442,7 +442,7 @@ LL |     (let 0 = 0)..;
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:196:6
+  --> $DIR/disallowed-positions.rs:195:6
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -451,7 +451,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:200:6
+  --> $DIR/disallowed-positions.rs:199:6
    |
 LL |     (let true = let true = true);
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -460,7 +460,7 @@ LL |     (let true = let true = true);
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:204:6
+  --> $DIR/disallowed-positions.rs:203:6
    |
 LL |     &let 0 = 0
    |      ^^^^^^^^^
@@ -469,7 +469,7 @@ LL |     &let 0 = 0
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:215:17
+  --> $DIR/disallowed-positions.rs:214:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -478,7 +478,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:219:17
+  --> $DIR/disallowed-positions.rs:218:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -487,7 +487,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:223:17
+  --> $DIR/disallowed-positions.rs:222:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -496,7 +496,7 @@ LL |         true && let 1 = 1
    = note: as well as when nested within `&&` and parentheses in those conditions
 
 error: `let` expressions are not supported here
-  --> $DIR/disallowed-positions.rs:233:17
+  --> $DIR/disallowed-positions.rs:232:17
    |
 LL |         true && let 1 = 1
    |                 ^^^^^^^^^
@@ -504,17 +504,8 @@ LL |         true && let 1 = 1
    = note: only supported directly in conditions of `if`- and `while`-expressions
    = note: as well as when nested within `&&` and parentheses in those conditions
 
-warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/disallowed-positions.rs:20:12
-   |
-LL | #![feature(let_chains)] // Avoid inflating `.stderr` with overzealous gates in this test.
-   |            ^^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
-
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:30:8
+  --> $DIR/disallowed-positions.rs:29:8
    |
 LL |     if &let 0 = 0 {}
    |        ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -526,19 +517,19 @@ LL +     if let 0 = 0 {}
    | 
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:34:8
+  --> $DIR/disallowed-positions.rs:33:8
    |
 LL |     if *let 0 = 0 {}
    |        ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:36:8
+  --> $DIR/disallowed-positions.rs:35:8
    |
 LL |     if -let 0 = 0 {}
    |        ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:44:8
+  --> $DIR/disallowed-positions.rs:43:8
    |
 LL |     if (let 0 = 0)? {}
    |        ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -546,7 +537,7 @@ LL |     if (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:44:19
+  --> $DIR/disallowed-positions.rs:43:19
    |
 LL | / fn nested_within_if_expr() {
 LL | |     if &let 0 = 0 {}
@@ -563,7 +554,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:54:8
+  --> $DIR/disallowed-positions.rs:53:8
    |
 LL |     if x = let 0 = 0 {}
    |        ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -574,7 +565,7 @@ LL |     if x == let 0 = 0 {}
    |          ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:57:8
+  --> $DIR/disallowed-positions.rs:56:8
    |
 LL |     if true..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -583,7 +574,7 @@ LL |     if true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:59:8
+  --> $DIR/disallowed-positions.rs:58:8
    |
 LL |     if ..(let 0 = 0) {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -592,7 +583,7 @@ LL |     if ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:61:8
+  --> $DIR/disallowed-positions.rs:60:8
    |
 LL |     if (let 0 = 0).. {}
    |        ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -601,7 +592,7 @@ LL |     if (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:65:12
+  --> $DIR/disallowed-positions.rs:64:12
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -612,7 +603,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:65:8
+  --> $DIR/disallowed-positions.rs:64:8
    |
 LL |     if let Range { start: _, end: _ } = true..true && false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -621,7 +612,7 @@ LL |     if let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:69:12
+  --> $DIR/disallowed-positions.rs:68:12
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -632,7 +623,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:69:8
+  --> $DIR/disallowed-positions.rs:68:8
    |
 LL |     if let Range { start: _, end: _ } = true..true || false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -641,7 +632,7 @@ LL |     if let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:76:12
+  --> $DIR/disallowed-positions.rs:75:12
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -652,16 +643,16 @@ LL |     if let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:76:41
+  --> $DIR/disallowed-positions.rs:75:41
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |                                         ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:76:41: 76:48]`
+           found closure `[closure@$DIR/disallowed-positions.rs:75:41: 75:48]`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:76:8
+  --> $DIR/disallowed-positions.rs:75:8
    |
 LL |     if let Range { start: F, end } = F..|| true {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -670,7 +661,7 @@ LL |     if let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:84:12
+  --> $DIR/disallowed-positions.rs:83:12
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |            ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -681,13 +672,13 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:84:44
+  --> $DIR/disallowed-positions.rs:83:44
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |                                            ^^^^^^^ expected `bool`, found `&&bool`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:84:8
+  --> $DIR/disallowed-positions.rs:83:8
    |
 LL |     if let Range { start: true, end } = t..&&false {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -696,7 +687,7 @@ LL |     if let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:40:20
+  --> $DIR/disallowed-positions.rs:39:20
    |
 LL |         if let 0 = 0? {}
    |                    ^^ the `?` operator cannot be applied to type `{integer}`
@@ -704,7 +695,7 @@ LL |         if let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:94:11
+  --> $DIR/disallowed-positions.rs:93:11
    |
 LL |     while &let 0 = 0 {}
    |           ^^^^^^^^^^ expected `bool`, found `&bool`
@@ -716,19 +707,19 @@ LL +     while let 0 = 0 {}
    | 
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:98:11
+  --> $DIR/disallowed-positions.rs:97:11
    |
 LL |     while *let 0 = 0 {}
    |           ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:100:11
+  --> $DIR/disallowed-positions.rs:99:11
    |
 LL |     while -let 0 = 0 {}
    |           ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:108:11
+  --> $DIR/disallowed-positions.rs:107:11
    |
 LL |     while (let 0 = 0)? {}
    |           ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -736,7 +727,7 @@ LL |     while (let 0 = 0)? {}
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:108:22
+  --> $DIR/disallowed-positions.rs:107:22
    |
 LL | / fn nested_within_while_expr() {
 LL | |     while &let 0 = 0 {}
@@ -753,7 +744,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:118:11
+  --> $DIR/disallowed-positions.rs:117:11
    |
 LL |     while x = let 0 = 0 {}
    |           ^^^^^^^^^^^^^ expected `bool`, found `()`
@@ -764,7 +755,7 @@ LL |     while x == let 0 = 0 {}
    |             ~~
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:121:11
+  --> $DIR/disallowed-positions.rs:120:11
    |
 LL |     while true..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -773,7 +764,7 @@ LL |     while true..(let 0 = 0) {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:123:11
+  --> $DIR/disallowed-positions.rs:122:11
    |
 LL |     while ..(let 0 = 0) {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo`
@@ -782,7 +773,7 @@ LL |     while ..(let 0 = 0) {}
             found struct `RangeTo<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:125:11
+  --> $DIR/disallowed-positions.rs:124:11
    |
 LL |     while (let 0 = 0).. {}
    |           ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom`
@@ -791,7 +782,7 @@ LL |     while (let 0 = 0).. {}
             found struct `RangeFrom<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:129:15
+  --> $DIR/disallowed-positions.rs:128:15
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -802,7 +793,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:129:11
+  --> $DIR/disallowed-positions.rs:128:11
    |
 LL |     while let Range { start: _, end: _ } = true..true && false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -811,7 +802,7 @@ LL |     while let Range { start: _, end: _ } = true..true && false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:133:15
+  --> $DIR/disallowed-positions.rs:132:15
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -822,7 +813,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:133:11
+  --> $DIR/disallowed-positions.rs:132:11
    |
 LL |     while let Range { start: _, end: _ } = true..true || false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -831,7 +822,7 @@ LL |     while let Range { start: _, end: _ } = true..true || false {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:140:15
+  --> $DIR/disallowed-positions.rs:139:15
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `fn() -> bool`
@@ -842,16 +833,16 @@ LL |     while let Range { start: F, end } = F..|| true {}
                   found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:140:44
+  --> $DIR/disallowed-positions.rs:139:44
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |                                            ^^^^^^^ expected `bool`, found closure
    |
    = note: expected type `bool`
-           found closure `[closure@$DIR/disallowed-positions.rs:140:44: 140:51]`
+           found closure `[closure@$DIR/disallowed-positions.rs:139:44: 139:51]`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:140:11
+  --> $DIR/disallowed-positions.rs:139:11
    |
 LL |     while let Range { start: F, end } = F..|| true {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -860,7 +851,7 @@ LL |     while let Range { start: F, end } = F..|| true {}
             found struct `std::ops::Range<bool>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:148:15
+  --> $DIR/disallowed-positions.rs:147:15
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^   - this expression has type `&&bool`
@@ -871,13 +862,13 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:148:47
+  --> $DIR/disallowed-positions.rs:147:47
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |                                               ^^^^^^^ expected `bool`, found `&&bool`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:148:11
+  --> $DIR/disallowed-positions.rs:147:11
    |
 LL |     while let Range { start: true, end } = t..&&false {}
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::Range`
@@ -886,7 +877,7 @@ LL |     while let Range { start: true, end } = t..&&false {}
             found struct `std::ops::Range<bool>`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:104:23
+  --> $DIR/disallowed-positions.rs:103:23
    |
 LL |         while let 0 = 0? {}
    |                       ^^ the `?` operator cannot be applied to type `{integer}`
@@ -894,19 +885,19 @@ LL |         while let 0 = 0? {}
    = help: the trait `Try` is not implemented for `{integer}`
 
 error[E0614]: type `bool` cannot be dereferenced
-  --> $DIR/disallowed-positions.rs:171:5
+  --> $DIR/disallowed-positions.rs:170:5
    |
 LL |     *let 0 = 0;
    |     ^^^^^^^^^^
 
 error[E0600]: cannot apply unary operator `-` to type `bool`
-  --> $DIR/disallowed-positions.rs:173:5
+  --> $DIR/disallowed-positions.rs:172:5
    |
 LL |     -let 0 = 0;
    |     ^^^^^^^^^^ cannot apply unary operator `-`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:181:5
+  --> $DIR/disallowed-positions.rs:180:5
    |
 LL |     (let 0 = 0)?;
    |     ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool`
@@ -914,7 +905,7 @@ LL |     (let 0 = 0)?;
    = help: the trait `Try` is not implemented for `bool`
 
 error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`)
-  --> $DIR/disallowed-positions.rs:181:16
+  --> $DIR/disallowed-positions.rs:180:16
    |
 LL | / fn outside_if_and_while_expr() {
 LL | |     &let 0 = 0;
@@ -931,7 +922,7 @@ LL | | }
    = help: the trait `FromResidual<_>` is not implemented for `()`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:196:10
+  --> $DIR/disallowed-positions.rs:195:10
    |
 LL |     (let Range { start: _, end: _ } = true..true || false);
    |          ^^^^^^^^^^^^^^^^^^^^^^^^^^   ---- this expression has type `bool`
@@ -942,7 +933,7 @@ LL |     (let Range { start: _, end: _ } = true..true || false);
             found struct `std::ops::Range<_>`
 
 error[E0308]: mismatched types
-  --> $DIR/disallowed-positions.rs:204:5
+  --> $DIR/disallowed-positions.rs:203:5
    |
 LL | fn outside_if_and_while_expr() {
    |                                - help: try adding a return type: `-> &bool`
@@ -951,14 +942,14 @@ LL |     &let 0 = 0
    |     ^^^^^^^^^^ expected `()`, found `&bool`
 
 error[E0277]: the `?` operator can only be applied to values that implement `Try`
-  --> $DIR/disallowed-positions.rs:177:17
+  --> $DIR/disallowed-positions.rs:176:17
    |
 LL |         let 0 = 0?;
    |                 ^^ the `?` operator cannot be applied to type `{integer}`
    |
    = help: the trait `Try` is not implemented for `{integer}`
 
-error: aborting due to 103 previous errors; 1 warning emitted
+error: aborting due to 103 previous errors
 
 Some errors have detailed explanations: E0277, E0308, E0600, E0614.
 For more information about an error, try `rustc --explain E0277`.
index 2b4259e9dc1506479fc6af5204b85c80b0d87e91..53fec8316e7e710400e9e5065054103729b44388 100644 (file)
@@ -12,79 +12,79 @@ fn _if() {
     if let 0 = 1 {} // Stable!
 
     if (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if (((let 0 = 1))) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if true && let 0 = 1 {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if let 0 = 1 && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if (let 0 = 1) && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if true && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     if (let 0 = 1) && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     if let Range { start: _, end: _ } = (true..true) && false {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 }
 
 fn _while() {
     while let 0 = 1 {} // Stable!
 
     while (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while (((let 0 = 1))) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while true && let 0 = 1 {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while let 0 = 1 && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while (let 0 = 1) && true {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while true && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     while (let 0 = 1) && (let 0 = 1) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
-    //~| ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
+    //~| ERROR `let` expressions in this position are unstable [E0658]
 
     while let Range { start: _, end: _ } = (true..true) && false {}
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 }
 
 fn _macros() {
     macro_rules! noop_expr { ($e:expr) => {}; }
 
     noop_expr!((let 0 = 1));
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
 
     macro_rules! use_expr {
         ($e:expr) => {
@@ -93,11 +93,11 @@ macro_rules! use_expr {
         }
     }
     use_expr!((let 0 = 1 && 0 == 0));
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
     use_expr!((let 0 = 1));
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
     #[cfg(FALSE)] (let 0 = 1);
-    //~^ ERROR `let` expressions in this position are experimental [E0658]
+    //~^ ERROR `let` expressions in this position are unstable [E0658]
     use_expr!(let 0 = 1);
     //~^ ERROR no rules expected the token `let`
     // ^--- FIXME(53667): Consider whether `Let` can be added to `ident_can_begin_expr`.
index 180eee0cadfe62baaef644988341054e485e0259..458826498fe2d1044ec7a6e2562f7e138852cb0d 100644 (file)
@@ -7,7 +7,7 @@ LL |     macro_rules! use_expr {
 LL |     use_expr!(let 0 = 1);
    |               ^^^ no rules expected this token in macro call
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:14:9
    |
 LL |     if (let 0 = 1) {}
@@ -15,9 +15,8 @@ LL |     if (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:17:11
    |
 LL |     if (((let 0 = 1))) {}
@@ -25,9 +24,8 @@ LL |     if (((let 0 = 1))) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:20:16
    |
 LL |     if true && let 0 = 1 {}
@@ -35,9 +33,8 @@ LL |     if true && let 0 = 1 {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:23:8
    |
 LL |     if let 0 = 1 && true {}
@@ -45,9 +42,8 @@ LL |     if let 0 = 1 && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:26:9
    |
 LL |     if (let 0 = 1) && true {}
@@ -55,9 +51,8 @@ LL |     if (let 0 = 1) && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:29:17
    |
 LL |     if true && (let 0 = 1) {}
@@ -65,9 +60,8 @@ LL |     if true && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:9
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
@@ -75,9 +69,8 @@ LL |     if (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:32:24
    |
 LL |     if (let 0 = 1) && (let 0 = 1) {}
@@ -85,9 +78,8 @@ LL |     if (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:8
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -95,9 +87,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:21
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -105,9 +96,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:35
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -115,9 +105,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:48
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -125,9 +114,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:36:61
    |
 LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -135,9 +123,8 @@ LL |     if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:43:8
    |
 LL |     if let Range { start: _, end: _ } = (true..true) && false {}
@@ -145,9 +132,8 @@ LL |     if let Range { start: _, end: _ } = (true..true) && false {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:50:12
    |
 LL |     while (let 0 = 1) {}
@@ -155,9 +141,8 @@ LL |     while (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:53:14
    |
 LL |     while (((let 0 = 1))) {}
@@ -165,9 +150,8 @@ LL |     while (((let 0 = 1))) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:56:19
    |
 LL |     while true && let 0 = 1 {}
@@ -175,9 +159,8 @@ LL |     while true && let 0 = 1 {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:59:11
    |
 LL |     while let 0 = 1 && true {}
@@ -185,9 +168,8 @@ LL |     while let 0 = 1 && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:62:12
    |
 LL |     while (let 0 = 1) && true {}
@@ -195,9 +177,8 @@ LL |     while (let 0 = 1) && true {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:65:20
    |
 LL |     while true && (let 0 = 1) {}
@@ -205,9 +186,8 @@ LL |     while true && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:68:12
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
@@ -215,9 +195,8 @@ LL |     while (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:68:27
    |
 LL |     while (let 0 = 1) && (let 0 = 1) {}
@@ -225,9 +204,8 @@ LL |     while (let 0 = 1) && (let 0 = 1) {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:11
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -235,9 +213,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:24
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -245,9 +222,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:38
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -255,9 +231,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:51
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -265,9 +240,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:72:64
    |
 LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {}
@@ -275,9 +249,8 @@ LL |     while let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) {
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:79:11
    |
 LL |     while let Range { start: _, end: _ } = (true..true) && false {}
@@ -285,9 +258,8 @@ LL |     while let Range { start: _, end: _ } = (true..true) && false {}
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:99:20
    |
 LL |     #[cfg(FALSE)] (let 0 = 1);
@@ -295,9 +267,8 @@ LL |     #[cfg(FALSE)] (let 0 = 1);
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:86:17
    |
 LL |     noop_expr!((let 0 = 1));
@@ -305,9 +276,8 @@ LL |     noop_expr!((let 0 = 1));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:95:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
@@ -315,9 +285,8 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
-error[E0658]: `let` expressions in this position are experimental
+error[E0658]: `let` expressions in this position are unstable
   --> $DIR/feature-gate.rs:97:16
    |
 LL |     use_expr!((let 0 = 1));
@@ -325,7 +294,6 @@ LL |     use_expr!((let 0 = 1));
    |
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
-   = help: you can write `matches!(<expr>, <pattern>)` instead of `let <pattern> = <expr>`
 
 error: aborting due to 33 previous errors
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs b/src/test/ui/rfc-2497-if-let-chains/irrefutable-lets.rs
new file mode 100644 (file)
index 0000000..5915cb9
--- /dev/null
@@ -0,0 +1,27 @@
+// check-pass
+
+#![feature(let_chains)]
+
+use std::ops::Range;
+
+fn main() {
+    let opt = Some(None..Some(1));
+
+    if let first = &opt && let Some(ref second) = first && let None = second.start {
+    }
+    if let Some(ref first) = opt && let second = first && let _third = second {
+    }
+    if let Some(ref first) = opt
+        && let Range { start: local_start, end: _ } = first
+        && let None = local_start {
+    }
+
+    while let first = &opt && let Some(ref second) = first && let None = second.start {
+    }
+    while let Some(ref first) = opt && let second = first && let _third = second {
+    }
+    while let Some(ref first) = opt
+        && let Range { start: local_start, end: _ } = first
+        && let None = local_start {
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-88498.rs b/src/test/ui/rfc-2497-if-let-chains/issue-88498.rs
new file mode 100644 (file)
index 0000000..3eb8a9a
--- /dev/null
@@ -0,0 +1,16 @@
+// check-pass
+
+pub enum UnOp {
+    Not(Vec<()>),
+}
+
+pub fn foo() {
+    if let Some(x) = None {
+        match x {
+            UnOp::Not(_) => {}
+        }
+    }
+}
+
+fn main() {
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs b/src/test/ui/rfc-2497-if-let-chains/issue-90722.rs
new file mode 100644 (file)
index 0000000..6b7d883
--- /dev/null
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(let_chains)]
+
+fn main() {
+    let x = Some(vec!["test"]);
+
+    if let Some(v) = x && v.is_empty() {
+        println!("x == Some([])");
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs b/src/test/ui/rfc-2497-if-let-chains/issue-92145.rs
new file mode 100644 (file)
index 0000000..7c7e31f
--- /dev/null
@@ -0,0 +1,11 @@
+// check-pass
+
+#![feature(let_chains)]
+
+fn main() {
+    let opt = Some("foo bar");
+
+    if true && let Some(x) = opt {
+        println!("{}", x);
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs b/src/test/ui/rfc-2497-if-let-chains/no-double-assigments.rs
new file mode 100644 (file)
index 0000000..6b91c45
--- /dev/null
@@ -0,0 +1,9 @@
+// check-pass
+
+fn main() {
+    loop {
+        // [1][0] should leave top scope
+        if true && [1][0] == 1 && true {
+        }
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs b/src/test/ui/rfc-2497-if-let-chains/then-else-blocks.rs
new file mode 100644 (file)
index 0000000..0856a10
--- /dev/null
@@ -0,0 +1,35 @@
+// run-pass
+
+#![feature(let_chains)]
+
+fn check_if_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
+    if let Some(first) = opt
+        && let Some(second) = first
+        && let Some(third) = second
+        && third == value
+    {
+        true
+    }
+    else {
+        false
+    }
+}
+
+fn check_while_let(opt: Option<Option<Option<i32>>>, value: i32) -> bool {
+    while let Some(first) = opt
+        && let Some(second) = first
+        && let Some(third) = second
+        && third == value
+    {
+        return true;
+    }
+    false
+}
+
+fn main() {
+    assert_eq!(check_if_let(Some(Some(Some(1))), 1), true);
+    assert_eq!(check_if_let(Some(Some(Some(1))), 9), false);
+
+    assert_eq!(check_while_let(Some(Some(Some(1))), 1), true);
+    assert_eq!(check_while_let(Some(Some(Some(1))), 9), false);
+}
index 0ab994ecd45bedeff1ce909a16f40b9049c51a13..2a15b1d799f846fc7379d8d28ec7a4c84d46a63c 100644 (file)
@@ -1,4 +1,4 @@
-// only-windows-msvc
+// only-windows
 #![feature(raw_dylib)]
 //~^ WARN the feature `raw_dylib` is incomplete
 
index d02bebc9d61d26a87d895d88743b7f2046a52613..13c9aa01e34ae8126858fb760bf1b32f37f5d2e8 100644 (file)
@@ -1,4 +1,5 @@
-// only-i686-pc-windows-msvc
+// only-x86
+// only-windows
 // compile-flags: --crate-type lib --emit link
 #![allow(clashing_extern_declarations)]
 #![feature(raw_dylib)]
index a9cfd6b23f9f8d8df177d128e41c89b089c084ad..93ca8f4d8d448e1780f22d56a80e32d43898f8e3 100644 (file)
@@ -1,5 +1,5 @@
 warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/multiple-declarations.rs:4:12
+  --> $DIR/multiple-declarations.rs:5:12
    |
 LL | #![feature(raw_dylib)]
    |            ^^^^^^^^^
@@ -8,7 +8,7 @@ LL | #![feature(raw_dylib)]
    = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
 
 error: multiple declarations of external function `f` from library `foo.dll` have different calling conventions
-  --> $DIR/multiple-declarations.rs:14:9
+  --> $DIR/multiple-declarations.rs:15:9
    |
 LL |         fn f(x: i32);
    |         ^^^^^^^^^^^^^
diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.rs
deleted file mode 100644 (file)
index e9690f0..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// only-windows-gnu
-// check-pass
-// compile-flags: --crate-type lib
-#![feature(raw_dylib)]
-//~^ WARNING: the feature `raw_dylib` is incomplete
-#[link(name = "foo", kind = "raw-dylib")]
-//~^ WARNING: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
-extern "C" {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr b/src/test/ui/rfc-2627-raw-dylib/raw-dylib-msvc-only.stderr
deleted file mode 100644 (file)
index 6e24112..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/raw-dylib-msvc-only.rs:4:12
-   |
-LL | #![feature(raw_dylib)]
-   |            ^^^^^^^^^
-   |
-   = note: `#[warn(incomplete_features)]` on by default
-   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
-
-warning: `#[link(...)]` with `kind = "raw-dylib"` not supported on windows-gnu
-  --> $DIR/raw-dylib-msvc-only.rs:6:1
-   |
-LL | #[link(name = "foo", kind = "raw-dylib")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: 2 warnings emitted
-
index e5a5ac2eb2bf12747811b9dd525a5c56b49e2747..dc647fd63f527651746d09a4298c1ed1cd028649 100644 (file)
@@ -1,4 +1,5 @@
-// only-x86_64-pc-windows-msvc
+// only-x86_64
+// only-windows
 // compile-flags: --crate-type lib --emit link
 #![allow(incomplete_features)]
 #![feature(raw_dylib)]
index fc9008128ae43a7baca761dc6876d4a3529d869c..d8a2a6af9c19e5dcd0ebc0270dfd1926d2c2326c 100644 (file)
@@ -1,5 +1,5 @@
 error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
-  --> $DIR/unsupported-abi.rs:7:5
+  --> $DIR/unsupported-abi.rs:8:5
    |
 LL |     fn f(x: i32);
    |     ^^^^^^^^^^^^^
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 ce02553051d2438e563e9299d8c7949be0af1e69..73c31cd9721f65e042412e3bb9aba33cfc49efd8 100644 (file)
@@ -2,12 +2,11 @@
 
 #![allow(unused_must_use)]
 #![allow(unconditional_recursion)]
-#![allow(deprecated)] // llvm_asm!
 // ignore-android: FIXME (#20004)
 // ignore-emscripten no processes
 // ignore-sgx no processes
 
-#![feature(llvm_asm)]
+#![feature(core_intrinsics)]
 #![feature(rustc_private)]
 
 #[cfg(unix)]
 use std::process::Command;
 use std::thread;
 
-// lifted from the test module
 // Inlining to avoid llvm turning the recursive functions into tail calls,
 // which doesn't consume stack.
 #[inline(always)]
-pub fn black_box<T>(dummy: T) { unsafe { llvm_asm!("" : : "r"(&dummy)) } }
+pub fn black_box<T>(dummy: T) { std::intrinsics::black_box(dummy); }
 
 fn silent_recurse() {
     let buf = [0u8; 1000];
index e6846fb40494faf3f33c08a05b95f5810fe1bb65..299a2d2f2d3de6f9b21ac115ab6c9b70b24f1cbe 100644 (file)
@@ -2,28 +2,25 @@ error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:8:52
    |
 LL |     async fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
-   |                          ----               ----   ^ ...but data from `f` is held across an await point here
-   |                          |                  |
-   |                          |                  this `async fn` implicitly returns an `impl Future<Output = &Foo>`
-   |                          this parameter and the returned future are declared with different lifetimes...
+   |                                    ----     ----   ^ ...but data from `f` is returned here
+   |                                    |
+   |                                    this parameter and the return type are declared with different lifetimes...
 
 error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:11:82
    |
 LL |     async fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-   |                          -----                        -----------------          ^ ...but data from `f` is held across an await point here
-   |                          |                            |
-   |                          |                            this `async fn` implicitly returns an `impl Future<Output = (Pin<&Foo>, &Foo)>`
-   |                          this parameter and the returned future are declared with different lifetimes...
+   |                                     ----              -----------------          ^ ...but data from `f` is returned here
+   |                                     |
+   |                                     this parameter and the return type are declared with different lifetimes...
 
 error[E0623]: lifetime mismatch
   --> $DIR/arbitrary_self_types_pin_lifetime_mismatch-async.rs:17:64
    |
 LL |     async fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
-   |                                  -----                   ---   ^^^ ...but data from `arg` is held across an await point here
-   |                                  |                       |
-   |                                  |                       this `async fn` implicitly returns an `impl Future<Output = &()>`
-   |                                  this parameter and the returned future are declared with different lifetimes...
+   |                                               ------     ---   ^^^ ...but data from `arg` is returned here
+   |                                               |
+   |                                               this parameter and the return type are declared with different lifetimes...
 
 error: aborting due to 3 previous errors
 
index 3221d27085096ed6add6e183d8f421de1b42abca..7448e8484b47a1af7b5e7bfffe1c14dd802d8ce4 100644 (file)
@@ -2,67 +2,61 @@ error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:13:9
    |
 LL |     async fn ref_self(&self, f: &u32) -> &u32 {
-   |                       -----              ----
-   |                       |                  |
-   |                       |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                       this parameter and the returned future are declared with different lifetimes...
+   |                                 ----     ----
+   |                                 |
+   |                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:19:9
    |
 LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
-   |                             -----              ----
-   |                             |                  |
-   |                             |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                             this parameter and the returned future are declared with different lifetimes...
+   |                                       ----     ----
+   |                                       |
+   |                                       this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:23:9
    |
 LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-   |                                     -----               ----
-   |                                     |                   |
-   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:27:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-   |                                     -----               ----
-   |                                     |                   |
-   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:31:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-   |                                             -----                ----
-   |                                             |                    |
-   |                                             |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                             this parameter and the returned future are declared with different lifetimes...
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/lt-ref-self-async.rs:35:9
    |
 LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-   |                                         -----                ----
-   |                                         |                    |
-   |                                         |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                         this parameter and the returned future are declared with different lifetimes...
+   |                                                     ----     ----
+   |                                                     |
+   |                                                     this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error: aborting due to 6 previous errors
 
index b6ca986923d2e8c5736a0b34f707972a954e0574..6056cc46d3d8a505346e9bfade02dba8ce145809 100644 (file)
@@ -2,67 +2,61 @@ error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:13:9
    |
 LL |     async fn ref_self(&mut self, f: &u32) -> &u32 {
-   |                       ---------              ----
-   |                       |                      |
-   |                       |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                       this parameter and the returned future are declared with different lifetimes...
+   |                                     ----     ----
+   |                                     |
+   |                                     this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:19:9
    |
 LL |     async fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
-   |                             ---------              ----
-   |                             |                      |
-   |                             |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                             this parameter and the returned future are declared with different lifetimes...
+   |                                           ----     ----
+   |                                           |
+   |                                           this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:23:9
    |
 LL |     async fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
-   |                                     ---------               ----
-   |                                     |                       |
-   |                                     |                       this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:27:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
-   |                                     ---------               ----
-   |                                     |                       |
-   |                                     |                       this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:31:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
-   |                                             ---------                ----
-   |                                             |                        |
-   |                                             |                        this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                             this parameter and the returned future are declared with different lifetimes...
+   |                                                             ----     ----
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-self-async.rs:35:9
    |
 LL |     async fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
-   |                                             ---------                ----
-   |                                             |                        |
-   |                                             |                        this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                             this parameter and the returned future are declared with different lifetimes...
+   |                                                             ----     ----
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error: aborting due to 6 previous errors
 
index eda15d76390b66d2d9f2adcd9da9ff436d0d0e36..61034ae4d47b6792ec66874f9079af8558291364 100644 (file)
@@ -2,56 +2,51 @@ error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:13:9
    |
 LL |     async fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
-   |                               -----------              ----
-   |                               |                        |
-   |                               |                        this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                               this parameter and the returned future are declared with different lifetimes...
+   |                                               ----     ----
+   |                                               |
+   |                                               this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:17:9
    |
 LL |     async fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
-   |                                       -----------               ----
-   |                                       |                         |
-   |                                       |                         this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                       this parameter and the returned future are declared with different lifetimes...
+   |                                                        ----     ----
+   |                                                        |
+   |                                                        this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:21:9
    |
 LL |     async fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
-   |                                       -----------               ----
-   |                                       |                         |
-   |                                       |                         this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                       this parameter and the returned future are declared with different lifetimes...
+   |                                                        ----     ----
+   |                                                        |
+   |                                                        this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:25:9
    |
 LL |     async fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
-   |                                               -----------                ----
-   |                                               |                          |
-   |                                               |                          this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                               this parameter and the returned future are declared with different lifetimes...
+   |                                                                 ----     ----
+   |                                                                 |
+   |                                                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-mut-struct-async.rs:29:9
    |
 LL |     async fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
-   |                                               -----------                ----
-   |                                               |                          |
-   |                                               |                          this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                               this parameter and the returned future are declared with different lifetimes...
+   |                                                                 ----     ----
+   |                                                                 |
+   |                                                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error: aborting due to 5 previous errors
 
index b42caa88c6fef26df3e5f617cac6e96c27568b35..0eab16e685d4c4fc618fd7962b55406c648311e2 100644 (file)
@@ -2,78 +2,71 @@ error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:23:9
    |
 LL |     async fn ref_self(&self, f: &u32) -> &u32 {
-   |                       -----              ----
-   |                       |                  |
-   |                       |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                       this parameter and the returned future are declared with different lifetimes...
+   |                                 ----     ----
+   |                                 |
+   |                                 this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:29:9
    |
 LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
-   |                             -----              ----
-   |                             |                  |
-   |                             |                  this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                             this parameter and the returned future are declared with different lifetimes...
+   |                                       ----     ----
+   |                                       |
+   |                                       this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:33:9
    |
 LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
-   |                                     -----               ----
-   |                                     |                   |
-   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:37:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
-   |                                     -----               ----
-   |                                     |                   |
-   |                                     |                   this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                     this parameter and the returned future are declared with different lifetimes...
+   |                                                ----     ----
+   |                                                |
+   |                                                this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:41:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
-   |                                             -----                ----
-   |                                             |                    |
-   |                                             |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                             this parameter and the returned future are declared with different lifetimes...
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:45:9
    |
 LL |     async fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
-   |                                             -----                ----
-   |                                             |                    |
-   |                                             |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                             this parameter and the returned future are declared with different lifetimes...
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-self-async.rs:49:9
    |
 LL |     async fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
-   |                                            -----                    ---
-   |                                            |                        |
-   |                                            |                        this `async fn` implicitly returns an `impl Future<Output = &u8>`
-   |                                            this parameter and the returned future are declared with different lifetimes...
+   |                                                             ---     ---
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error: aborting due to 7 previous errors
 
index 599becd308062631ee7bcca793c8217b6782ca29..aa1d7453e83e1c0fefc5a3123b57d143451f6e1f 100644 (file)
@@ -2,56 +2,51 @@ error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:13:9
    |
 LL |     async fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
-   |                               -------              ----
-   |                               |                    |
-   |                               |                    this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                               this parameter and the returned future are declared with different lifetimes...
+   |                                           ----     ----
+   |                                           |
+   |                                           this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:17:9
    |
 LL |     async fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
-   |                                       -------               ----
-   |                                       |                     |
-   |                                       |                     this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                       this parameter and the returned future are declared with different lifetimes...
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:21:9
    |
 LL |     async fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
-   |                                       -------               ----
-   |                                       |                     |
-   |                                       |                     this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                       this parameter and the returned future are declared with different lifetimes...
+   |                                                    ----     ----
+   |                                                    |
+   |                                                    this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:25:9
    |
 LL |     async fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
-   |                                               -------                ----
-   |                                               |                      |
-   |                                               |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                               this parameter and the returned future are declared with different lifetimes...
+   |                                                             ----     ----
+   |                                                             |
+   |                                                             this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error[E0623]: lifetime mismatch
   --> $DIR/ref-struct-async.rs:29:9
    |
 LL |     async fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
-   |                                           -------                ----
-   |                                           |                      |
-   |                                           |                      this `async fn` implicitly returns an `impl Future<Output = &u32>`
-   |                                           this parameter and the returned future are declared with different lifetimes...
+   |                                                         ----     ----
+   |                                                         |
+   |                                                         this parameter and the return type are declared with different lifetimes...
 LL |         f
-   |         ^ ...but data from `f` is held across an await point here
+   |         ^ ...but data from `f` is returned here
 
 error: aborting due to 5 previous errors
 
index cc17d8f8e3962e59f2d3782367c7eb6f63603132..9839b8880e9e1f43a25ca014553ba0a61c8bbab9 100644 (file)
@@ -1,8 +1,8 @@
 struct S;
 
 impl S {
-    fn f(self: _) {} //~ERROR the type placeholder `_` is not allowed within types on item signatures for functions
-    fn g(self: &_) {} //~ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    fn f(self: _) {} //~ERROR the placeholder `_` is not allowed within types on item signatures for functions
+    fn g(self: &_) {} //~ERROR the placeholder `_` is not allowed within types on item signatures for functions
 }
 
 fn main() {}
index d3bf63efa40d87511ae8e3bd367d12ab931d9a8f..4f9e3f21dca52a5ce1fbe13ff75aed4a74c82119 100644 (file)
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/self-infer.rs:4:16
    |
 LL |     fn f(self: _) {}
@@ -9,7 +9,7 @@ help: use type parameters instead
 LL |     fn f<T>(self: T) {}
    |         +++       ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/self-infer.rs:5:17
    |
 LL |     fn g(self: &_) {}
diff --git a/src/test/ui/simd/intrinsic/generic-as.rs b/src/test/ui/simd/intrinsic/generic-as.rs
new file mode 100644 (file)
index 0000000..a975190
--- /dev/null
@@ -0,0 +1,48 @@
+// run-pass
+
+#![feature(repr_simd, platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_as<T, U>(x: T) -> U;
+}
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct V<T>([T; 2]);
+
+fn main() {
+    unsafe {
+        let u = V::<u32>([u32::MIN, u32::MAX]);
+        let i: V<i16> = simd_as(u);
+        assert_eq!(i.0[0], u.0[0] as i16);
+        assert_eq!(i.0[1], u.0[1] as i16);
+    }
+
+    unsafe {
+        let f = V::<f32>([f32::MIN, f32::MAX]);
+        let i: V<i16> = simd_as(f);
+        assert_eq!(i.0[0], f.0[0] as i16);
+        assert_eq!(i.0[1], f.0[1] as i16);
+    }
+
+    unsafe {
+        let f = V::<f32>([f32::MIN, f32::MAX]);
+        let u: V<u8> = simd_as(f);
+        assert_eq!(u.0[0], f.0[0] as u8);
+        assert_eq!(u.0[1], f.0[1] as u8);
+    }
+
+    unsafe {
+        let f = V::<f64>([f64::MIN, f64::MAX]);
+        let i: V<isize> = simd_as(f);
+        assert_eq!(i.0[0], f.0[0] as isize);
+        assert_eq!(i.0[1], f.0[1] as isize);
+    }
+
+    unsafe {
+        let f = V::<f64>([f64::MIN, f64::MAX]);
+        let u: V<usize> = simd_as(f);
+        assert_eq!(u.0[0], f.0[0] as usize);
+        assert_eq!(u.0[1], f.0[1] as usize);
+    }
+}
diff --git a/src/test/ui/simd/intrinsic/generic-cast-pointer-width.rs b/src/test/ui/simd/intrinsic/generic-cast-pointer-width.rs
new file mode 100644 (file)
index 0000000..b938231
--- /dev/null
@@ -0,0 +1,21 @@
+// run-pass
+#![feature(repr_simd, platform_intrinsics)]
+
+extern "platform-intrinsic" {
+    fn simd_cast<T, U>(x: T) -> U;
+}
+
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct V<T>([T; 4]);
+
+fn main() {
+    let u = V::<usize>([0, 1, 2, 3]);
+    let uu32: V<u32> = unsafe { simd_cast(u) };
+    let ui64: V<i64> = unsafe { simd_cast(u) };
+
+    for (u, (uu32, ui64)) in u.0.iter().zip(uu32.0.iter().zip(ui64.0.iter())) {
+        assert_eq!(*u as u32, *uu32);
+        assert_eq!(*u as i64, *ui64);
+    }
+}
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 d805bbc79269015c9c466a22e2b3a38524253951..82ef13f3362d461a9eeee3f3c542059a2e9f4921 100644 (file)
@@ -1,8 +1,11 @@
-error[E0437]: type `bar` is not a member of trait `Foo`
-  --> $DIR/impl-wrong-item-for-trait.rs:30:5
+error[E0323]: item `bar` is an associated const, which doesn't match its trait `Foo`
+  --> $DIR/impl-wrong-item-for-trait.rs:12:5
    |
-LL |     type bar = u64;
-   |     ^^^^^^^^^^^^^^^ not a member of trait `Foo`
+LL |     fn bar(&self);
+   |     -------------- item in trait
+...
+LL |     const bar: u64 = 1;
+   |     ^^^^^^^^^^^^^^^^^^^ does not match trait
 
 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
@@ -13,15 +16,6 @@ LL |     const MY_CONST: u32;
 LL |     fn MY_CONST() {}
    |     ^^^^^^^^^^^^^^^^ does not match trait
 
-error[E0323]: item `bar` is an associated const, which doesn't match its trait `Foo`
-  --> $DIR/impl-wrong-item-for-trait.rs:12:5
-   |
-LL |     fn bar(&self);
-   |     -------------- item in trait
-...
-LL |     const bar: u64 = 1;
-   |     ^^^^^^^^^^^^^^^^^^^ does not match trait
-
 error[E0325]: item `bar` is an associated type, which doesn't match its trait `Foo`
   --> $DIR/impl-wrong-item-for-trait.rs:30:5
    |
@@ -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`.
index 07d194476a5db50a98e7333fa51eac7ca3d2f622..ad51707070f9f0f84e7503217fbce9b2363a2741 100644 (file)
@@ -1,4 +1,4 @@
-error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, (I,)), [])`
+error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[HASH]::Id::This) }, Ty((I,))), [])`
   --> $DIR/repeated_projection_type.rs:19:1
    |
 LL | / impl<I, V: Id<This = (I,)>> X for V {
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),
    |                               +
index a05c59c786b0a71f6a9d8a9cde75b7ec4048c5ca..72f0f45fb83802ffb20250c0c63ee291e0c6b6a2 100644 (file)
@@ -4,7 +4,7 @@ error: comparison operators cannot be chained
 LL |     T1<1>::C;
    |       ^ ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     T1::<1>::C;
    |       ++
@@ -15,7 +15,7 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
 LL |     T2<1, 2>::C;
    |         ^ expected one of `.`, `;`, `?`, `}`, or an operator
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     T2::<1, 2>::C;
    |       ++
@@ -26,7 +26,7 @@ error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
 LL |     T3<1, 2, 3>::C;
    |         ^ expected one of `.`, `;`, `?`, `}`, or an operator
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL |     T3::<1, 2, 3>::C;
    |       ++
index 8f30a301bb82f97260281ed2822a83497b484287..ef9a414307cc9128c4342dd641478cc0ec3a8291 100644 (file)
@@ -4,7 +4,7 @@ error: comparison operators cannot be chained
 LL | fn foo1() -> [(); Foo1<10>::SUM] {
    |                       ^  ^
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL | fn foo1() -> [(); Foo1::<10>::SUM] {
    |                       ++
@@ -15,7 +15,7 @@ error: expected one of `.`, `?`, `]`, or an operator, found `,`
 LL | fn foo2() -> [(); Foo2<10, 20>::SUM] {
    |                          ^ expected one of `.`, `?`, `]`, or an operator
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL | fn foo2() -> [(); Foo2::<10, 20>::SUM] {
    |                       ++
@@ -26,7 +26,7 @@ error: expected one of `.`, `?`, `]`, or an operator, found `,`
 LL | fn foo3() -> [(); Foo3<10, 20, 30>::SUM] {
    |                          ^ expected one of `.`, `?`, `]`, or an operator
    |
-help: use `::<...>` instead of `<...>` to specify type or const arguments
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
    |
 LL | fn foo3() -> [(); Foo3::<10, 20, 30>::SUM] {
    |                       ++
index 483f9bbb48cc6d69656b7ef7923d2ac30bee03d6..f2485041d9ba22bde817d7e284a7e07e422679c4 100644 (file)
@@ -8,14 +8,14 @@
 //~| HELP: provide a type for the constant
 
 static B: _ = "abc";
-//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for static variables
+//~^ ERROR: the placeholder `_` is not allowed within types on item signatures for static variables
 //~| NOTE: not allowed in type signatures
 //~| HELP: replace with the correct type
 
 
 // FIXME: this should also suggest a function pointer, as the closure is non-capturing
 const C: _ = || 42;
-//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for constants
+//~^ ERROR: the placeholder `_` is not allowed within types on item signatures for constants
 //~| NOTE: not allowed in type signatures
 //~| NOTE: however, the inferred type
 
index 3a489a6e9431323d94f045c3199b0ccb0f85f822..6127446c83e3b68e830c23d33c58e019a388b7b7 100644 (file)
@@ -4,7 +4,7 @@ error: missing type for `const` item
 LL | const A = 5;
    |       ^ help: provide a type for the constant: `A: i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/unnamable-types.rs:10:11
    |
 LL | static B: _ = "abc";
@@ -13,7 +13,7 @@ LL | static B: _ = "abc";
    |           not allowed in type signatures
    |           help: replace with the correct type: `&str`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/unnamable-types.rs:17:10
    |
 LL | const C: _ = || 42;
diff --git a/src/test/ui/symbol-names/foreign-types.rs b/src/test/ui/symbol-names/foreign-types.rs
new file mode 100644 (file)
index 0000000..8f5b077
--- /dev/null
@@ -0,0 +1,19 @@
+// build-fail
+// compile-flags: -C symbol-mangling-version=v0
+
+#![feature(extern_types)]
+#![feature(rustc_attrs)]
+
+extern "C" {
+    type ForeignType;
+}
+
+struct Check<T: ?Sized>(T);
+
+#[rustc_symbol_name]
+//~^ ERROR symbol-name(_RMCs
+//~| ERROR demangling(<foreign_types[
+//~| ERROR demangling-alt(<foreign_types::Check<foreign_types::ForeignType>>)
+impl Check<ForeignType> {}
+
+fn main() {}
diff --git a/src/test/ui/symbol-names/foreign-types.stderr b/src/test/ui/symbol-names/foreign-types.stderr
new file mode 100644 (file)
index 0000000..fcffdd2
--- /dev/null
@@ -0,0 +1,20 @@
+error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB<REF>_5CheckNvB<REF>_11ForeignTypeE)
+  --> $DIR/foreign-types.rs:13:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<foreign_types[HASH]::Check<foreign_types[HASH]::ForeignType>>)
+  --> $DIR/foreign-types.rs:13:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<foreign_types::Check<foreign_types::ForeignType>>)
+  --> $DIR/foreign-types.rs:13:1
+   |
+LL | #[rustc_symbol_name]
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
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/default-method/rustc_must_implement_one_of.rs b/src/test/ui/traits/default-method/rustc_must_implement_one_of.rs
new file mode 100644 (file)
index 0000000..5ba2f5c
--- /dev/null
@@ -0,0 +1,44 @@
+#![feature(rustc_attrs)]
+
+#[rustc_must_implement_one_of(eq, neq)]
+trait Equal {
+    fn eq(&self, other: &Self) -> bool {
+        !self.neq(other)
+    }
+
+    fn neq(&self, other: &Self) -> bool {
+        !self.eq(other)
+    }
+}
+
+struct T0;
+struct T1;
+struct T2;
+struct T3;
+
+impl Equal for T0 {
+    fn eq(&self, _other: &Self) -> bool {
+        true
+    }
+}
+
+impl Equal for T1 {
+    fn neq(&self, _other: &Self) -> bool {
+        false
+    }
+}
+
+impl Equal for T2 {
+    fn eq(&self, _other: &Self) -> bool {
+        true
+    }
+
+    fn neq(&self, _other: &Self) -> bool {
+        false
+    }
+}
+
+impl Equal for T3 {}
+//~^ not all trait items implemented, missing one of: `eq`, `neq`
+
+fn main() {}
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of.stderr b/src/test/ui/traits/default-method/rustc_must_implement_one_of.stderr
new file mode 100644 (file)
index 0000000..5a4dd13
--- /dev/null
@@ -0,0 +1,15 @@
+error[E0046]: not all trait items implemented, missing one of: `eq`, `neq`
+  --> $DIR/rustc_must_implement_one_of.rs:41:1
+   |
+LL | impl Equal for T3 {}
+   | ^^^^^^^^^^^^^^^^^ missing one of `eq`, `neq` in implementation
+   |
+note: required because of this annotation
+  --> $DIR/rustc_must_implement_one_of.rs:3:1
+   |
+LL | #[rustc_must_implement_one_of(eq, neq)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0046`.
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs b/src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.rs
new file mode 100644 (file)
index 0000000..56e8fcf
--- /dev/null
@@ -0,0 +1,19 @@
+#![feature(rustc_attrs)]
+
+#[rustc_must_implement_one_of(a, a)]
+//~^ Functions names are duplicated
+trait Trait {
+    fn a() {}
+}
+
+#[rustc_must_implement_one_of(b, a, a, c, b, c)]
+//~^ Functions names are duplicated
+//~| Functions names are duplicated
+//~| Functions names are duplicated
+trait Trait1 {
+    fn a() {}
+    fn b() {}
+    fn c() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.stderr b/src/test/ui/traits/default-method/rustc_must_implement_one_of_duplicates.stderr
new file mode 100644 (file)
index 0000000..777beba
--- /dev/null
@@ -0,0 +1,34 @@
+error: Functions names are duplicated
+  --> $DIR/rustc_must_implement_one_of_duplicates.rs:3:31
+   |
+LL | #[rustc_must_implement_one_of(a, a)]
+   |                               ^  ^
+   |
+   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+
+error: Functions names are duplicated
+  --> $DIR/rustc_must_implement_one_of_duplicates.rs:9:34
+   |
+LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
+   |                                  ^  ^
+   |
+   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+
+error: Functions names are duplicated
+  --> $DIR/rustc_must_implement_one_of_duplicates.rs:9:31
+   |
+LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
+   |                               ^           ^
+   |
+   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+
+error: Functions names are duplicated
+  --> $DIR/rustc_must_implement_one_of_duplicates.rs:9:40
+   |
+LL | #[rustc_must_implement_one_of(b, a, a, c, b, c)]
+   |                                        ^     ^
+   |
+   = note: All `#[rustc_must_implement_one_of]` arguments must be unique
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.rs b/src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.rs
new file mode 100644 (file)
index 0000000..ec29958
--- /dev/null
@@ -0,0 +1,13 @@
+#[rustc_must_implement_one_of(eq, neq)]
+//~^ the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std
+trait Equal {
+    fn eq(&self, other: &Self) -> bool {
+        !self.neq(other)
+    }
+
+    fn neq(&self, other: &Self) -> bool {
+        !self.eq(other)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr b/src/test/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr
new file mode 100644 (file)
index 0000000..228bc3e
--- /dev/null
@@ -0,0 +1,11 @@
+error[E0658]: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std
+  --> $DIR/rustc_must_implement_one_of_gated.rs:1:1
+   |
+LL | #[rustc_must_implement_one_of(eq, neq)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs b/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.rs
new file mode 100644 (file)
index 0000000..1089e5f
--- /dev/null
@@ -0,0 +1,38 @@
+#![feature(rustc_attrs)]
+
+#[rustc_must_implement_one_of(a, b)]
+//~^ Function not found in this trait
+//~| Function not found in this trait
+trait Tr0 {}
+
+#[rustc_must_implement_one_of(a, b)]
+//~^ Function not found in this trait
+trait Tr1 {
+    fn a() {}
+}
+
+#[rustc_must_implement_one_of(a)]
+//~^ the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
+trait Tr2 {
+    fn a() {}
+}
+
+#[rustc_must_implement_one_of]
+//~^ malformed `rustc_must_implement_one_of` attribute input
+trait Tr3 {}
+
+#[rustc_must_implement_one_of(A, B)]
+trait Tr4 {
+    const A: u8 = 1; //~ Not a function
+
+    type B; //~ Not a function
+}
+
+#[rustc_must_implement_one_of(a, b)]
+trait Tr5 {
+    fn a(); //~ This function doesn't have a default implementation
+
+    fn b(); //~ This function doesn't have a default implementation
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr b/src/test/ui/traits/default-method/rustc_must_implement_one_of_misuse.stderr
new file mode 100644 (file)
index 0000000..74a6dc8
--- /dev/null
@@ -0,0 +1,82 @@
+error: malformed `rustc_must_implement_one_of` attribute input
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:20:1
+   |
+LL | #[rustc_must_implement_one_of]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_must_implement_one_of(function1, function2, ...)]`
+
+error: Function not found in this trait
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:3:31
+   |
+LL | #[rustc_must_implement_one_of(a, b)]
+   |                               ^
+
+error: Function not found in this trait
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:3:34
+   |
+LL | #[rustc_must_implement_one_of(a, b)]
+   |                                  ^
+
+error: Function not found in this trait
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:8:34
+   |
+LL | #[rustc_must_implement_one_of(a, b)]
+   |                                  ^
+
+error: the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:14:1
+   |
+LL | #[rustc_must_implement_one_of(a)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Not a function
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:26:5
+   |
+LL |     const A: u8 = 1;
+   |     ^^^^^^^^^^^^^^^^
+   |
+note: required by this annotation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:24:1
+   |
+LL | #[rustc_must_implement_one_of(A, B)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: All `#[rustc_must_implement_one_of]` arguments must be associated function names
+
+error: Not a function
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:28:5
+   |
+LL |     type B;
+   |     ^^^^^^^
+   |
+note: required by this annotation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:24:1
+   |
+LL | #[rustc_must_implement_one_of(A, B)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: All `#[rustc_must_implement_one_of]` arguments must be associated function names
+
+error: This function doesn't have a default implementation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:33:5
+   |
+LL |     fn a();
+   |     ^^^^^^^
+   |
+note: required by this annotation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:31:1
+   |
+LL | #[rustc_must_implement_one_of(a, b)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: This function doesn't have a default implementation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:35:5
+   |
+LL |     fn b();
+   |     ^^^^^^^
+   |
+note: required by this annotation
+  --> $DIR/rustc_must_implement_one_of_misuse.rs:31:1
+   |
+LL | #[rustc_must_implement_one_of(a, b)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 9 previous errors
+
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 31c45a2093a0478cbdbf179545aca8e6ad05ad5f..8d818d4a387a6fd199cdf8c33e0c5589820597ef 100644 (file)
@@ -5,7 +5,7 @@
 type Pointer<T> = impl std::ops::Deref<Target=T>;
 
 fn test() -> Pointer<_> {
-    //~^ ERROR: the type placeholder `_` is not allowed within types
+    //~^ ERROR: the placeholder `_` is not allowed within types
     Box::new(1)
 }
 
index 593aeeacb83aa1cf5016b63106e688f1805bf827..15205ba9b419e244513bcd6e55a84e68a60cbc49 100644 (file)
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-77179.rs:7:22
    |
 LL | fn test() -> Pointer<_> {
index 1de9cd8007cff290d12e1cc2877d0f797a5231aa..44ca256b05163c0749e256c145448393a777b4dd 100644 (file)
@@ -1,4 +1,4 @@
 fn main() {
     static BUG: fn(_) -> u8 = |_| 8;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions [E0121]
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions [E0121]
 }
index ac1752e17dfb96211c12dfdcbe7064e8e3ff9ffd..e7aea33758cb258b5a84572c90bee0f01902c5c5 100644 (file)
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/issue-74086.rs:2:20
    |
 LL |     static BUG: fn(_) -> u8 = |_| 8;
index 0d1534df091fa42ce494c035a02877e7bae7618e..885acc48231b24e4435e4f7c88f1f253dc3de2fe 100644 (file)
@@ -5,7 +5,7 @@ pub struct UI {}
 impl UI {
     pub fn run() -> Result<_> {
         //~^ ERROR: this enum takes 2 generic arguments but 1 generic argument was supplied
-        //~| ERROR: the type placeholder `_` is not allowed within types on item signatures for return types
+        //~| ERROR: the placeholder `_` is not allowed within types on item signatures for return types
         let mut ui = UI {};
         ui.interact();
 
@@ -14,7 +14,7 @@ pub fn run() -> Result<_> {
 
     pub fn interact(&mut self) -> Result<_> {
         //~^ ERROR: this enum takes 2 generic arguments but 1 generic argument was supplied
-        //~| ERROR: the type placeholder `_` is not allowed within types on item signatures for return types
+        //~| ERROR: the placeholder `_` is not allowed within types on item signatures for return types
         unimplemented!();
     }
 }
index 5e42c817e030b361814d8811f22bee9f6d967864..3861e0507f6ddeb6b8d313d76db226b38f6b601b 100644 (file)
@@ -34,13 +34,13 @@ help: add missing generic argument
 LL |     pub fn interact(&mut self) -> Result<_, E> {
    |                                           +++
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-75883.rs:15:42
    |
 LL |     pub fn interact(&mut self) -> Result<_> {
    |                                          ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-75883.rs:6:28
    |
 LL |     pub fn run() -> Result<_> {
index de4bdf4e6d9de9ff46bc933fdf4fdcf126339a89..1438f481ec7e135245e72fbad5a679f0666f55e2 100644 (file)
@@ -1,10 +1,10 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constant items
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constant items
   --> $DIR/issue-75889.rs:3:24
    |
 LL | const FOO: dyn Fn() -> _ = "";
    |                        ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static items
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static items
   --> $DIR/issue-75889.rs:4:25
    |
 LL | static BOO: dyn Fn() -> _ = "";
index 99a93b1863d6ed804d2194f26b56f8560b66abe4..1624f6b7742b0d88a3598f60c800eb9d9ade15b4 100644 (file)
@@ -3,11 +3,11 @@
 pub struct T<'a>(&'a str);
 
 pub fn f<'a>(val: T<'a>) -> _ {
-    //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for return types
     g(val)
 }
 
 pub fn g(_: T<'static>) -> _ {}
-//~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR: the placeholder `_` is not allowed within types on item signatures for return types
 
 fn main() {}
index 5a695fecc29dc7f4e4fbcb136988070be8c69b67..2261ba616545fb2a167b1ff5942bc3789e2bf022 100644 (file)
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-80779.rs:10:28
    |
 LL | pub fn g(_: T<'static>) -> _ {}
@@ -7,7 +7,7 @@ LL | pub fn g(_: T<'static>) -> _ {}
    |                            not allowed in type signatures
    |                            help: replace with the correct return type: `()`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-80779.rs:5:29
    |
 LL | pub fn f<'a>(val: T<'a>) -> _ {
index 5117f250fe5ea0b8ed05f344d2c39e3cf4fb321a..8935535fb7eb8b9b9e79ca57bdcc813d322b6348 100644 (file)
@@ -1,8 +1,8 @@
 const TEST4: fn() -> _ = 42;
-                  //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+                  //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn main() {
     const TEST5: fn() -> _ = 42;
-                      //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+                      //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 }
index 8206156a6180a08097aa905b7db3e70498bc62a2..3ff4375cd8d3f1a514f48fc6accc9f37f0f2bcab 100644 (file)
@@ -1,10 +1,10 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/issue-81885.rs:1:22
    |
 LL | const TEST4: fn() -> _ = 42;
    |                      ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/issue-81885.rs:5:26
    |
 LL |     const TEST5: fn() -> _ = 42;
index 7c5cf1082be0925cadb8517a02825d3a4e0801dd..9376e8bcf80bc7d317054e1897943e70b0e675fb 100644 (file)
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/issue-83621-placeholder-static-in-extern.rs:4:15
    |
 LL |     static x: _;
index 0b942d6d94f84199aaf7695547821ecdab8dec41..3c7c990d4e27c1f002053f0a25a3cfc6080a9701 100644 (file)
@@ -2,6 +2,6 @@
 // This test ensures that the compiler does not suggest `Foo<[type error]>` in diagnostic messages.
 
 fn foo() -> Option<_> {} //~ ERROR: [E0308]
-//~^ ERROR: the type placeholder `_` is not allowed
+//~^ ERROR: the placeholder `_` is not allowed
 
 fn main() {}
index 314fe561803687e2707b845de4a4d4679490cc2b..32f4c8f6fdf8255def0295c2733c2fc3ae75eb03 100644 (file)
@@ -9,7 +9,7 @@ LL | fn foo() -> Option<_> {}
    = note:   expected enum `Option<_>`
            found unit type `()`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/issue-91450-inner-ty-error.rs:4:20
    |
 LL | fn foo() -> Option<_> {}
index f657bea164872d9a96777e427d37d6cb8c6054d7..ab2e2d8c53aa3eb2166af328d8aaff2a536a84b9 100644 (file)
@@ -2,13 +2,13 @@
 
 trait Test {
     const TEST: fn() -> _;
-    //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for functions [E0121]
-    //~| ERROR: the type placeholder `_` is not allowed within types on item signatures for constants [E0121]
+    //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121]
+    //~| ERROR: the placeholder `_` is not allowed within types on item signatures for constants [E0121]
 }
 
 impl Test for MyStruct {
     const TEST: fn() -> _ = 42;
-    //~^ ERROR: the type placeholder `_` is not allowed within types on item signatures for functions [E0121]
+    //~^ ERROR: the placeholder `_` is not allowed within types on item signatures for functions [E0121]
 }
 
 fn main() {}
index 62f4db8638f3c14004f2d895580f86a09fc58a9e..e7b2e554a8d425261b3926352d2204168b6fac75 100644 (file)
@@ -1,16 +1,16 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/type-placeholder-fn-in-const.rs:4:25
    |
 LL |     const TEST: fn() -> _;
    |                         ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/type-placeholder-fn-in-const.rs:4:25
    |
 LL |     const TEST: fn() -> _;
    |                         ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/type-placeholder-fn-in-const.rs:10:25
    |
 LL |     const TEST: fn() -> _ = 42;
index a3b75543510aebea747308fb7172ef7cb6a4694d..ca0876be58df9909d111e16ac6cea7d8272bb3f4 100644 (file)
@@ -5,67 +5,67 @@
 // inference by using the `_` type placeholder.
 
 fn test() -> _ { 5 }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
 fn test2() -> (_, _) { (5, 5) }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
 static TEST3: _ = "test";
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
 static TEST4: _ = 145;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
 static TEST5: (_, _) = (1, 2);
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
 fn test6(_: _) { }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn test6_b<T>(_: _, _: T) { }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn test7(x: _) { let _x: usize = x; }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 fn test8(_f: fn() -> _) { }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
-//~^^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+//~^^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 struct Test9;
 
 impl Test9 {
     fn test9(&self) -> _ { () }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
     fn test10(&self, _x : _) { }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 }
 
 fn test11(x: &usize) -> &_ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
     &x
 }
 
 unsafe fn test12(x: *const usize) -> *const *const _ {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
     &x
 }
 
 impl Clone for Test9 {
     fn clone(&self) -> _ { Test9 }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
     fn clone_from(&mut self, other: _) { *self = Test9; }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 }
 
 struct Test10 {
     a: _,
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
     b: (_, _),
 }
 
@@ -73,94 +73,94 @@ pub fn main() {
     static A = 42;
     //~^ ERROR missing type for `static` item
     static B: _ = 42;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
     static C: Option<_> = Some(42);
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
     fn fn_test() -> _ { 5 }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
     fn fn_test2() -> (_, _) { (5, 5) }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
     static FN_TEST3: _ = "test";
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
     static FN_TEST4: _ = 145;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
     static FN_TEST5: (_, _) = (1, 2);
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for static variables
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for static variables
 
     fn fn_test6(_: _) { }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
     fn fn_test7(x: _) { let _x: usize = x; }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
     fn fn_test8(_f: fn() -> _) { }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
-    //~^^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
+    //~^^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
     struct FnTest9;
 
     impl FnTest9 {
         fn fn_test9(&self) -> _ { () }
-        //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
         fn fn_test10(&self, _x : _) { }
-        //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     }
 
     impl Clone for FnTest9 {
         fn clone(&self) -> _ { FnTest9 }
-        //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
         fn clone_from(&mut self, other: _) { *self = FnTest9; }
-        //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     }
 
     struct FnTest10 {
         a: _,
-        //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+        //~^ ERROR the placeholder `_` is not allowed within types on item signatures for structs
         b: (_, _),
     }
 
     fn fn_test11(_: _) -> (_, _) { panic!() }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
     //~| ERROR type annotations needed
 
     fn fn_test12(x: i32) -> (_, _) { (x, x) }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
     fn fn_test13(x: _) -> (i32, _) { (x, x) }
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 }
 
 trait T {
     fn method_test1(&self, x: _);
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     fn method_test2(&self, x: _) -> _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     fn method_test3(&self) -> _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     fn assoc_fn_test1(x: _);
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     fn assoc_fn_test2(x: _) -> _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
     fn assoc_fn_test3() -> _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 }
 
 struct BadStruct<_>(_);
 //~^ ERROR expected identifier, found reserved identifier `_`
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for structs
 trait BadTrait<_> {}
 //~^ ERROR expected identifier, found reserved identifier `_`
 impl BadTrait<_> for BadStruct<_> {}
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for implementations
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for implementations
 
 fn impl_trait() -> impl BadTrait<_> {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for opaque types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types
     unimplemented!()
 }
 
@@ -168,19 +168,19 @@ fn impl_trait() -> impl BadTrait<_> {
 //~^ ERROR expected identifier, found reserved identifier `_`
 //~| ERROR expected identifier, found reserved identifier `_`
 //~| ERROR the name `_` is already used
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for structs
 struct BadStruct2<_, T>(_, T);
 //~^ ERROR expected identifier, found reserved identifier `_`
-//~| ERROR the type placeholder `_` is not allowed within types on item signatures for structs
+//~| ERROR the placeholder `_` is not allowed within types on item signatures for structs
 
 type X = Box<_>;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for type aliases
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for type aliases
 
 struct Struct;
 trait Trait<T> {}
 impl Trait<usize> for Struct {}
 type Y = impl Trait<_>;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for opaque types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for opaque types
 fn foo() -> Y {
     Struct
 }
@@ -188,25 +188,25 @@ fn foo() -> Y {
 trait Qux {
     type A;
     type B = _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
     const C: _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
     const D: _ = 42;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
     // type E: _; // FIXME: make the parser propagate the existence of `B`
     type F: std::ops::Fn(_);
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
 }
 impl Qux for Struct {
     type A = _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
     type B = _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for associated types
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated types
     const C: _;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
     //~| ERROR associated constant in `impl` without body
     const D: _ = 42;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
 }
 
 fn map<T>(_: fn() -> Option<&'static T>) -> Option<T> {
@@ -214,9 +214,9 @@ fn map<T>(_: fn() -> Option<&'static T>) -> Option<T> {
 }
 
 fn value() -> Option<&'static _> {
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
     Option::<&'static u8>::None
 }
 
 const _: Option<_> = map(value);
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
index e1f66afdacc11d4498b6e3fe81439222f03b9c0b..c07b96f9a977ae325e2a2cc527f7719ff949d7a3 100644 (file)
@@ -44,7 +44,7 @@ LL | struct BadStruct1<_, _>(_);
    |                   |
    |                   first use of `_`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:7:14
    |
 LL | fn test() -> _ { 5 }
@@ -53,7 +53,7 @@ LL | fn test() -> _ { 5 }
    |              not allowed in type signatures
    |              help: replace with the correct return type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:10:16
    |
 LL | fn test2() -> (_, _) { (5, 5) }
@@ -63,7 +63,7 @@ LL | fn test2() -> (_, _) { (5, 5) }
    |               |not allowed in type signatures
    |               help: replace with the correct return type: `(i32, i32)`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:13:15
    |
 LL | static TEST3: _ = "test";
@@ -72,7 +72,7 @@ LL | static TEST3: _ = "test";
    |               not allowed in type signatures
    |               help: replace with the correct type: `&str`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:16:15
    |
 LL | static TEST4: _ = 145;
@@ -81,13 +81,13 @@ LL | static TEST4: _ = 145;
    |               not allowed in type signatures
    |               help: replace with the correct type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:19:15
    |
 LL | static TEST5: (_, _) = (1, 2);
    |               ^^^^^^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:22:13
    |
 LL | fn test6(_: _) { }
@@ -98,7 +98,7 @@ help: use type parameters instead
 LL | fn test6<T>(_: T) { }
    |         +++    ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:25:18
    |
 LL | fn test6_b<T>(_: _, _: T) { }
@@ -109,7 +109,7 @@ help: use type parameters instead
 LL | fn test6_b<T, U>(_: U, _: T) { }
    |             +++     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:28:30
    |
 LL | fn test6_c<T, K, L, A, B>(_: _, _: (T, K, L, A, B)) { }
@@ -120,7 +120,7 @@ help: use type parameters instead
 LL | fn test6_c<T, K, L, A, B, U>(_: U, _: (T, K, L, A, B)) { }
    |                         +++     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:31:13
    |
 LL | fn test7(x: _) { let _x: usize = x; }
@@ -131,7 +131,7 @@ help: use type parameters instead
 LL | fn test7<T>(x: T) { let _x: usize = x; }
    |         +++    ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:34:22
    |
 LL | fn test8(_f: fn() -> _) { }
@@ -140,7 +140,7 @@ LL | fn test8(_f: fn() -> _) { }
    |                      not allowed in type signatures
    |                      help: use type parameters instead: `T`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:34:22
    |
 LL | fn test8(_f: fn() -> _) { }
@@ -151,7 +151,7 @@ help: use type parameters instead
 LL | fn test8<T>(_f: fn() -> T) { }
    |         +++             ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:48:26
    |
 LL | fn test11(x: &usize) -> &_ {
@@ -160,7 +160,7 @@ LL | fn test11(x: &usize) -> &_ {
    |                         |not allowed in type signatures
    |                         help: replace with the correct return type: `&'static &'static usize`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:53:52
    |
 LL | unsafe fn test12(x: *const usize) -> *const *const _ {
@@ -169,7 +169,7 @@ LL | unsafe fn test12(x: *const usize) -> *const *const _ {
    |                                      |             not allowed in type signatures
    |                                      help: replace with the correct return type: `*const *const usize`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:67:8
    |
 LL |     a: _,
@@ -194,7 +194,7 @@ error: missing type for `static` item
 LL |     static A = 42;
    |            ^ help: provide a type for the static variable: `A: i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:75:15
    |
 LL |     static B: _ = 42;
@@ -203,13 +203,13 @@ LL |     static B: _ = 42;
    |               not allowed in type signatures
    |               help: replace with the correct type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:77:15
    |
 LL |     static C: Option<_> = Some(42);
    |               ^^^^^^^^^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:79:21
    |
 LL |     fn fn_test() -> _ { 5 }
@@ -218,7 +218,7 @@ LL |     fn fn_test() -> _ { 5 }
    |                     not allowed in type signatures
    |                     help: replace with the correct return type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:82:23
    |
 LL |     fn fn_test2() -> (_, _) { (5, 5) }
@@ -228,7 +228,7 @@ LL |     fn fn_test2() -> (_, _) { (5, 5) }
    |                      |not allowed in type signatures
    |                      help: replace with the correct return type: `(i32, i32)`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:85:22
    |
 LL |     static FN_TEST3: _ = "test";
@@ -237,7 +237,7 @@ LL |     static FN_TEST3: _ = "test";
    |                      not allowed in type signatures
    |                      help: replace with the correct type: `&str`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:88:22
    |
 LL |     static FN_TEST4: _ = 145;
@@ -246,13 +246,13 @@ LL |     static FN_TEST4: _ = 145;
    |                      not allowed in type signatures
    |                      help: replace with the correct type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for static variables
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for static variables
   --> $DIR/typeck_type_placeholder_item.rs:91:22
    |
 LL |     static FN_TEST5: (_, _) = (1, 2);
    |                      ^^^^^^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:94:20
    |
 LL |     fn fn_test6(_: _) { }
@@ -263,7 +263,7 @@ help: use type parameters instead
 LL |     fn fn_test6<T>(_: T) { }
    |                +++    ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:97:20
    |
 LL |     fn fn_test7(x: _) { let _x: usize = x; }
@@ -274,7 +274,7 @@ help: use type parameters instead
 LL |     fn fn_test7<T>(x: T) { let _x: usize = x; }
    |                +++    ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:100:29
    |
 LL |     fn fn_test8(_f: fn() -> _) { }
@@ -283,7 +283,7 @@ LL |     fn fn_test8(_f: fn() -> _) { }
    |                             not allowed in type signatures
    |                             help: use type parameters instead: `T`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:100:29
    |
 LL |     fn fn_test8(_f: fn() -> _) { }
@@ -294,7 +294,7 @@ help: use type parameters instead
 LL |     fn fn_test8<T>(_f: fn() -> T) { }
    |                +++             ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:123:12
    |
 LL |         a: _,
@@ -319,7 +319,7 @@ error[E0282]: type annotations needed
 LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
    |                  ^ cannot infer type
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:128:28
    |
 LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
@@ -327,7 +327,7 @@ LL |     fn fn_test11(_: _) -> (_, _) { panic!() }
    |                            |
    |                            not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:132:30
    |
 LL |     fn fn_test12(x: i32) -> (_, _) { (x, x) }
@@ -337,7 +337,7 @@ LL |     fn fn_test12(x: i32) -> (_, _) { (x, x) }
    |                             |not allowed in type signatures
    |                             help: replace with the correct return type: `(i32, i32)`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:135:33
    |
 LL |     fn fn_test13(x: _) -> (i32, _) { (x, x) }
@@ -346,7 +346,7 @@ LL |     fn fn_test13(x: _) -> (i32, _) { (x, x) }
    |                           |     not allowed in type signatures
    |                           help: replace with the correct return type: `(i32, i32)`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:154:21
    |
 LL | struct BadStruct<_>(_);
@@ -357,7 +357,7 @@ help: use type parameters instead
 LL | struct BadStruct<T>(T);
    |                  ~  ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for implementations
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for implementations
   --> $DIR/typeck_type_placeholder_item.rs:159:15
    |
 LL | impl BadTrait<_> for BadStruct<_> {}
@@ -370,13 +370,13 @@ help: use type parameters instead
 LL | impl<T> BadTrait<T> for BadStruct<T> {}
    |     +++          ~                ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for opaque types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
   --> $DIR/typeck_type_placeholder_item.rs:162:34
    |
 LL | fn impl_trait() -> impl BadTrait<_> {
    |                                  ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:167:25
    |
 LL | struct BadStruct1<_, _>(_);
@@ -387,7 +387,7 @@ help: use type parameters instead
 LL | struct BadStruct1<T, _>(T);
    |                   ~     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for structs
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
   --> $DIR/typeck_type_placeholder_item.rs:172:25
    |
 LL | struct BadStruct2<_, T>(_, T);
@@ -398,19 +398,19 @@ help: use type parameters instead
 LL | struct BadStruct2<U, T>(U, T);
    |                   ~     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for type aliases
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for type aliases
   --> $DIR/typeck_type_placeholder_item.rs:176:14
    |
 LL | type X = Box<_>;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for opaque types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for opaque types
   --> $DIR/typeck_type_placeholder_item.rs:182:21
    |
 LL | type Y = impl Trait<_>;
    |                     ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:216:31
    |
 LL | fn value() -> Option<&'static _> {
@@ -419,7 +419,7 @@ LL | fn value() -> Option<&'static _> {
    |               |               not allowed in type signatures
    |               help: replace with the correct return type: `Option<&'static u8>`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item.rs:221:10
    |
 LL | const _: Option<_> = map(value);
@@ -428,7 +428,7 @@ LL | const _: Option<_> = map(value);
    |          not allowed in type signatures
    |          help: replace with the correct type: `Option<u8>`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:140:31
    |
 LL |     fn method_test1(&self, x: _);
@@ -439,7 +439,7 @@ help: use type parameters instead
 LL |     fn method_test1<T>(&self, x: T);
    |                    +++           ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:142:31
    |
 LL |     fn method_test2(&self, x: _) -> _;
@@ -452,7 +452,7 @@ help: use type parameters instead
 LL |     fn method_test2<T>(&self, x: T) -> T;
    |                    +++           ~     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:144:31
    |
 LL |     fn method_test3(&self) -> _;
@@ -463,7 +463,7 @@ help: use type parameters instead
 LL |     fn method_test3<T>(&self) -> T;
    |                    +++           ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:146:26
    |
 LL |     fn assoc_fn_test1(x: _);
@@ -474,7 +474,7 @@ help: use type parameters instead
 LL |     fn assoc_fn_test1<T>(x: T);
    |                      +++    ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:148:26
    |
 LL |     fn assoc_fn_test2(x: _) -> _;
@@ -487,7 +487,7 @@ help: use type parameters instead
 LL |     fn assoc_fn_test2<T>(x: T) -> T;
    |                      +++    ~     ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:150:28
    |
 LL |     fn assoc_fn_test3() -> _;
@@ -498,19 +498,19 @@ help: use type parameters instead
 LL |     fn assoc_fn_test3<T>() -> T;
    |                      +++      ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
   --> $DIR/typeck_type_placeholder_item.rs:190:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item.rs:192:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item.rs:194:14
    |
 LL |     const D: _ = 42;
@@ -519,13 +519,13 @@ LL |     const D: _ = 42;
    |              not allowed in type signatures
    |              help: replace with the correct type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
   --> $DIR/typeck_type_placeholder_item.rs:197:26
    |
 LL |     type F: std::ops::Fn(_);
    |                          ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:41:24
    |
 LL |     fn test9(&self) -> _ { () }
@@ -534,7 +534,7 @@ LL |     fn test9(&self) -> _ { () }
    |                        not allowed in type signatures
    |                        help: replace with the correct return type: `()`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:44:27
    |
 LL |     fn test10(&self, _x : _) { }
@@ -545,7 +545,7 @@ help: use type parameters instead
 LL |     fn test10<T>(&self, _x : T) { }
    |              +++             ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:59:24
    |
 LL |     fn clone(&self) -> _ { Test9 }
@@ -554,7 +554,7 @@ LL |     fn clone(&self) -> _ { Test9 }
    |                        not allowed in type signatures
    |                        help: replace with the correct return type: `Test9`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:62:37
    |
 LL |     fn clone_from(&mut self, other: _) { *self = Test9; }
@@ -565,7 +565,7 @@ help: use type parameters instead
 LL |     fn clone_from<T>(&mut self, other: T) { *self = Test9; }
    |                  +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:107:31
    |
 LL |         fn fn_test9(&self) -> _ { () }
@@ -574,7 +574,7 @@ LL |         fn fn_test9(&self) -> _ { () }
    |                               not allowed in type signatures
    |                               help: replace with the correct return type: `()`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:110:34
    |
 LL |         fn fn_test10(&self, _x : _) { }
@@ -585,7 +585,7 @@ help: use type parameters instead
 LL |         fn fn_test10<T>(&self, _x : T) { }
    |                     +++             ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item.rs:115:28
    |
 LL |         fn clone(&self) -> _ { FnTest9 }
@@ -594,7 +594,7 @@ LL |         fn clone(&self) -> _ { FnTest9 }
    |                            not allowed in type signatures
    |                            help: replace with the correct return type: `FnTest9`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item.rs:118:41
    |
 LL |         fn clone_from(&mut self, other: _) { *self = FnTest9; }
@@ -605,25 +605,25 @@ help: use type parameters instead
 LL |         fn clone_from<T>(&mut self, other: T) { *self = FnTest9; }
    |                      +++                   ~
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
   --> $DIR/typeck_type_placeholder_item.rs:201:14
    |
 LL |     type A = _;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for associated types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated types
   --> $DIR/typeck_type_placeholder_item.rs:203:14
    |
 LL |     type B = _;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item.rs:205:14
    |
 LL |     const C: _;
    |              ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item.rs:208:14
    |
 LL |     const D: _ = 42;
index 3af5cf926abf0a4eb2c076d56eb7c854b0fd6f83..53f31b683c1a4c4e3d725419d76a23c0ea040a2d 100644 (file)
@@ -2,27 +2,27 @@
 // using the `_` type placeholder.
 
 fn test1() -> _ { Some(42) }
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for return types
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for return types
 
 const TEST2: _ = 42u32;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
 
 const TEST3: _ = Some(42);
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
 
 const TEST4: fn() -> _ = 42;
-//~^ ERROR the type placeholder `_` is not allowed within types on item signatures for functions
+//~^ ERROR the placeholder `_` is not allowed within types on item signatures for functions
 
 trait Test5 {
     const TEST5: _ = 42;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
 }
 
 struct Test6;
 
 impl Test6 {
     const TEST6: _ = 13;
-    //~^ ERROR the type placeholder `_` is not allowed within types on item signatures for constants
+    //~^ ERROR the placeholder `_` is not allowed within types on item signatures for constants
 }
 
 pub fn main() {
index 1b56b1033a8c1f23d5a81460848452d290f83b5a..e8191832318e5b7f532eed9bf875b58233fc7db6 100644 (file)
@@ -1,4 +1,4 @@
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
   --> $DIR/typeck_type_placeholder_item_help.rs:4:15
    |
 LL | fn test1() -> _ { Some(42) }
@@ -7,7 +7,7 @@ LL | fn test1() -> _ { Some(42) }
    |               not allowed in type signatures
    |               help: replace with the correct return type: `Option<i32>`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item_help.rs:7:14
    |
 LL | const TEST2: _ = 42u32;
@@ -16,7 +16,7 @@ LL | const TEST2: _ = 42u32;
    |              not allowed in type signatures
    |              help: replace with the correct type: `u32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item_help.rs:10:14
    |
 LL | const TEST3: _ = Some(42);
@@ -25,13 +25,13 @@ LL | const TEST3: _ = Some(42);
    |              not allowed in type signatures
    |              help: replace with the correct type: `Option<i32>`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for functions
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for functions
   --> $DIR/typeck_type_placeholder_item_help.rs:13:22
    |
 LL | const TEST4: fn() -> _ = 42;
    |                      ^ not allowed in type signatures
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item_help.rs:17:18
    |
 LL |     const TEST5: _ = 42;
@@ -40,7 +40,7 @@ LL |     const TEST5: _ = 42;
    |                  not allowed in type signatures
    |                  help: replace with the correct type: `i32`
 
-error[E0121]: the type placeholder `_` is not allowed within types on item signatures for constants
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for constants
   --> $DIR/typeck_type_placeholder_item_help.rs:24:18
    |
 LL |     const TEST6: _ = 13;
index fee93dc070d5b5bf03b632bf9dd82ac91bb54e7b..633f1edb26cef567dca1bd1a7194a07b0be1a26e 100644 (file)
@@ -1,20 +1,11 @@
 error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
-  --> $DIR/inline_asm.rs:11:5
+  --> $DIR/inline_asm.rs:8:5
    |
 LL |     asm!("nop");
    |     ^^^^^^^^^^^ use of inline assembly
    |
    = note: inline assembly is entirely unchecked and can cause undefined behavior
 
-error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
-  --> $DIR/inline_asm.rs:12:5
-   |
-LL |     llvm_asm!("nop");
-   |     ^^^^^^^^^^^^^^^^ use of inline assembly
-   |
-   = note: inline assembly is entirely unchecked and can cause undefined behavior
-   = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0133`.
index 7c1f86ac0e091dc21a16a6128483ef3df2288d75..12c7efe4f50b6f802d015d6376d0339d311f4938 100644 (file)
@@ -2,12 +2,8 @@
 // [thir]compile-flags: -Z thir-unsafeck
 // needs-asm-support
 
-#![feature(llvm_asm)]
-#![allow(deprecated)] // llvm_asm!
-
 use std::arch::asm;
 
 fn main() {
     asm!("nop"); //~ ERROR use of inline assembly is unsafe and requires unsafe function or block
-    llvm_asm!("nop"); //~ ERROR use of inline assembly is unsafe and requires unsafe function or block
 }
index fee93dc070d5b5bf03b632bf9dd82ac91bb54e7b..633f1edb26cef567dca1bd1a7194a07b0be1a26e 100644 (file)
@@ -1,20 +1,11 @@
 error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
-  --> $DIR/inline_asm.rs:11:5
+  --> $DIR/inline_asm.rs:8:5
    |
 LL |     asm!("nop");
    |     ^^^^^^^^^^^ use of inline assembly
    |
    = note: inline assembly is entirely unchecked and can cause undefined behavior
 
-error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
-  --> $DIR/inline_asm.rs:12:5
-   |
-LL |     llvm_asm!("nop");
-   |     ^^^^^^^^^^^^^^^^ use of inline assembly
-   |
-   = note: inline assembly is entirely unchecked and can cause undefined behavior
-   = note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0133`.
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 b77c5a907c11893444d58290456046edb4173d6f..44c96f31d0ba8ca5d71a8aee1e49da371f5cbf28 100644 (file)
@@ -20,8 +20,7 @@ Then, you can generate the manifest and all the packages from `path/to/dist` to
 `path/to/output` with:
 
 ```
-$ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com \
-    CHANNEL VERSION
+$ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com CHANNEL
 ```
 
 Remember to replace `CHANNEL` with the channel you produced dist artifacts of
index c1579ae9ac54a225a57ae865bda8bc6416ee957b..6b56d6bc4adf068391105254d9e00539619fb004 100644 (file)
     "x86_64-unknown-hermit",
 ];
 
-static DOCS_TARGETS: &[&str] = &[
-    "aarch64-unknown-linux-gnu",
-    "i686-apple-darwin",
-    "i686-pc-windows-gnu",
-    "i686-pc-windows-msvc",
-    "i686-unknown-linux-gnu",
-    "x86_64-apple-darwin",
-    "x86_64-pc-windows-gnu",
-    "x86_64-pc-windows-msvc",
-    "x86_64-unknown-linux-gnu",
-    "x86_64-unknown-linux-musl",
+/// This allows the manifest to contain rust-docs for hosts that don't build
+/// docs.
+///
+/// Tuples of `(host_partial, host_instead)`. If the host does not have the
+/// rust-docs component available, then if the host name contains
+/// `host_partial`, it will use the docs from `host_instead` instead.
+///
+/// The order here matters, more specific entries should be first.
+static DOCS_FALLBACK: &[(&str, &str)] = &[
+    ("-apple-", "x86_64-apple-darwin"),
+    ("aarch64", "aarch64-unknown-linux-gnu"),
+    ("arm-", "aarch64-unknown-linux-gnu"),
+    ("", "x86_64-unknown-linux-gnu"),
 ];
 
 static MSI_INSTALLERS: &[&str] = &[
@@ -301,23 +303,27 @@ fn build_manifest(&mut self) -> Manifest {
     }
 
     fn add_packages_to(&mut self, manifest: &mut Manifest) {
-        let mut package = |name, targets| self.package(name, &mut manifest.pkg, targets);
-        package("rustc", HOSTS);
-        package("rustc-dev", HOSTS);
-        package("reproducible-artifacts", HOSTS);
-        package("rustc-docs", HOSTS);
-        package("cargo", HOSTS);
-        package("rust-mingw", MINGW);
-        package("rust-std", TARGETS);
-        package("rust-docs", DOCS_TARGETS);
-        package("rust-src", &["*"]);
-        package("rls-preview", HOSTS);
-        package("rust-analyzer-preview", HOSTS);
-        package("clippy-preview", HOSTS);
-        package("miri-preview", HOSTS);
-        package("rustfmt-preview", HOSTS);
-        package("rust-analysis", TARGETS);
-        package("llvm-tools-preview", TARGETS);
+        macro_rules! package {
+            ($name:expr, $targets:expr) => {
+                self.package($name, &mut manifest.pkg, $targets, &[])
+            };
+        }
+        package!("rustc", HOSTS);
+        package!("rustc-dev", HOSTS);
+        package!("reproducible-artifacts", HOSTS);
+        package!("rustc-docs", HOSTS);
+        package!("cargo", HOSTS);
+        package!("rust-mingw", MINGW);
+        package!("rust-std", TARGETS);
+        self.package("rust-docs", &mut manifest.pkg, HOSTS, DOCS_FALLBACK);
+        package!("rust-src", &["*"]);
+        package!("rls-preview", HOSTS);
+        package!("rust-analyzer-preview", HOSTS);
+        package!("clippy-preview", HOSTS);
+        package!("miri-preview", HOSTS);
+        package!("rustfmt-preview", HOSTS);
+        package!("rust-analysis", TARGETS);
+        package!("llvm-tools-preview", TARGETS);
     }
 
     fn add_artifacts_to(&mut self, manifest: &mut Manifest) {
@@ -500,7 +506,13 @@ fn extend_profile(
             .extend(pkgs.iter().map(|s| (*s).to_owned()));
     }
 
-    fn package(&mut self, pkgname: &str, dst: &mut BTreeMap<String, Package>, targets: &[&str]) {
+    fn package(
+        &mut self,
+        pkgname: &str,
+        dst: &mut BTreeMap<String, Package>,
+        targets: &[&str],
+        fallback: &[(&str, &str)],
+    ) {
         let version_info = self
             .versions
             .version(&PkgType::from_component(pkgname))
@@ -512,16 +524,32 @@ fn package(&mut self, pkgname: &str, dst: &mut BTreeMap<String, Package>, target
             is_present = false; // Pretend the component is entirely missing.
         }
 
+        macro_rules! tarball_name {
+            ($target_name:expr) => {
+                self.versions.tarball_name(&PkgType::from_component(pkgname), $target_name).unwrap()
+            };
+        }
+        let mut target_from_compressed_tar = |target_name| {
+            let target = Target::from_compressed_tar(self, &tarball_name!(target_name));
+            if target.available {
+                return target;
+            }
+            for (substr, fallback_target) in fallback {
+                if target_name.contains(substr) {
+                    let t = Target::from_compressed_tar(self, &tarball_name!(fallback_target));
+                    // Fallbacks must always be available.
+                    assert!(t.available);
+                    return t;
+                }
+            }
+            Target::unavailable()
+        };
+
         let targets = targets
             .iter()
             .map(|name| {
                 let target = if is_present {
-                    let filename = self
-                        .versions
-                        .tarball_name(&PkgType::from_component(pkgname), name)
-                        .unwrap();
-
-                    Target::from_compressed_tar(self, &filename)
+                    target_from_compressed_tar(name)
                 } else {
                     // If the component is not present for this build add it anyway but mark it as
                     // unavailable -- this way rustup won't allow upgrades without --force
index 11575139adcf6656b069e3e14ffa45e6d771afc4..95c2297de264b7d76cb868b88f631b99fe4823a4 100644 (file)
@@ -169,7 +169,7 @@ pub(crate) fn disable_version(&mut self, package: &PkgType) {
     }
 
     pub(crate) fn archive_name(
-        &mut self,
+        &self,
         package: &PkgType,
         target: &str,
         extension: &str,
@@ -189,11 +189,7 @@ pub(crate) fn archive_name(
         }
     }
 
-    pub(crate) fn tarball_name(
-        &mut self,
-        package: &PkgType,
-        target: &str,
-    ) -> Result<String, Error> {
+    pub(crate) fn tarball_name(&self, package: &PkgType, target: &str) -> Result<String, Error> {
         self.archive_name(package, target, "tar.gz")
     }
 
index 358e79fe56fe374649275ca7aebaafd57ade0e8d..95bb3c92bf516017e812e7f1c14c2dea3845b30e 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 358e79fe56fe374649275ca7aebaafd57ade0e8d
+Subproject commit 95bb3c92bf516017e812e7f1c14c2dea3845b30e
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..258a8256f53177752b46ed1914cd5a1789e639aa 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
@@ -3048,6 +3049,7 @@ Released 2018-09-13
 [`iter_not_returning_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_not_returning_iterator
 [`iter_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth
 [`iter_nth_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_nth_zero
+[`iter_overeager_cloned`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_overeager_cloned
 [`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
 [`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
 [`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
@@ -3070,6 +3072,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 +3256,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 238c919b69d6b41522f43178381aba48be058e6e..a6be75b5e310a29ce5af8231014a893aaf6b65e8 100644 (file)
@@ -1,4 +1,4 @@
-Copyright 2014-2021 The Rust Project Developers
+Copyright 2014-2022 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
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 04169a42b8be8337d55f7732e7ff26fd9b7032b1..0d62c37278e586a8196a77071d3b190d44655755 100644 (file)
@@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
    same "printed page" as the copyright notice for easier
    identification within third-party archives.
 
-Copyright 2014-2021 The Rust Project Developers
+Copyright 2014-2022 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
index 90a2d3950d19b07323204ca4b3a1dedcb608a89f..b724b24aa8309d6f210dec5f9f91f7693481c786 100644 (file)
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2014-2021 The Rust Project Developers
+Copyright (c) 2014-2022 The Rust Project Developers
 
 Permission is hereby granted, free of charge, to any
 person obtaining a copy of this software and associated
index 1bbd89e7822e8a8f7d7d01c29b8302432c145ea4..edbc626e354b5bbc11120a1ac539a92538455ba9 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
 
@@ -242,7 +238,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT
 
 ## License
 
-Copyright 2014-2021 The Rust Project Developers
+Copyright 2014-2022 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license
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 e16f4369da9fcdd488063d232f2f70890e86bef4..12c1bddf79d5d23e21913616a6dbefed03611682 100644 (file)
@@ -6,9 +6,8 @@
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -220,8 +219,6 @@ struct ExprVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
         if eq_expr_value(self.cx, self.assignee, expr) {
             self.counter += 1;
@@ -229,7 +226,4 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
 
         walk_expr(self, expr);
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::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 0977cf22b2c4e00343756b8ef381f66291ae24f5..ca4af66cad16bd48d474490af53d9c06ffc82a87 100644 (file)
     /// {`!=`, `>=`, `>`, `!=`, `>=`, `>`}) can be determined from the following
     /// table:
     ///
-    /// |Comparison  |Bit Op|Example     |is always|Formula               |
-    /// |------------|------|------------|---------|----------------------|
-    /// |`==` or `!=`| `&`  |`x & 2 == 3`|`false`  |`c & m != c`          |
-    /// |`<`  or `>=`| `&`  |`x & 2 < 3` |`true`   |`m < c`               |
-    /// |`>`  or `<=`| `&`  |`x & 1 > 1` |`false`  |`m <= c`              |
-    /// |`==` or `!=`| `|`  |`x | 1 == 0`|`false`  |`c | m != c`          |
-    /// |`<`  or `>=`| `|`  |`x | 1 < 1` |`false`  |`m >= c`              |
-    /// |`<=` or `>` | `|`  |`x | 1 > 0` |`true`   |`m > c`               |
+    /// |Comparison  |Bit Op|Example      |is always|Formula               |
+    /// |------------|------|-------------|---------|----------------------|
+    /// |`==` or `!=`| `&`  |`x & 2 == 3` |`false`  |`c & m != c`          |
+    /// |`<`  or `>=`| `&`  |`x & 2 < 3`  |`true`   |`m < c`               |
+    /// |`>`  or `<=`| `&`  |`x & 1 > 1`  |`false`  |`m <= c`              |
+    /// |`==` or `!=`| `\|` |`x \| 1 == 0`|`false`  |`c \| m != c`         |
+    /// |`<`  or `>=`| `\|` |`x \| 1 < 1` |`false`  |`m >= c`              |
+    /// |`<=` or `>` | `\|` |`x \| 1 > 0` |`true`   |`m > c`               |
     ///
     /// ### Why is this bad?
     /// If the bits that the comparison cares about are always
     /// without changing the outcome. The basic structure can be seen in the
     /// following table:
     ///
-    /// |Comparison| Bit Op  |Example    |equals |
-    /// |----------|---------|-----------|-------|
-    /// |`>` / `<=`|`|` / `^`|`x | 2 > 3`|`x > 3`|
-    /// |`<` / `>=`|`|` / `^`|`x ^ 1 < 4`|`x < 4`|
+    /// |Comparison| Bit Op   |Example     |equals |
+    /// |----------|----------|------------|-------|
+    /// |`>` / `<=`|`\|` / `^`|`x \| 2 > 3`|`x > 3`|
+    /// |`<` / `>=`|`\|` / `^`|`x ^ 1 < 4` |`x < 4`|
     ///
     /// ### Why is this bad?
     /// Not equally evil as [`bad_bit_mask`](#bad_bit_mask),
index 475fdb440d4ecf8b0347551f308f9542bb3e0730..b3f9c1b297679f8a8774ba2c54d34cece15f0c87 100644 (file)
@@ -5,10 +5,9 @@
 use clippy_utils::{differing_macro_contexts, get_parent_expr};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BlockCheckMode, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
@@ -55,8 +54,6 @@ struct ExVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for ExVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         if let ExprKind::Closure(_, _, eid, _, _) = expr.kind {
             // do not lint if the closure is called using an iterator (see #1141)
@@ -82,9 +79,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         }
         walk_expr(self, expr);
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 const BRACED_EXPR_MESSAGE: &str = "omit braces around single expression condition";
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,
+        );
     }
 }
index 43ad0f7605c106bdf4ce1a4899a99c955e295a00..7ffc8ecd31e5d37348b107bbd7572d7f583a9ced 100644 (file)
@@ -5,10 +5,9 @@
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::sym;
@@ -452,8 +451,6 @@ fn bool_expr(&self, e: &'tcx Expr<'_>) {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         if !e.span.from_expansion() {
             match &e.kind {
@@ -470,9 +467,6 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         }
         walk_expr(self, e);
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 fn implements_ord<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> bool {
@@ -485,8 +479,6 @@ struct NotSimplificationVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind {
             if let Some(suggestion) = simplify_not(self.cx, inner) {
@@ -504,7 +496,4 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 
         walk_expr(self, expr);
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
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 84a2373efe15b0adadd14d9361d18638ad084545..85f952375491f213556d9f3fa606e8ad17edf044 100644 (file)
@@ -5,10 +5,9 @@
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::LimitStack;
 use rustc_ast::ast::Attribute;
-use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, FnDecl, HirId};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use rustc_span::{sym, BytePos};
@@ -149,8 +148,6 @@ struct CcHelper {
 }
 
 impl<'tcx> Visitor<'tcx> for CcHelper {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         walk_expr(self, e);
         match e.kind {
@@ -167,7 +164,4 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             _ => {},
         }
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
index d07bc23235b0f37bdadf0811097775129c8e3802..8b79f1600aeb0ab7542ea6d3286b68d8d1159f45 100644 (file)
@@ -7,10 +7,10 @@
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, DiagnosticBuilder};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Block, Expr, ExprKind, HirId};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{source_map::Span, symbol::Symbol, BytePos};
 use std::borrow::Cow;
@@ -183,7 +183,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
                 lint_same_cond(cx, &conds);
                 lint_same_fns_in_if_cond(cx, &conds);
                 // Block duplication
-                lint_same_then_else(cx, &blocks, conds.len() == blocks.len(), expr);
+                lint_same_then_else(cx, &conds, &blocks, conds.len() == blocks.len(), expr);
             }
         }
     }
@@ -192,6 +192,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
 /// Implementation of `BRANCHES_SHARING_CODE` and `IF_SAME_THEN_ELSE` if the blocks are equal.
 fn lint_same_then_else<'tcx>(
     cx: &LateContext<'tcx>,
+    conds: &[&'tcx Expr<'_>],
     blocks: &[&Block<'tcx>],
     has_conditional_else: bool,
     expr: &'tcx Expr<'_>,
@@ -204,7 +205,7 @@ fn lint_same_then_else<'tcx>(
     // Check if each block has shared code
     let has_expr = blocks[0].expr.is_some();
 
-    let (start_eq, mut end_eq, expr_eq) = if let Some(block_eq) = scan_block_for_eq(cx, blocks) {
+    let (start_eq, mut end_eq, expr_eq) = if let Some(block_eq) = scan_block_for_eq(cx, conds, blocks) {
         (block_eq.start_eq, block_eq.end_eq, block_eq.expr_eq)
     } else {
         return;
@@ -316,14 +317,14 @@ 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<'_>, conds: &[&Expr<'_>], blocks: &[&Block<'_>]) -> Option<BlockEqual> {
     let mut start_eq = usize::MAX;
     let mut end_eq = usize::MAX;
     let mut expr_eq = true;
-    let mut iter = blocks.windows(2);
-    while let Some(&[win0, win1]) = iter.next() {
-        let l_stmts = win0.stmts;
-        let r_stmts = win1.stmts;
+    let mut iter = blocks.windows(2).enumerate();
+    while let Some((i, &[block0, block1])) = iter.next() {
+        let l_stmts = block0.stmts;
+        let r_stmts = block1.stmts;
 
         // `SpanlessEq` now keeps track of the locals and is therefore context sensitive clippy#6752.
         // The comparison therefore needs to be done in a way that builds the correct context.
@@ -340,22 +341,26 @@ fn scan_block_for_eq(cx: &LateContext<'tcx>, blocks: &[&Block<'tcx>]) -> Option<
             it1.zip(it2)
                 .fold(0, |acc, (l, r)| if evaluator.eq_stmt(l, r) { acc + 1 } else { 0 })
         };
-        let block_expr_eq = both(&win0.expr, &win1.expr, |l, r| evaluator.eq_expr(l, r));
+        let block_expr_eq = both(&block0.expr, &block1.expr, |l, r| evaluator.eq_expr(l, r));
 
         // IF_SAME_THEN_ELSE
         if_chain! {
             if block_expr_eq;
             if l_stmts.len() == r_stmts.len();
             if l_stmts.len() == current_start_eq;
-            if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, win0.hir_id);
-            if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, win1.hir_id);
+            // `conds` may have one last item than `blocks`.
+            // Any `i` from `blocks.windows(2)` will exist in `conds`, but `i+1` may not exist on the last iteration.
+            if !matches!(conds[i].kind, ExprKind::Let(..));
+            if !matches!(conds.get(i + 1).map(|e| &e.kind), Some(ExprKind::Let(..)));
+            if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, block0.hir_id);
+            if !is_lint_allowed(cx, IF_SAME_THEN_ELSE, block1.hir_id);
             then {
                 span_lint_and_note(
                     cx,
                     IF_SAME_THEN_ELSE,
-                    win0.span,
+                    block0.span,
                     "this `if` has identical blocks",
-                    Some(win1.span),
+                    Some(block1.span),
                     "same as this",
                 );
 
@@ -385,11 +390,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 +420,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;
@@ -565,10 +566,10 @@ fn new(cx: &'a LateContext<'tcx>) -> Self {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for UsedValueFinderVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 
     fn visit_local(&mut self, l: &'tcx rustc_hir::Local<'tcx>) {
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..78acdb5dfd580bd7906c298a28ca05f3bf51e76d 100644 (file)
@@ -5,12 +5,11 @@
 use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
 use rustc_errors::Applicability;
 use rustc_hir::{
-    intravisit::{walk_expr, walk_stmt, NestedVisitorMap, Visitor},
+    intravisit::{walk_expr, walk_stmt, Visitor},
     Body, Expr, ExprKind, HirId, Lit, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::{
-    hir::map::Map,
     lint::in_external_macro,
     ty::{self, FloatTy, IntTy, PolyFnSig, Ty},
 };
@@ -54,7 +53,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);
@@ -117,8 +116,6 @@ fn check_lit(&self, lit: &Lit, lit_ty: Ty<'tcx>) {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     #[allow(clippy::too_many_lines)]
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         match &expr.kind {
@@ -161,7 +158,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 }
                                     });
@@ -209,10 +206,6 @@ fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
         walk_stmt(self, stmt);
         self.ty_bounds.pop();
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 fn fn_sig_opt<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<PolyFnSig<'tcx>> {
index fa2b348591be4d7a0118095a99734f9297f60900..af46e99c6446ef9c487328eb28f77aff18a7f329 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),
 
@@ -449,7 +449,6 @@ fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId,
         | ExprKind::Continue(..)
         | ExprKind::Ret(..)
         | ExprKind::InlineAsm(..)
-        | ExprKind::LlvmInlineAsm(..)
         | ExprKind::Struct(..)
         | ExprKind::Repeat(..)
         | ExprKind::Yield(..) => true,
@@ -457,7 +456,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 +498,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 +567,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 097cb65f56e4e8c63b760cb56bfb32aa30a59a0e..6d3df260ca25592a59a43e5d75751200c20f7591 100644 (file)
@@ -3,12 +3,12 @@
 use clippy_utils::ty::{implements_trait, is_copy};
 use clippy_utils::{get_trait_def_id, is_automatically_derived, is_lint_allowed, match_def_path};
 use if_chain::if_chain;
-use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
 use rustc_hir::{
     BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, HirId, Impl, Item, ItemKind, TraitRef, UnsafeSource, Unsafety,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
@@ -382,7 +382,7 @@ struct UnsafeVisitor<'a, 'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for UnsafeVisitor<'_, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
     fn visit_fn(&mut self, kind: FnKind<'tcx>, decl: &'tcx FnDecl<'_>, body_id: BodyId, span: Span, id: HirId) {
         if self.has_unsafe {
@@ -414,7 +414,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         walk_expr(self, expr);
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }
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..a00361e6062ad4ab1faee890838dd36a9f54328a 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};
 use rustc_errors::emitter::EmitterWriter;
 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::intravisit::{self, Visitor};
+use rustc_hir::{AnonConst, Expr};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_parse::maybe_new_parser_from_source_str;
@@ -798,31 +799,24 @@ struct FindPanicUnwrap<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if self.panic_span.is_some() {
             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();
@@ -840,12 +834,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
     // Panics in const blocks will cause compilation to fail.
     fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        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..9c0a966b0beef16b68bf8e8ab80d7f566cce5a39 100644 (file)
@@ -10,7 +10,7 @@
 use rustc_errors::Applicability;
 use rustc_hir::{
     hir_id::HirIdSet,
-    intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor},
+    intravisit::{walk_expr, Visitor},
     Block, Expr, ExprKind, Guard, HirId, Pat, Stmt, StmtKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -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 }
     }
@@ -370,11 +370,6 @@ fn visit_non_tail_expr(&mut self, e: &'tcx Expr<'_>) {
     }
 }
 impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> {
-    type Map = ErasedMap<'tcx>;
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
         match stmt.kind {
             StmtKind::Semi(e) => {
@@ -504,7 +499,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
                     self.loops.pop();
                 },
                 ExprKind::Block(block, _) => self.visit_block(block),
-                ExprKind::InlineAsm(_) | ExprKind::LlvmInlineAsm(_) => {
+                ExprKind::InlineAsm(_) => {
                     self.can_use_entry = false;
                 },
                 _ => {
@@ -532,7 +527,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 +628,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 cdac9f3e6e1776949edb94d07a993b42f0d05c8a..65599a0587d449ab2150abdb280442d808e6a48c 100644 (file)
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
 use clippy_utils::{get_parent_expr, path_to_local, path_to_local_id};
 use if_chain::if_chain;
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BinOpKind, Block, Expr, ExprKind, Guard, HirId, Local, Node, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -133,8 +132,6 @@ fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         match e.kind {
             ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
@@ -167,9 +164,6 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
     fn visit_block(&mut self, _: &'tcx Block<'_>) {
         // don't continue over blocks, LateLintPass already does that
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 /// Walks up the AST from the given write expression (`vis.write_expr`) looking
@@ -299,8 +293,6 @@ struct ReadVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for ReadVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if expr.hir_id == self.last_expr.hir_id {
             return;
@@ -343,9 +335,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 
         walk_expr(self, expr);
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 /// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`.
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..574678b5542111d4c3132b825139c56356254e25 100644 (file)
@@ -1,10 +1,10 @@
 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};
-use rustc_middle::hir::map::Map;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Span};
@@ -67,8 +67,8 @@ 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::intravisit::{self, Visitor};
+    use rustc_hir::{Expr, ImplItemKind};
 
     struct FindPanicUnwrap<'a, 'tcx> {
         lcx: &'a LateContext<'tcx>,
@@ -77,17 +77,9 @@ struct FindPanicUnwrap<'a, 'tcx> {
     }
 
     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);
                 }
             }
@@ -105,10 +97,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             // and check sub-expressions
             intravisit::walk_expr(self, expr);
         }
-
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
     }
 
     for impl_item in impl_items {
index 3f043e5f2f1c55be2ec3b1833297bfb76e8d547b..395c920c9974c0a525772f0e5ae88c108458b40e 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;
@@ -9,7 +9,7 @@
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::kw;
-use rustc_span::{sym, Span};
+use rustc_span::{sym, BytePos, Span};
 
 declare_clippy_lint! {
     /// ### What it does
 
 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,
                         ExprKind::MethodCall(path, ..) => path.ident.name.as_str() == "to_string",
                         _ => false,
                     };
-                    let sugg = if is_new_string {
+                    let sugg = if format_args.format_string_span.contains(value.span) {
+                        // Implicit argument. e.g. `format!("{x}")` span points to `{x}`
+                        let spdata = value.span.data();
+                        let span = Span::new(
+                            spdata.lo + BytePos(1),
+                            spdata.hi - BytePos(1),
+                            spdata.ctxt,
+                            spdata.parent
+                        );
+                        let snip = snippet_with_applicability(cx, span, "..", &mut applicability);
+                        if is_new_string {
+                            snip.into()
+                        } else {
+                            format!("{snip}.to_string()")
+                        }
+                    } else if is_new_string {
                         snippet_with_applicability(cx, value.span, "..", &mut applicability).into_owned()
                     } else {
                         let sugg = Sugg::hir_with_applicability(cx, value, "<arg>", &mut applicability);
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..2610f0ff384eb25575cc75e52ec6f729fb2018f1 100644 (file)
@@ -4,7 +4,6 @@
 use rustc_hir::{self as hir, def::Res, intravisit, QPath};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::{
-    hir::map::Map,
     lint::in_external_macro,
     ty::{self, Ty},
 };
@@ -18,7 +17,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 +39,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 +47,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 +61,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());
@@ -211,8 +210,6 @@ struct StaticMutVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
         use hir::ExprKind::{AddrOf, Assign, AssignOp, Call, MethodCall};
 
@@ -244,10 +241,6 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
             _ => {},
         }
     }
-
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::None
-    }
 }
 
 fn is_mutated_static(e: &hir::Expr<'_>) -> bool {
index f83789bb2199e0e2bfff2fb35eb2d64297c1e7ac..ab3dae4b67f9a54e271702f0ebcb8880488e6749 100644 (file)
@@ -1,6 +1,6 @@
 use rustc_hir::{self as hir, intravisit, HirIdSet};
 use rustc_lint::LateContext;
-use rustc_middle::{hir::map::Map, ty};
+use rustc_middle::ty;
 use rustc_span::def_id::LocalDefId;
 
 use clippy_utils::diagnostics::span_lint;
@@ -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>,
@@ -42,8 +42,7 @@ fn check_raw_ptr(
     let expr = &body.value;
     if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(def_id) {
         let raw_ptrs = iter_input_pats(decl, body)
-            .zip(decl.inputs.iter())
-            .filter_map(|(arg, ty)| raw_ptr_arg(arg, ty))
+            .filter_map(|arg| raw_ptr_arg(cx, arg))
             .collect::<HirIdSet>();
 
         if !raw_ptrs.is_empty() {
@@ -59,8 +58,12 @@ fn check_raw_ptr(
     }
 }
 
-fn raw_ptr_arg(arg: &hir::Param<'_>, ty: &hir::Ty<'_>) -> Option<hir::HirId> {
-    if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.kind, &ty.kind) {
+fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option<hir::HirId> {
+    if let (&hir::PatKind::Binding(_, id, _, _), Some(&ty::RawPtr(_))) = (
+        &arg.pat.kind,
+        cx.maybe_typeck_results()
+            .map(|typeck_results| typeck_results.pat_ty(arg.pat).kind()),
+    ) {
         Some(id)
     } else {
         None
@@ -74,8 +77,6 @@ struct DerefVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
         match expr.kind {
             hir::ExprKind::Call(f, args) => {
@@ -103,10 +104,6 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
 
         intravisit::walk_expr(self, expr);
     }
-
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::None
-    }
 }
 
 impl<'a, 'tcx> DerefVisitor<'a, '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 e20741d2407e63b21a09ff0b4d40b299dbedcd77..0cc697d8425517495e2aac59b7e0cb7f28a59759 100644 (file)
@@ -3,10 +3,9 @@
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::SpanlessEq;
 use if_chain::if_chain;
-use rustc_hir::intravisit::{self as visit, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self as visit, Visitor};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
 
@@ -91,8 +90,6 @@ pub struct OppVisitor<'a, 'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
             self.found_mutex = Some(mutex);
@@ -101,10 +98,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         }
         visit::walk_expr(self, expr);
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 /// Checks if `Mutex::lock` is called in any of the branches.
@@ -115,8 +108,6 @@ pub struct ArmVisitor<'a, 'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for ArmVisitor<'_, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         if let Some(mutex) = is_mutex_lock_call(self.cx, expr) {
             self.found_mutex = Some(mutex);
@@ -125,10 +116,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         }
         visit::walk_expr(self, expr);
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 impl<'tcx, 'l> ArmVisitor<'tcx, 'l> {
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 6358228dd47f0e421cc06a7f1306655db868234f..104de0ff62f8a2e0d0101a601d34fc458c72de1c 100644 (file)
@@ -3,10 +3,10 @@
 
 use rustc_errors::DiagnosticBuilder;
 use rustc_hir as hir;
-use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{Ty, TyS, TypeckResults};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -294,8 +294,6 @@ fn new(cx: &'a LateContext<'tcx>) -> Self {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for ImplicitHasherTypeVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_ty(&mut self, t: &'tcx hir::Ty<'_>) {
         if let Some(target) = ImplicitHasherType::new(self.cx, t) {
             self.found.push(target);
@@ -311,10 +309,6 @@ fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
 
         walk_inf(self, inf);
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 /// Looks for default-hasher-dependent constructors like `HashMap::new`.
@@ -337,7 +331,7 @@ fn new(cx: &'a LateContext<'tcx>, target: &'b ImplicitHasherType<'tcx>) -> Self
 }
 
 impl<'a, 'b, 'tcx> Visitor<'tcx> for ImplicitHasherConstructorVisitor<'a, 'b, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_body(&mut self, body: &'tcx Body<'_>) {
         let old_maybe_typeck_results = self.maybe_typeck_results.replace(self.cx.tcx.typeck_body(body.id()));
@@ -389,7 +383,7 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         walk_expr(self, e);
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }
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..4615122bbf9e51cef7b6c3087b2e9a1eefabc945 100644 (file)
@@ -7,9 +7,9 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -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();
@@ -230,10 +230,10 @@ struct SliceIndexLintingVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
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..b56d87c5348c2996ace5bafdf1475582df5c2d98 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.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).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 64f6d62fbdcd80c12fac55ad62654d9054f75cee..e1168c3f6022ef381fc2eb576b44fb47ea8c3e41 100644 (file)
@@ -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) => {
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..87fd7f99748a1df8d1b00018e7e7b1c09d55a68d 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(methods::ITER_NEXT_SLICE),
     LintId::of(methods::ITER_NTH),
     LintId::of(methods::ITER_NTH_ZERO),
+    LintId::of(methods::ITER_OVEREAGER_CLONED),
     LintId::of(methods::ITER_SKIP_NEXT),
     LintId::of(methods::MANUAL_FILTER_MAP),
     LintId::of(methods::MANUAL_FIND_MAP),
     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),
     LintId::of(reference::REF_IN_DEREF),
     LintId::of(regex::INVALID_REGEX),
     LintId::of(repeat_once::REPEAT_ONCE),
-    LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
     LintId::of(returns::LET_AND_RETURN),
     LintId::of(returns::NEEDLESS_RETURN),
     LintId::of(self_assignment::SELF_ASSIGNMENT),
index 002122793f3b6b4c2a26965be3bbbd1239f2d1cb..56146a0fd3a7525d84cfeb51f2dd08cfdf8119c0 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,
     methods::ITER_NEXT_SLICE,
     methods::ITER_NTH,
     methods::ITER_NTH_ZERO,
+    methods::ITER_OVEREAGER_CLONED,
     methods::ITER_SKIP_NEXT,
     methods::MANUAL_FILTER_MAP,
     methods::MANUAL_FIND_MAP,
     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..1292675f4a96cde9b178869674b143c6e5038907 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),
@@ -80,6 +81,7 @@
     LintId::of(ranges::RANGE_PLUS_ONE),
     LintId::of(redundant_else::REDUNDANT_ELSE),
     LintId::of(ref_option_ref::REF_OPTION_REF),
+    LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
     LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED),
     LintId::of(strings::STRING_ADD_ASSIGN),
     LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS),
index 2ea0b696f1feb3ad437c61d8c9c1072de7da606f..c44ef124bfa0ea3bcb1130283606736cc08ebbef 100644 (file)
     LintId::of(methods::EXPECT_FUN_CALL),
     LintId::of(methods::EXTEND_WITH_DRAIN),
     LintId::of(methods::ITER_NTH),
+    LintId::of(methods::ITER_OVEREAGER_CLONED),
     LintId::of(methods::MANUAL_STR_REPEAT),
     LintId::of(methods::OR_FUN_CALL),
     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 8594338ffa5ab5558dfb2ae26a4eb7f6e831f08a..10f8ae4b7f7fca8583cde6a976955579a3efc4e1 100644 (file)
@@ -16,7 +16,6 @@
     LintId::of(methods::SUSPICIOUS_MAP),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
     LintId::of(octal_escapes::OCTAL_ESCAPES),
-    LintId::of(return_self_not_must_use::RETURN_SELF_NOT_MUST_USE),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL),
     LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL),
 ])
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..565057140454d4af4e3de567c216092365b45408 100644 (file)
@@ -2,8 +2,7 @@
 use clippy_utils::trait_ref_of_method;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::intravisit::{
-    walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty,
-    NestedVisitorMap, Visitor,
+    walk_fn_decl, walk_generic_param, walk_generics, walk_item, walk_param_bound, walk_poly_trait_ref, walk_ty, Visitor,
 };
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
@@ -12,7 +11,6 @@
     TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereClause, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::{kw, Symbol};
@@ -91,7 +89,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,
@@ -354,8 +352,6 @@ fn abort(&self) -> bool {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
         self.record(&Some(*lifetime));
@@ -409,9 +405,6 @@ fn visit_ty(&mut self, ty: &'tcx Ty<'_>) {
         }
         walk_ty(self, ty);
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 /// Are any lifetimes mentioned in the `where` clause? If so, we don't try to
@@ -457,8 +450,6 @@ struct LifetimeChecker {
 }
 
 impl<'tcx> Visitor<'tcx> for LifetimeChecker {
-    type Map = Map<'tcx>;
-
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
         self.map.remove(&lifetime.name.ident().name);
@@ -474,9 +465,6 @@ fn visit_generic_param(&mut self, param: &'tcx GenericParam<'_>) {
             walk_generic_param(self, param);
         }
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 fn report_extra_lifetimes<'tcx>(cx: &LateContext<'tcx>, func: &'tcx FnDecl<'_>, generics: &'tcx Generics<'_>) {
@@ -508,16 +496,10 @@ struct BodyLifetimeChecker {
 }
 
 impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
-    type Map = Map<'tcx>;
-
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
         if lifetime.name.ident().name != kw::Empty && lifetime.name.ident().name != kw::StaticLifetime {
             self.lifetimes_used_in_body = true;
         }
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
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..9d8679d77c6d02590737d25a19de817cb6e6f679 100644 (file)
@@ -2,11 +2,10 @@
 use clippy_utils::diagnostics::span_lint_and_note;
 use clippy_utils::{get_enclosing_block, higher, path_to_local};
 use if_chain::if_chain;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, Node, PatKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
 use rustc_middle::{mir::FakeReadCause, ty};
 use rustc_span::source_map::Span;
 use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
@@ -147,13 +146,7 @@ pub fn is_found(cx: &LateContext<'_>, hir_id: HirId) -> bool {
     }
 }
 
-impl intravisit::Visitor<'tcx> for BreakAfterExprVisitor {
-    type Map = Map<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
+impl<'tcx> intravisit::Visitor<'tcx> for BreakAfterExprVisitor {
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         if self.past_candidate {
             return;
index ba895f35faa267a1d7e0545bdc6f8bdf978f3afd..f7d3227af01745a0ae532005ef8cf771cf98a960 100644 (file)
@@ -7,10 +7,10 @@
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
 use rustc_hir::{Block, Expr, ExprKind, HirId, HirIdSet, Local, Mutability, Node, PatKind, Stmt, StmtKind};
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, TyS};
 use rustc_span::sym;
@@ -262,11 +262,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
             walk_expr(self, expr);
         }
     }
-
-    type Map = Map<'tcx>;
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 impl<'tcx> IterFunctionVisitor<'_, 'tcx> {
@@ -298,7 +293,7 @@ struct UsedCountVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for UsedCountVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if path_to_local_id(expr, self.id) {
@@ -308,8 +303,8 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         }
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }
 
@@ -339,8 +334,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..22da21bc6bc40597f815c86f6f29822052bb39db 100644 (file)
@@ -8,10 +8,9 @@
 use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, QPath};
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
 use rustc_middle::middle::region;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::{sym, Symbol};
@@ -58,8 +57,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 +261,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(
@@ -296,8 +293,6 @@ fn check(&mut self, idx: &'tcx Expr<'_>, seqexpr: &'tcx Expr<'_>, expr: &'tcx Ex
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for VarVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if_chain! {
             // a range index op
@@ -376,7 +371,4 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         }
         self.prefer_mutable = old;
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
index a3aa6be6afd645ccd94a717d431c481af8c1ed5d..3bfc62b19ef2af85f5a1409e6b0ef3945293e7e1 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<'_>>,
@@ -181,7 +181,6 @@ fn never_loop_expr(expr: &Expr<'_>, main_loop_id: HirId) -> NeverLoopResult {
         ExprKind::Struct(_, _, None)
         | ExprKind::Yield(_, _)
         | ExprKind::Closure(_, _, _, _, _)
-        | ExprKind::LlvmInlineAsm(_)
         | ExprKind::Path(_)
         | ExprKind::ConstBlock(_)
         | ExprKind::Lit(_)
index 2eb247de9f42b79a789e8695fb05edaaada931c5..c61b411708c2a932be82b960d21c0146d0d88c37 100644 (file)
@@ -6,10 +6,9 @@
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
 use rustc_span::symbol::sym;
 use std::iter::Iterator;
 
@@ -49,7 +48,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()
@@ -134,8 +133,6 @@ fn should_lint(&self) -> bool {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         match &expr.kind {
             // Non-determinism may occur ... don't give a lint
@@ -175,10 +172,6 @@ fn visit_stmt(&mut self, s: &'tcx Stmt<'_>) {
             }
         }
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 // Given some statement, determine if that statement is a push on a Vec. If it is, return
index f6b7e1bc353fd24c6b9c736a52a93fb7d2823f88..eac0f03b142a821c56ade84d17f2ea5fe8264f04 100644 (file)
@@ -3,10 +3,10 @@
 use if_chain::if_chain;
 use rustc_ast::ast::{LitIntType, LitKind};
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, walk_local, walk_pat, walk_stmt, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, walk_local, walk_pat, walk_stmt, Visitor};
 use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, Local, Mutability, Pat, PatKind, Stmt};
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::Ty;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Symbol};
@@ -50,8 +50,6 @@ pub(super) fn into_results(self) -> impl Iterator<Item = HirId> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if self.done {
             return;
@@ -102,9 +100,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
             walk_expr(self, expr);
         }
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 enum InitializeVisitorState<'hir> {
@@ -151,7 +146,7 @@ pub(super) fn get_result(&self) -> Option<(Symbol, Option<Ty<'tcx>>, &'tcx Expr<
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_local(&mut self, l: &'tcx Local<'_>) {
         // Look for declarations of the variable
@@ -254,8 +249,8 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         }
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }
 
@@ -283,8 +278,6 @@ pub(super) struct LoopNestVisitor {
 }
 
 impl<'tcx> Visitor<'tcx> for LoopNestVisitor {
-    type Map = Map<'tcx>;
-
     fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
         if stmt.hir_id == self.hir_id {
             self.nesting = LookFurther;
@@ -323,10 +316,6 @@ fn visit_pat(&mut self, pat: &'tcx Pat<'_>) {
         }
         walk_pat(self, pat);
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the
index 5f9ebad25e893614ccc22ae9b31836949b3187ea..5dcfed65c78ac7829e004564ce8b1957c81d4866 100644 (file)
@@ -5,11 +5,10 @@
 use if_chain::if_chain;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefIdMap;
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::HirIdSet;
 use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, cond: &'tcx Expr<'_>, expr: &'tcx Expr<'_>) {
     if constant(cx, cx.typeck_results(), cond).is_some() {
@@ -67,8 +66,6 @@ struct HasBreakOrReturnVisitor {
 }
 
 impl<'tcx> Visitor<'tcx> for HasBreakOrReturnVisitor {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if self.has_break_or_return {
             return;
@@ -84,10 +81,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 
         walk_expr(self, expr);
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 /// Collects the set of variables in an expression
@@ -123,8 +116,6 @@ fn insert_def_id(&mut self, ex: &'tcx Expr<'_>) {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for VarCollectorVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
         match ex.kind {
             ExprKind::Path(_) => self.insert_def_id(ex),
@@ -134,8 +125,4 @@ fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
             _ => walk_expr(self, ex),
         }
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
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..e0b235c355980e444ee8367a422cc32adb497791 100644 (file)
@@ -7,13 +7,14 @@
 };
 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::intravisit::{walk_expr, Visitor};
+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,18 +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> {
-        type Map = ErasedMap<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-
+    impl<'tcx> Visitor<'tcx> for V<'_, '_, 'tcx> {
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             if self.uses_iter {
                 // return
@@ -228,7 +240,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,12 +248,7 @@ struct AfterLoopVisitor<'a, 'b, 'tcx> {
         after_loop: bool,
         used_iter: bool,
     }
-    impl Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
-        type Map = ErasedMap<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-
+    impl<'tcx> Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> {
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             if self.used_iter {
                 return;
@@ -275,13 +282,7 @@ struct NestedLoopVisitor<'a, 'b, 'tcx> {
         found_local: bool,
         used_after: bool,
     }
-    impl Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
-        type Map = ErasedMap<'tcx>;
-
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-
+    impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> {
         fn visit_local(&mut self, l: &'tcx Local<'_>) {
             if !self.after_loop {
                 l.pat.each_binding_or_first(&mut |_, id, _, _| {
index 41f5a913b316e1db5b61ac63cd48e3ef2ba61c38..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;
@@ -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,
                 );
             }
index 86819752f90ffe1753eaa2baa4d681f569bf9046..2af3555e370a4b8ec15f0c4204e24276abe324c1 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
+    Term, AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
     IsAsync, ItemKind, LifetimeName, TraitRef, Ty, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -140,7 +140,7 @@ fn future_output_ty<'tcx>(trait_ref: &'tcx TraitRef<'tcx>) -> Option<&'tcx Ty<'t
         if args.bindings.len() == 1;
         let binding = &args.bindings[0];
         if binding.ident.name == sym::Output;
-        if let TypeBindingKind::Equality{ty: output} = binding.kind;
+        if let TypeBindingKind::Equality{term: Term::Ty(output)} = binding.kind;
         then {
             return Some(output)
         }
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 f8e28f1671f07cc66b26a6f0dd74570d38595d95..039cb3aafdb780eca45eaeadd8c71626e6f84ac8 100644 (file)
@@ -6,11 +6,10 @@
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_hir::def::Res;
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::BinOpKind;
 use rustc_hir::{BorrowKind, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
 use rustc_middle::ty;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -203,11 +202,6 @@ struct StrippingFinder<'a, 'tcx> {
     }
 
     impl<'a, 'tcx> Visitor<'tcx> for StrippingFinder<'a, 'tcx> {
-        type Map = Map<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-
         fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
             if_chain! {
                 if is_ref_str(self.cx, ex);
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..b0eebf35e274df6694fef2524b96aaafcf0f90a1 100644 (file)
@@ -2,10 +2,9 @@
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, MatchSource, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -55,7 +54,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);
@@ -86,12 +85,6 @@ struct MatchExprVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for MatchExprVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
     fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
         match ex.kind {
             ExprKind::MethodCall(segment, _, [receiver], _) if self.case_altered(segment.ident.as_str(), receiver) => {
index 22970507f964c2c9416ab1fadead327da3637995..33d022c73a5e7c007aa286918e8a78e6db392321 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,
@@ -1790,7 +1776,7 @@ mod redundant_pattern_match {
     use rustc_errors::Applicability;
     use rustc_hir::LangItem::{OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
     use rustc_hir::{
-        intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor},
+        intravisit::{walk_expr, Visitor},
         Arm, Block, Expr, ExprKind, LangItem, MatchSource, Node, Pat, PatKind, QPath, UnOp,
     };
     use rustc_lint::LateContext;
@@ -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,17 +1874,12 @@ 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,
         }
         impl<'a, 'tcx> Visitor<'tcx> for V<'a, 'tcx> {
-            type Map = ErasedMap<'tcx>;
-            fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-                NestedVisitorMap::None
-            }
-
             fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
                 match expr.kind {
                     // Taking the reference of a value leaves a temporary
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 90492ffda3cc6e626706dde8ee340b459ff7bd38..865e7702b7151567bb0e12da002d1265b2b77301 100644 (file)
@@ -1,31 +1,40 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_context;
+use clippy_utils::ty::peel_mid_ty_refs;
 use clippy_utils::{is_diag_item_method, is_diag_trait_item};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_middle::ty::TyS;
-use rustc_span::{sym, Span};
+use rustc_span::sym;
 
 use super::IMPLICIT_CLONE;
 
-pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, span: Span) {
+pub fn check(cx: &LateContext<'_>, method_name: &str, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
     if_chain! {
         if let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
         if is_clone_like(cx, method_name, method_def_id);
         let return_type = cx.typeck_results().expr_ty(expr);
-        let input_type = cx.typeck_results().expr_ty(recv).peel_refs();
+        let input_type = cx.typeck_results().expr_ty(recv);
+        let (input_type, ref_count) = peel_mid_ty_refs(input_type);
         if let Some(ty_name) = input_type.ty_adt_def().map(|adt_def| cx.tcx.item_name(adt_def.did));
         if TyS::same_type(return_type, input_type);
         then {
+            let mut app = Applicability::MachineApplicable;
+            let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
             span_lint_and_sugg(
                 cx,
                 IMPLICIT_CLONE,
-                span,
+                expr.span,
                 &format!("implicitly cloning a `{}` by calling `{}` on its dereferenced type", ty_name, method_name),
                 "consider using",
-                "clone".to_string(),
-                Applicability::MachineApplicable
+                if ref_count > 1 {
+                    format!("({}{}).clone()", "*".repeat(ref_count - 1), recv_snip)
+                } else {
+                    format!("{}.clone()", recv_snip)
+                },
+                app,
             );
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
new file mode 100644 (file)
index 0000000..ca33bfc
--- /dev/null
@@ -0,0 +1,62 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::{get_iterator_item_ty, is_copy};
+use itertools::Itertools;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use std::ops::Not;
+
+use super::ITER_OVEREAGER_CLONED;
+use crate::redundant_clone::REDUNDANT_CLONE;
+
+/// lint overeager use of `cloned()` for `Iterator`s
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx hir::Expr<'_>,
+    recv: &'tcx hir::Expr<'_>,
+    name: &str,
+    map_arg: &[hir::Expr<'_>],
+) {
+    // Check if it's iterator and get type associated with `Item`.
+    let inner_ty = match get_iterator_item_ty(cx, cx.typeck_results().expr_ty_adjusted(recv)) {
+        Some(ty) => ty,
+        _ => return,
+    };
+
+    match inner_ty.kind() {
+        ty::Ref(_, ty, _) if !is_copy(cx, ty) => {},
+        _ => return,
+    };
+
+    let (lint, preserve_cloned) = match name {
+        "count" => (REDUNDANT_CLONE, false),
+        _ => (ITER_OVEREAGER_CLONED, true),
+    };
+    let wildcard_params = map_arg.is_empty().not().then(|| "...").unwrap_or_default();
+    let msg = format!(
+        "called `cloned().{}({})` on an `Iterator`. It may be more efficient to call `{}({}){}` instead",
+        name,
+        wildcard_params,
+        name,
+        wildcard_params,
+        preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
+    );
+
+    span_lint_and_sugg(
+        cx,
+        lint,
+        expr.span,
+        &msg,
+        "try this",
+        format!(
+            "{}.{}({}){}",
+            snippet(cx, recv.span, ".."),
+            name,
+            map_arg.iter().map(|a| snippet(cx, a.span, "..")).join(", "),
+            preserve_cloned.then(|| ".cloned()").unwrap_or_default(),
+        ),
+        Applicability::MachineApplicable,
+    );
+}
index 4e33b2ff14cdeaa2e3d7427e5349c30c2f22a5d5..a9a06c3db75545703a387dd16d86efa763841408 100644 (file)
@@ -30,6 +30,7 @@
 mod iter_next_slice;
 mod iter_nth;
 mod iter_nth_zero;
+mod iter_overeager_cloned;
 mod iter_skip_next;
 mod iterator_step_by_zero;
 mod manual_saturating_arithmetic;
@@ -80,7 +81,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;
 
     "used `cloned` where `copied` could be used instead"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `_.cloned().<func>()` where call to `.cloned()` can be postponed.
+    ///
+    /// ### Why is this bad?
+    /// It's often inefficient to clone all elements of an iterator, when eventually, only some
+    /// of them will be consumed.
+    ///
+    /// ### Examples
+    /// ```rust
+    /// # let vec = vec!["string".to_string()];
+    ///
+    /// // Bad
+    /// vec.iter().cloned().take(10);
+    ///
+    /// // Good
+    /// vec.iter().take(10).cloned();
+    ///
+    /// // Bad
+    /// vec.iter().cloned().last();
+    ///
+    /// // Good
+    /// vec.iter().last().cloned();
+    ///
+    /// ```
+    /// ### Known Problems
+    /// This `lint` removes the side of effect of cloning items in the iterator.
+    /// A code that relies on that side-effect could fail.
+    ///
+    #[clippy::version = "1.59.0"]
+    pub ITER_OVEREAGER_CLONED,
+    perf,
+    "using `cloned()` early with `Iterator::iter()` can lead to some performance inefficiencies"
+}
+
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for usages of `Iterator::flat_map()` where `filter_map()` could be
     /// ### 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");
@@ -1946,6 +1986,7 @@ pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Sel
     CLONE_ON_COPY,
     CLONE_ON_REF_PTR,
     CLONE_DOUBLE_REF,
+    ITER_OVEREAGER_CLONED,
     CLONED_INSTEAD_OF_COPIED,
     FLAT_MAP_OPTION,
     INEFFICIENT_TO_STRING,
@@ -1997,24 +2038,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 +2090,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 +2166,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;
             }
 
@@ -2145,12 +2178,16 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
                 // one of the associated types must be Self
                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
                     if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
+                        let assoc_ty = match projection_predicate.term {
+                          ty::Term::Ty(ty) => ty,
+                          ty::Term::Const(_c) => continue,
+                        };
                         // 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(assoc_ty, self_adt) {
                                 return;
                             }
-                        } else if contains_ty(cx.tcx, projection_predicate.ty, self_ty) {
+                        } else if contains_ty(assoc_ty, self_ty) {
                             return;
                         }
                     }
@@ -2199,7 +2236,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 +2254,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 +2270,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 +2284,15 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 },
                 _ => {},
             },
-            ("count", []) => match method_call!(recv) {
-                Some((name @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
-                    iter_count::check(cx, expr, recv2, name);
+            (name @ "count", args @ []) => match method_call(recv) {
+                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
+                Some((name2 @ ("into_iter" | "iter" | "iter_mut"), [recv2], _)) => {
+                    iter_count::check(cx, expr, recv2, name2);
                 },
                 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),
             },
@@ -2270,14 +2308,14 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 flat_map_identity::check(cx, expr, arg, span);
                 flat_map_option::check(cx, expr, arg, span);
             },
-            ("flatten", []) => {
-                if let Some(("map", [recv, map_arg], _)) = method_call!(recv) {
-                    map_flatten::check(cx, expr, recv, map_arg);
-                }
+            (name @ "flatten", args @ []) => match method_call(recv) {
+                Some(("map", [recv, map_arg], _)) => map_flatten::check(cx, expr, recv, map_arg),
+                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
+                _ => {},
             },
             ("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);
                 }
             },
@@ -2285,8 +2323,15 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
             ("is_file", []) => filetype_is_file::check(cx, expr, recv),
             ("is_none", []) => check_is_some_is_none(cx, expr, recv, false),
             ("is_some", []) => check_is_some_is_none(cx, expr, recv, true),
+            ("last", args @ []) | ("skip", args @ [_]) => {
+                if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+                    if let ("cloned", []) = (name2, args2) {
+                        iter_overeager_cloned::check(cx, expr, recv2, name, args);
+                    }
+                }
+            },
             ("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),
@@ -2300,20 +2345,22 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 map_identity::check(cx, expr, recv, m_arg, span);
             },
             ("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
-            ("next", []) => {
-                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),
-                        ("iter", []) => iter_next_slice::check(cx, expr, recv),
-                        ("skip", [arg]) => iter_skip_next::check(cx, expr, recv, arg),
+            (name @ "next", args @ []) => {
+                if let Some((name2, [recv2, args2 @ ..], _)) = method_call(recv) {
+                    match (name2, args2) {
+                        ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
+                        ("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
+                        ("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, msrv),
+                        ("iter", []) => iter_next_slice::check(cx, expr, recv2),
+                        ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
                         ("skip_while", [_]) => skip_while_next::check(cx, expr),
                         _ => {},
                     }
                 }
             },
-            ("nth", [n_arg]) => match method_call!(recv) {
+            ("nth", args @ [n_arg]) => match method_call(recv) {
                 Some(("bytes", [recv2], _)) => bytes_nth::check(cx, expr, recv2, n_arg),
+                Some(("cloned", [recv2], _)) => iter_overeager_cloned::check(cx, expr, recv2, name, args),
                 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),
                 _ => iter_nth_zero::check(cx, expr, recv, n_arg),
@@ -2341,15 +2388,22 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
                 }
             },
             ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg),
+            ("take", args @ [_arg]) => {
+                if let Some((name2, [recv2, args2 @ ..], _span2)) = method_call(recv) {
+                    if let ("cloned", []) = (name2, args2) {
+                        iter_overeager_cloned::check(cx, expr, recv2, name, args);
+                    }
+                }
+            },
             ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => {
-                implicit_clone::check(cx, name, expr, recv, span);
+                implicit_clone::check(cx, name, expr, recv);
             },
-            ("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 +2412,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 +2425,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 +2589,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 2faa6a69f81dc136bb45e56b11f779149015ecc3..9c6f421103185c7f02437bc63372256642fa3111 100644 (file)
@@ -5,10 +5,10 @@
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_path, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_path, Visitor};
 use rustc_hir::{self, HirId, Path};
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_span::source_map::Span;
 use rustc_span::{sym, Symbol};
 
@@ -97,15 +97,15 @@ struct UnwrapVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
     fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
         self.identifiers.insert(ident(path));
         walk_path(self, path);
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }
 
@@ -116,7 +116,7 @@ struct MapExprVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for MapExprVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
     fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
         if self.identifiers.contains(&ident(path)) {
@@ -126,8 +126,8 @@ fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
         walk_path(self, path);
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }
 
index 4e4653dadcafcdc1bfe926c2c9cda0a58eea697b..448dc4e6147ffb97470ad021a674bab68c8ed432 100644 (file)
@@ -4,6 +4,7 @@
 use clippy_utils::ty::{implements_trait, match_type};
 use clippy_utils::{contains_return, is_trait_item, last_path_segment, paths};
 use if_chain::if_chain;
+use rustc_errors::emitter::MAX_SUGGESTION_HIGHLIGHT_LINES;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -23,6 +24,7 @@ pub(super) fn check<'tcx>(
     args: &'tcx [hir::Expr<'_>],
 ) {
     /// Checks for `unwrap_or(T::new())` or `unwrap_or(T::default())`.
+    #[allow(clippy::too_many_arguments)]
     fn check_unwrap_or_default(
         cx: &LateContext<'_>,
         name: &str,
@@ -31,6 +33,7 @@ fn check_unwrap_or_default(
         arg: &hir::Expr<'_>,
         or_has_args: bool,
         span: Span,
+        method_span: Span,
     ) -> bool {
         let is_default_default = || is_trait_item(cx, fun, sym::Default);
 
@@ -52,16 +55,27 @@ fn check_unwrap_or_default(
 
             then {
                 let mut applicability = Applicability::MachineApplicable;
+                let hint = "unwrap_or_default()";
+                let mut sugg_span = span;
+
+                let mut sugg: String = format!(
+                    "{}.{}",
+                    snippet_with_applicability(cx, self_expr.span, "..", &mut applicability),
+                    hint
+                );
+
+                if sugg.lines().count() > MAX_SUGGESTION_HIGHLIGHT_LINES {
+                    sugg_span = method_span.with_hi(span.hi());
+                    sugg = hint.to_string();
+                }
+
                 span_lint_and_sugg(
                     cx,
                     OR_FUN_CALL,
-                    span,
+                    sugg_span,
                     &format!("use of `{}` followed by a call to `{}`", name, path),
                     "try this",
-                    format!(
-                        "{}.unwrap_or_default()",
-                        snippet_with_applicability(cx, self_expr.span, "..", &mut applicability)
-                    ),
+                    sugg,
                     applicability,
                 );
 
@@ -164,7 +178,7 @@ fn check_general_case<'tcx>(
         match inner_arg.kind {
             hir::ExprKind::Call(fun, or_args) => {
                 let or_has_args = !or_args.is_empty();
-                if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span) {
+                if !check_unwrap_or_default(cx, name, fun, self_arg, arg, or_has_args, expr.span, method_span) {
                     let fun_span = if or_has_args { None } else { Some(fun.span) };
                     check_general_case(cx, name, method_span, self_arg, arg, expr.span, fun_span);
                 }
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 59bdfb923ed49f2229c00b478677f78fb05b2717..784014f0d87433de6b4b373052c7ffe4eb0e1fb3 100644 (file)
@@ -2,10 +2,9 @@
 use clippy_utils::usage::mutated_variables;
 use clippy_utils::{is_lang_ctor, is_trait_method, path_to_local_id};
 use rustc_hir as hir;
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
 use rustc_middle::ty::{self, TyS};
 use rustc_span::sym;
 
@@ -113,8 +112,6 @@ fn new(cx: &'a LateContext<'tcx>, arg_id: hir::HirId) -> ReturnVisitor<'a, 'tcx>
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for ReturnVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
         if let hir::ExprKind::Ret(Some(expr)) = &expr.kind {
             let (found_mapping, found_filtering) = check_expression(self.cx, self.arg_id, expr);
@@ -124,8 +121,4 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
             walk_expr(self, expr);
         }
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
index 8300df03e9935a9f0219364edc2ebc3a817cd2c4..5fee18c5129a90d9cc4ae690aa47c7c33bea30cc 100644 (file)
@@ -4,21 +4,22 @@
 use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait};
 use clippy_utils::{fn_def_id, get_parent_expr, path_to_local_id, usage};
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, HirId, LangItem, Mutability, Pat};
 use rustc_lint::LateContext;
-use rustc_middle::{hir::map::Map, ty};
+use rustc_middle::hir::nested_filter;
+use rustc_middle::ty;
 use rustc_span::{sym, Symbol};
 
 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 +31,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 +72,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 +102,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>,
@@ -128,10 +140,10 @@ struct CloneOrCopyVisitor<'cx, 'tcx> {
 }
 
 impl<'cx, 'tcx> Visitor<'tcx> for CloneOrCopyVisitor<'cx, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
index c48bacfce0d37739f159b379fac6d10921093dac..9162de3cceafa3b377c67020154ece42f4c170cd 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,
@@ -239,9 +243,10 @@ fn check_other_call_arg(
         if if trait_predicate.def_id() == deref_trait_id {
             if let [projection_predicate] = projection_predicates[..] {
                 let normalized_ty =
-                    cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.ty);
+                    cx.tcx.subst_and_normalize_erasing_regions(call_substs, cx.param_env, projection_predicate.term);
                 implements_trait(cx, receiver_ty, deref_trait_id, &[])
-                    && get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(normalized_ty)
+                    && get_associated_type(cx, receiver_ty, deref_trait_id,
+                    "Target").map_or(false, |ty| ty::Term::Ty(ty) == normalized_ty)
             } else {
                 false
             }
@@ -278,7 +283,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 +299,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 +324,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 +364,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..8db71d1e967620ca73267880368df8dafc609090 100644 (file)
@@ -548,6 +548,7 @@ fn is_array(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     matches!(&cx.typeck_results().expr_ty(expr).peel_refs().kind(), ty::Array(_, _))
 }
 
+#[allow(clippy::too_many_lines)]
 fn check_to_owned(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool) {
     #[derive(Default)]
     struct EqImpl {
@@ -644,10 +645,26 @@ fn symmetric_partial_eq<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, other: Ty<'t
                 hint = expr_snip;
             } else {
                 span = expr.span.to(other.span);
+
+                let cmp_span = if other.span < expr.span {
+                    other.span.between(expr.span)
+                } else {
+                    expr.span.between(other.span)
+                };
                 if eq_impl.ty_eq_other {
-                    hint = format!("{} == {}", expr_snip, snippet(cx, other.span, ".."));
+                    hint = format!(
+                        "{}{}{}",
+                        expr_snip,
+                        snippet(cx, cmp_span, ".."),
+                        snippet(cx, other.span, "..")
+                    );
                 } else {
-                    hint = format!("{} == {}", snippet(cx, other.span, ".."), expr_snip);
+                    hint = format!(
+                        "{}{}{}",
+                        snippet(cx, other.span, ".."),
+                        snippet(cx, cmp_span, ".."),
+                        expr_snip
+                    );
                 }
             }
 
@@ -717,7 +734,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 bcbea8f1e66b47edadc368481dc4a50584b48597..cb16f00047a394b06b147151fd0244f9bde86274 100644 (file)
@@ -3,7 +3,6 @@
 use rustc_hir as hir;
 use rustc_hir::intravisit;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -47,8 +46,6 @@ pub struct MutVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> intravisit::Visitor<'tcx> for MutVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
         if in_external_macro(self.cx.sess(), expr.span) {
             return;
@@ -114,7 +111,4 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
 
         intravisit::walk_ty(self, ty);
     }
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::None
-    }
 }
index 12e219cd5c8714318c166726acae0c659bb6c32c..cd1bc20237028dbce9fef4a3c0fa711c7750dd54 100644 (file)
@@ -1,9 +1,9 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{higher, is_direct_expn_of};
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{BorrowKind, Expr, ExprKind, MatchSource, Mutability};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 
 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
+                    ),
+                );
             }
         }
     }
@@ -80,7 +84,7 @@ fn expr_span(&self) -> Option<Span> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         match expr.kind {
@@ -111,7 +115,7 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         walk_expr(self, expr);
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }
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..44c4b70524d9371353f42858188077cc4ac9cbad 100644 (file)
@@ -1,10 +1,9 @@
 use rustc_errors::Applicability;
 use rustc_hir::{
-    intravisit::{walk_expr, NestedVisitorMap, Visitor},
+    intravisit::{walk_expr, Visitor},
     Expr, ExprKind, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{source_map::Span, sym, Symbol};
 
@@ -48,7 +47,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,
@@ -136,8 +135,6 @@ struct RetCollector {
 }
 
 impl<'tcx> Visitor<'tcx> for RetCollector {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &Expr<'_>) {
         match expr.kind {
             ExprKind::Ret(..) => {
@@ -160,8 +157,4 @@ fn visit_expr(&mut self, expr: &Expr<'_>) {
 
         walk_expr(self, expr);
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
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 7d2ff083b7e07f95b8c76971933638d3caf175f2..21ac6548b0179cafa486608e4f7153d04e137080 100644 (file)
@@ -280,7 +280,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 {
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..3e0e32857f1dad1e0c02b49426f0e485e397982b 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,10 +624,7 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Loca
                 .flat_map(HybridBitSet::iter)
                 .collect();
 
-            if ContainsRegion(self.cx.tcx)
-                .visit_ty(self.body.local_decls[*dest].ty)
-                .is_break()
-            {
+            if ContainsRegion.visit_ty(self.body.local_decls[*dest].ty).is_break() {
                 mutable_variables.push(*dest);
             }
 
@@ -703,15 +700,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 +761,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 0de282542fc3c73fc0e15446364b1505e1b3c3b8..0c77cf5e77dd28232f97e0e80c5adcb8209eaeb5 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_hir::intravisit as hir_visit;
 use rustc_hir::intravisit::Visitor as HirVisitor;
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -106,7 +106,7 @@ struct ClosureUsageCount<'a, 'tcx> {
                 count: usize,
             }
             impl<'a, 'tcx> hir_visit::Visitor<'tcx> for ClosureUsageCount<'a, 'tcx> {
-                type Map = Map<'tcx>;
+                type NestedFilter = nested_filter::OnlyBodies;
 
                 fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                     if_chain! {
@@ -121,8 +121,8 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
                     hir_visit::walk_expr(self, expr);
                 }
 
-                fn nested_visit_map(&mut self) -> hir_visit::NestedVisitorMap<Self::Map> {
-                    hir_visit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+                fn nested_visit_map(&mut self) -> Self::Map {
+                    self.cx.tcx.hir()
                 }
             }
             let mut closure_usage_count = ClosureUsageCount { cx, path, count: 0 };
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..79f104eac0be24c9e5b55e719021af891613471a 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
     ///     }
     /// }
     /// ```
     #[clippy::version = "1.59.0"]
     pub RETURN_SELF_NOT_MUST_USE,
-    suspicious,
+    pedantic,
     "missing `#[must_use]` annotation on a method returning `Self`"
 }
 
 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..8068fa22d9ccf8eea0fb4801d0d9b3f92193184a 100644 (file)
@@ -4,10 +4,9 @@
 use if_chain::if_chain;
 use rustc_ast::ast::Attribute;
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, FnKind, Visitor};
 use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, PatKind, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -287,8 +286,6 @@ struct BorrowVisitor<'a, 'tcx> {
 }
 
 impl<'tcx> Visitor<'tcx> for BorrowVisitor<'_, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         if self.borrows {
             return;
@@ -301,14 +298,10 @@ 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(_)));
         }
 
         walk_expr(self, expr);
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
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 1ae772ef70b124ae31244efd4ca23cc2058b7e38..607fa847dae5f61959f8dd69c5f902f88bc376bf 100644 (file)
@@ -5,10 +5,9 @@
 use if_chain::if_chain;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor};
 use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::symbol::sym;
 
@@ -270,8 +269,6 @@ fn is_repeat_zero(&self, expr: &Expr<'_>) -> bool {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_stmt(&mut self, stmt: &'tcx Stmt<'_>) {
         if self.initialization_found {
             match stmt.kind {
@@ -308,8 +305,4 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
 
         walk_expr(self, expr);
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
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..c3d984fb5ae10b3d57314fedc1f4940dacf75e8e 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),
@@ -567,7 +567,6 @@ fn ident_difference_expr_with_base_location(
         | (Repeat(_, _), Repeat(_, _))
         | (Struct(_), Struct(_))
         | (MacCall(_), MacCall(_))
-        | (LlvmInlineAsm(_), LlvmInlineAsm(_))
         | (InlineAsm(_), InlineAsm(_))
         | (Ret(_), Ret(_))
         | (Continue(_), Continue(_))
index a3195de81d15c7415be7d5f95a3626ad1c0ba54a..4294464dbf61a5fffbda1a1d728a9c3a71608f9d 100644 (file)
@@ -2,9 +2,8 @@
 use clippy_utils::{binop_traits, trait_ref_of_method, BINOP_TRAITS, OP_ASSIGN_TRAITS};
 use if_chain::if_chain;
 use rustc_hir as hir;
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -66,7 +65,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);
@@ -104,8 +103,6 @@ struct BinaryExprVisitor {
 }
 
 impl<'tcx> Visitor<'tcx> for BinaryExprVisitor {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
         match expr.kind {
             hir::ExprKind::Binary(..)
@@ -116,8 +113,4 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
 
         walk_expr(self, expr);
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
index af36f7267004d3c71db87e595e016f981f7ec942..c9b2ce476e89d0d5cb8408a7b4f0978a3593c5fb 100644 (file)
@@ -53,13 +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::ArrayLen::Body(length) = length;
+        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 20c136407a1b6a7c2cd8f7a744d2109b1b1309d4..5ca4023aa5c199b3d8d2296525b2f2eb5640057b 100644 (file)
@@ -1,9 +1,8 @@
 use clippy_utils::diagnostics::span_lint;
 use rustc_hir as hir;
-use rustc_hir::intravisit::{walk_inf, walk_ty, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_inf, walk_ty, Visitor};
 use rustc_hir::{GenericParamKind, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
 use rustc_target::spec::abi::Abi;
 
 use super::TYPE_COMPLEXITY;
@@ -37,8 +36,6 @@ struct TypeComplexityVisitor {
 }
 
 impl<'tcx> Visitor<'tcx> for TypeComplexityVisitor {
-    type Map = Map<'tcx>;
-
     fn visit_infer(&mut self, inf: &'tcx hir::InferArg) {
         self.score += 1;
         walk_inf(self, inf);
@@ -78,7 +75,4 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'_>) {
         walk_ty(self, ty);
         self.nest -= sub_nest;
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
index 3d3b4a6679dd1e445b956a8777b6a6e889c93b8d..e42c6c63ede0ba2e419de335318e2bcf841d4a89 100644 (file)
@@ -2,11 +2,10 @@
 use clippy_utils::is_lint_allowed;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet};
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, HirId, Local, UnsafeSource};
 use rustc_lexer::TokenKind;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -113,13 +112,7 @@ fn check_block_post(&mut self, _: &LateContext<'_>, _: &'_ Block<'_>) {
     }
 }
 
-impl<'hir> Visitor<'hir> for UndocumentedUnsafeBlocks {
-    type Map = Map<'hir>;
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
-
+impl<'v> Visitor<'v> for UndocumentedUnsafeBlocks {
     fn visit_expr(&mut self, ex: &'v Expr<'v>) {
         match ex.kind {
             ExprKind::Block(_, _) => self.local_level = self.local_level.saturating_add(1),
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 fe35ff33d35a4736f49f8a3b656e75b3f82b787d..68156df2ecea879c1067e9c184131cbd53579d28 100644 (file)
@@ -98,9 +98,10 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
                         if trait_pred.self_ty() == inp;
                         if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
                         then {
-                            if ord_preds.iter().any(|ord| ord.self_ty() == return_ty_pred.ty) {
+                            if ord_preds.iter().any(|ord| Some(ord.self_ty()) ==
+                            return_ty_pred.term.ty()) {
                                 args_to_check.push((i, "Ord".to_string()));
-                            } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.ty) {
+                            } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) {
                                 args_to_check.push((i, "PartialOrd".to_string()));
                             }
                         }
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..7d75ff36e971ab3dc01230c6c533d1dcb861be1e 100644 (file)
@@ -224,10 +224,7 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintTrigger> {
 
 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)
-            .any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
+    matches!(ty.kind(), ty::Ref(..)) || ty.walk().any(|arg| matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
 }
 
 impl LateLintPass<'_> for UnnecessarySortBy {
index 1ccb78425c29af05f3415a393603ad08be412012..2b89398ecd6ad1ea3ed6be1359814d43aa0be47c 100644 (file)
@@ -1,8 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnHeader, HirId, IsAsync, YieldSource};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 
@@ -43,7 +43,7 @@ struct AsyncFnVisitor<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
         if let ExprKind::Yield(_, YieldSource::Await { .. }) = ex.kind {
@@ -52,8 +52,8 @@ fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
         walk_expr(self, ex);
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }
 
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 918fa5f7dc12467bb6a19fd5601756d5ccf027eb..0a728d7700b3073ee6b00435fdec36d8f77f10ee 100644 (file)
@@ -4,10 +4,10 @@
 use clippy_utils::{differing_macro_contexts, path_to_local, usage::is_potentially_mutated};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
 use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, PathSegment, UnOp};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::Ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -215,7 +215,7 @@ fn visit_branch(
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for UnwrappableVariablesVisitor<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // Shouldn't lint when `expr` is in macro.
@@ -297,8 +297,8 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         }
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }
 
index 994df85cb8ac4f7c5130275884a75f12e34491f6..2c13f1049b59955a2e81ebb7b42dc1f5317c1fe3 100644 (file)
@@ -3,10 +3,9 @@
 use clippy_utils::{method_chain_args, return_ty};
 use if_chain::if_chain;
 use rustc_hir as hir;
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Expr, ImplItemKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::hir::map::Map;
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{sym, Span};
@@ -81,8 +80,6 @@ struct FindExpectUnwrap<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for FindExpectUnwrap<'a, 'tcx> {
-    type Map = Map<'tcx>;
-
     fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // check for `expect`
         if let Some(arglists) = method_chain_args(expr, &["expect"]) {
@@ -107,10 +104,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
         // and check sub-expressions
         intravisit::walk_expr(self, expr);
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) {
index a86db58741eb6ca0a052b2dbf21756dd0ee2d03f..6c5a5fe1434f8885ed8686eefee5378d1e78c66e 100644 (file)
@@ -8,11 +8,10 @@
     self as hir,
     def::{CtorOf, DefKind, Res},
     def_id::LocalDefId,
-    intravisit::{walk_inf, walk_ty, NestedVisitorMap, Visitor},
+    intravisit::{walk_inf, walk_ty, Visitor},
     Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Path, QPath, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
@@ -170,7 +169,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);
@@ -262,8 +261,6 @@ struct SkipTyCollector {
 }
 
 impl<'tcx> Visitor<'tcx> for SkipTyCollector {
-    type Map = Map<'tcx>;
-
     fn visit_infer(&mut self, inf: &hir::InferArg) {
         self.types_to_skip.push(inf.hir_id);
 
@@ -274,10 +271,6 @@ fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) {
 
         walk_ty(self, hir_ty);
     }
-
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 fn span_lint(cx: &LateContext<'_>, span: Span) {
index 9b06ca4e824932c7492d25f9e8421c231c9b6e73..1d7bb24302606aab731c945d6e32b2bee4ab35f8 100644 (file)
@@ -547,10 +547,6 @@ macro_rules! kind {
                 kind!("InlineAsm(_)");
                 out!("// unimplemented: `ExprKind::InlineAsm` is not further destructured at the moment");
             },
-            ExprKind::LlvmInlineAsm(_) => {
-                kind!("LlvmInlineAsm(_)");
-                out!("// unimplemented: `ExprKind::LlvmInlineAsm` is not further destructured at the moment");
-            },
             ExprKind::Struct(qpath, fields, base) => {
                 bind!(self, qpath, fields);
                 opt_bind!(self, base);
@@ -573,7 +569,7 @@ macro_rules! kind {
                         bind!(self, anon_const);
                         out!("if let ArrayLen::Body({anon_const}) = {length};");
                         self.body(field!(anon_const.body));
-                    }
+                    },
                 }
             },
             ExprKind::Err => kind!("Err"),
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 c96766e56784f2b4fc3fce17403dea3153fc6266..89eae06fef79b04a65ca76f986ced2efcc3b4534 100644 (file)
@@ -304,19 +304,6 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
                 }
             }
         },
-        hir::ExprKind::LlvmInlineAsm(asm) => {
-            let inputs = &asm.inputs_exprs;
-            let outputs = &asm.outputs_exprs;
-            println!("{}LlvmInlineAsm", ind);
-            println!("{}inputs:", ind);
-            for e in inputs.iter() {
-                print_expr(cx, e, indent + 1);
-            }
-            println!("{}outputs:", ind);
-            for e in outputs.iter() {
-                print_expr(cx, e, indent + 1);
-            }
-        },
         hir::ExprKind::Struct(path, fields, ref base) => {
             println!("{}Struct", ind);
             println!("{}path: {:?}", ind, path);
@@ -342,8 +329,8 @@ fn print_expr(cx: &LateContext<'_>, expr: &hir::Expr<'_>, indent: usize) {
             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)
-                }
+                    print_expr(cx, &cx.tcx.hir().body(anon_const.body).value, indent + 1);
+                },
             }
         },
         hir::ExprKind::Err => {
index 7d196af7a53f475e6046fece7d2bb972fe60575e..02fa866db5235586530d45b04d4b7cb61696d03b 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::{
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::hir_id::CRATE_HIR_ID;
-use rustc_hir::intravisit::{NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::Visitor;
 use rustc_hir::{
     BinOpKind, Block, Expr, ExprKind, HirId, Item, Local, MutTy, Mutability, Node, Path, Stmt, StmtKind, Ty, TyKind,
     UnOp,
 };
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::map::Map;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty;
 use rustc_semver::RustcVersion;
@@ -34,7 +34,7 @@
 
 use std::borrow::{Borrow, Cow};
 
-#[cfg(feature = "metadata-collector-lint")]
+#[cfg(feature = "internal")]
 pub mod metadata_collector;
 
 declare_clippy_lint! {
@@ -410,9 +410,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,
@@ -539,7 +543,7 @@ struct LintCollector<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for LintCollector<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::All;
 
     fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
         if path.segments.len() == 1 {
@@ -547,8 +551,8 @@ fn visit_path(&mut self, path: &'tcx Path<'_>, _: HirId) {
         }
     }
 
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::All(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }
 
@@ -924,9 +928,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.module_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;
+                        }
                     }
                 }
             }
index 7707eebd6223e2cb01ab4b0b4bd559ab3fc7aa6c..8485c14bfe72a5ea338a2af8003b3201fe13fddb 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
@@ -20,7 +19,6 @@
     self as hir, def::DefKind, intravisit, intravisit::Visitor, ExprKind, Item, ItemKind, Mutability, QPath,
 };
 use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId};
-use rustc_middle::hir::map::Map;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, Loc, Span, Symbol};
 use serde::{ser::SerializeStruct, Serialize, Serializer};
@@ -578,7 +576,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 +695,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));
@@ -739,10 +737,10 @@ fn new(cx: &'a LateContext<'hir>) -> Self {
 }
 
 impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> {
-    type Map = Map<'hir>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::All(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 
     fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
@@ -793,10 +791,10 @@ fn complete(self) -> Option<usize> {
 }
 
 impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> {
-    type Map = Map<'hir>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::All(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 
     fn visit_path(&mut self, path: &'hir hir::Path<'hir>, _id: hir::HirId) {
@@ -825,7 +823,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 +833,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)) {
@@ -876,10 +874,10 @@ fn is_multi_part(&self) -> bool {
 }
 
 impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> {
-    type Map = Map<'hir>;
+    type NestedFilter = nested_filter::All;
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::All(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 
     fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) {
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..604c95d2bc81f17c4a3fe86ea71337bf8fb158e1 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;
@@ -646,11 +645,19 @@ pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
     }
 }
 
-pub fn eq_assoc_constraint(l: &AssocTyConstraint, r: &AssocTyConstraint) -> bool {
-    use AssocTyConstraintKind::*;
+fn eq_term(l: &Term, r: &Term) -> bool {
+  match (l, r) {
+    (Term::Ty(l), Term::Ty(r)) => eq_ty(l,r),
+    (Term::Const(l), Term::Const(r)) => eq_anon_const(l,r),
+    _ => false,
+  }
+}
+
+pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool {
+    use AssocConstraintKind::*;
     eq_id(l.ident, r.ident)
         && match (&l.kind, &r.kind) {
-            (Equality { ty: l }, Equality { ty: r }) => eq_ty(l, r),
+            (Equality { term: l }, Equality { term: r }) => eq_term(l, r),
             (Bound { bounds: l }, Bound { bounds: r }) => over(l, r, eq_generic_bound),
             _ => false,
         }
@@ -679,34 +686,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..34c5af848a6dbe1bfaa92ec1efbfae3e4b4624bf 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<'_>,
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..8bdc59a7175b2eb987499e9aa7ad6ba58eb80562 100644 (file)
@@ -12,7 +12,7 @@
 use crate::ty::{all_predicates_of, is_copy};
 use crate::visitors::is_const_evaluatable;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{def_id::DefId, Block, Expr, ExprKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, PredicateKind};
@@ -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,18 +97,13 @@ 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,
     }
 
     impl<'cx, 'tcx> Visitor<'tcx> for V<'cx, 'tcx> {
-        type Map = ErasedMap<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             use EagernessSuggestion::{ForceNoChange, Lazy, NoChange};
             if self.eagerness == ForceNoChange {
@@ -175,7 +175,6 @@ fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
                 | ExprKind::Continue(_)
                 | ExprKind::Ret(_)
                 | ExprKind::InlineAsm(_)
-                | ExprKind::LlvmInlineAsm(_)
                 | ExprKind::Yield(..)
                 | ExprKind::Err => {
                     self.eagerness = ForceNoChange;
@@ -225,11 +224,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 ac2b1a0259e3e8546d731b525f1f40e2138aaf80..b0fee46f82474a9d893391ffc0dd6246d6060bac 100644 (file)
@@ -6,9 +6,9 @@
 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, ArrayLen
+    StmtKind, Ty, TyKind, TypeBinding,
 };
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::LateContext;
@@ -171,11 +171,11 @@ 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,
-            }
+        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 {
@@ -396,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, ll), &TyKind::Array(rt, rl)) => {
-                self.eq_ty(lt, rt) && self.eq_array_length(ll, rl)
-            },
+            (&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)
             },
@@ -685,7 +683,7 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
                 }
                 self.hash_pat(pat);
             },
-            ExprKind::LlvmInlineAsm(..) | ExprKind::Err => {},
+            ExprKind::Err => {},
             ExprKind::Lit(ref l) => {
                 l.node.hash(&mut self.s);
             },
@@ -853,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 {
@@ -963,7 +963,7 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
 
     pub fn hash_array_length(&mut self, length: ArrayLen) {
         match length {
-            ArrayLen::Infer(..) => {}
+            ArrayLen::Infer(..) => {},
             ArrayLen::Body(anon_const) => self.hash_body(anon_const.body),
         }
     }
index 91ebc7ea89cc026172eb13069f9f356c1ec5e235..5c0800d2f038f8f5c0a55968c7358d764ec48015 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::intravisit::{walk_expr, FnKind, 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, ArrayLen
+    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::map::Map;
 use rustc_middle::hir::place::PlaceBase;
 use rustc_middle::ty as rustc_ty;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
@@ -90,7 +89,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;
@@ -126,7 +124,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) => {
@@ -146,13 +144,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]
@@ -223,7 +214,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(..),
             ..
@@ -282,7 +273,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 {
@@ -298,7 +293,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,
@@ -375,7 +370,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,
@@ -383,7 +378,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()
@@ -522,7 +517,7 @@ macro_rules! try_res {
             }
         };
     }
-    fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Option<Res> {
+    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)
@@ -538,18 +533,34 @@ fn item_child_by_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, name: &str) -> Opt
             _ => 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(|&&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()
@@ -594,12 +605,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(); }
     }
@@ -628,6 +640,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 {
@@ -636,7 +661,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 {
@@ -710,8 +743,7 @@ 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, len) => if_chain! {
-            if let ArrayLen::Body(len) = len;
+        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);
@@ -760,7 +792,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],
@@ -777,8 +809,7 @@ pub fn can_move_expr_to_closure_no_visit(
         | ExprKind::Continue(_)
         | ExprKind::Ret(_)
         | ExprKind::Yield(..)
-        | ExprKind::InlineAsm(_)
-        | ExprKind::LlvmInlineAsm(_) => false,
+        | ExprKind::InlineAsm(_) => false,
         // Accessing a field of a local value can only be done if the type isn't
         // partially moved.
         ExprKind::Field(
@@ -835,7 +866,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
@@ -935,7 +966,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.
@@ -948,12 +979,7 @@ struct V<'cx, 'tcx> {
         /// mutable reference.
         captures: HirIdMap<CaptureKind>,
     }
-    impl Visitor<'tcx> for V<'_, 'tcx> {
-        type Map = ErasedMap<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-
+    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             if !self.allow_closure {
                 return;
@@ -976,8 +1002,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)
@@ -1089,14 +1115,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, .. })
@@ -1112,16 +1137,11 @@ pub struct ContainsName {
 }
 
 impl<'tcx> Visitor<'tcx> for ContainsName {
-    type Map = Map<'tcx>;
-
     fn visit_name(&mut self, _: Span, name: Symbol) {
         if self.name == name {
             self.result = true;
         }
     }
-    fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-        NestedVisitorMap::None
-    }
 }
 
 /// Checks if an `Expr` contains a certain name.
@@ -1146,19 +1166,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
@@ -1218,7 +1225,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(
@@ -1619,7 +1626,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
@@ -1687,32 +1694,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
@@ -1752,7 +1733,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(
         _,
         &[
@@ -1856,7 +1837,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 {
@@ -1962,7 +1943,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)
@@ -2008,7 +1989,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()),
@@ -2016,7 +1997,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());
             },
         }
     }
@@ -2062,8 +2043,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 {
@@ -2086,7 +2067,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 => {
@@ -2100,7 +2081,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) => {
@@ -2183,7 +2164,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 836558b07cb02b110bd500d980b43b98dc57fa4c..7512039a480bb95e191d17eed4b34d3708643d42 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),
@@ -210,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)) => {
@@ -222,8 +233,6 @@ fn check_statement(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, statemen
         // just an assignment
         StatementKind::SetDiscriminant { place, .. } => check_place(tcx, **place, span, body),
 
-        StatementKind::LlvmInlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
-
         StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping { dst, src, count }) => {
             check_operand(tcx, dst, span, body)?;
             check_operand(tcx, src, span, body)?;
@@ -239,7 +248,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) {
@@ -249,7 +258,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;
@@ -274,7 +283,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..563edd32d25185fb3918e344cfe7680760a64a4d 100644 (file)
@@ -147,7 +147,6 @@ fn hir_from_snippet(expr: &hir::Expr<'_>, get_snippet: impl Fn(Span) -> Cow<'a,
             | hir::ExprKind::Field(..)
             | hir::ExprKind::Index(..)
             | hir::ExprKind::InlineAsm(..)
-            | hir::ExprKind::LlvmInlineAsm(..)
             | hir::ExprKind::ConstBlock(..)
             | hir::ExprKind::Lit(..)
             | hir::ExprKind::Loop(..)
@@ -205,7 +204,6 @@ pub fn ast(cx: &EarlyContext<'_>, expr: &ast::Expr, default: &'a str) -> Self {
             | ast::ExprKind::ForLoop(..)
             | ast::ExprKind::Index(..)
             | ast::ExprKind::InlineAsm(..)
-            | ast::ExprKind::LlvmInlineAsm(..)
             | ast::ExprKind::ConstBlock(..)
             | ast::ExprKind::Lit(..)
             | ast::ExprKind::Loop(..)
@@ -461,7 +459,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 +844,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 2066915e1d184a9d6d9d8c96256dddfd057f040c..405e306359bc9b2dfe46278b43c4d5e3c6307a90 100644 (file)
@@ -6,7 +6,7 @@
 use rustc_hir::{Expr, ExprKind, HirId};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
-use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty;
 use rustc_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
@@ -96,18 +96,12 @@ fn collect_binding_hir_ids(body: &'tcx hir::Body<'tcx>) -> Vec<hir::HirId> {
     }
 }
 impl<'tcx> intravisit::Visitor<'tcx> for ParamBindingIdCollector {
-    type Map = Map<'tcx>;
-
     fn visit_pat(&mut self, pat: &'tcx hir::Pat<'tcx>) {
         if let hir::PatKind::Binding(_, hir_id, ..) = pat.kind {
             self.binding_hir_ids.push(hir_id);
         }
         intravisit::walk_pat(self, pat);
     }
-
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::None
-    }
 }
 
 pub struct BindingUsageFinder<'a, 'tcx> {
@@ -127,7 +121,7 @@ pub fn are_params_used(cx: &'a LateContext<'tcx>, body: &'tcx hir::Body<'tcx>) -
     }
 }
 impl<'a, 'tcx> intravisit::Visitor<'tcx> for BindingUsageFinder<'a, 'tcx> {
-    type Map = Map<'tcx>;
+    type NestedFilter = nested_filter::OnlyBodies;
 
     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         if !self.usage_found {
@@ -143,8 +137,8 @@ fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
         }
     }
 
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
     }
 }
 
index 4bfd3c64b9c361acb61001600277e3064bbb2ff3..40451b17a9c63ce30693fbf2ab7147b2a020f284 100644 (file)
@@ -1,12 +1,13 @@
 use crate::path_to_local_id;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::intravisit::{self, walk_block, walk_expr, NestedVisitorMap, Visitor};
+use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor};
 use rustc_hir::{
     Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, Stmt, UnOp, Unsafety,
 };
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
+use rustc_middle::hir::nested_filter;
 use rustc_middle::ty;
 
 /// Convenience method for creating a `Visitor` with just `visit_expr` overridden and nested
@@ -19,9 +20,9 @@ struct V<'tcx, F> {
         f: F,
     }
     impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> bool> Visitor<'tcx> for V<'tcx, F> {
-        type Map = Map<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::OnlyBodies(self.hir)
+        type NestedFilter = nested_filter::OnlyBodies;
+        fn nested_visit_map(&mut self) -> Self::Map {
+            self.hir
         }
 
         fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
@@ -40,11 +41,6 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
 pub fn expr_visitor_no_bodies<'tcx>(f: impl FnMut(&'tcx Expr<'tcx>) -> bool) -> impl Visitor<'tcx> {
     struct V<F>(F);
     impl<'tcx, F: FnMut(&'tcx Expr<'tcx>) -> bool> Visitor<'tcx> for V<F> {
-        type Map = intravisit::ErasedMap<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             if (self.0)(e) {
                 walk_expr(self, e);
@@ -113,12 +109,6 @@ fn drop(&mut self) {
     }
 
     impl<'hir, F: FnMut(&'hir hir::Expr<'hir>) -> bool> intravisit::Visitor<'hir> for RetFinder<F> {
-        type Map = Map<'hir>;
-
-        fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-            intravisit::NestedVisitorMap::None
-        }
-
         fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) {
             intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt);
         }
@@ -173,7 +163,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 +207,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,15 +221,15 @@ 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,
     }
     impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
-        type Map = Map<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+        type NestedFilter = nested_filter::OnlyBodies;
+        fn nested_visit_map(&mut self) -> Self::Map {
+            self.cx.tcx.hir()
         }
 
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
@@ -321,15 +311,15 @@ 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,
     }
     impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
-        type Map = Map<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::OnlyBodies(self.cx.tcx.hir())
+        type NestedFilter = nested_filter::OnlyBodies;
+        fn nested_visit_map(&mut self) -> Self::Map {
+            self.cx.tcx.hir()
         }
         fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
             if self.is_unsafe {
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 6027538dc4ab22a74ee3a0299a2849667b450dcf..01891b51d3b0fc8f03d41143fc1af92b13ba91ac 100644 (file)
@@ -53,7 +53,7 @@ This gives the following output in clippy:
 
 ## License
 
-Copyright 2014-2020 The Rust Project Developers
+Copyright 2014-2022 The Rust Project Developers
 
 Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
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
 
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
diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed
new file mode 100644 (file)
index 0000000..44e41bd
--- /dev/null
@@ -0,0 +1,29 @@
+// run-rustfix
+
+use std::fmt::{self, Display};
+
+fn main() {
+    let a = Foo;
+
+    if a != "bar" {
+        println!("foo");
+    }
+
+    if a != "bar" {
+        println!("foo");
+    }
+}
+
+struct Foo;
+
+impl Display for Foo {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "foo")
+    }
+}
+
+impl PartialEq<&str> for Foo {
+    fn eq(&self, other: &&str) -> bool {
+        "foo" == *other
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs
new file mode 100644 (file)
index 0000000..662673a
--- /dev/null
@@ -0,0 +1,29 @@
+// run-rustfix
+
+use std::fmt::{self, Display};
+
+fn main() {
+    let a = Foo;
+
+    if a.to_string() != "bar" {
+        println!("foo");
+    }
+
+    if "bar" != a.to_string() {
+        println!("foo");
+    }
+}
+
+struct Foo;
+
+impl Display for Foo {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "foo")
+    }
+}
+
+impl PartialEq<&str> for Foo {
+    fn eq(&self, other: &&str) -> bool {
+        "foo" == *other
+    }
+}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.stderr
new file mode 100644 (file)
index 0000000..e4d0d82
--- /dev/null
@@ -0,0 +1,18 @@
+error: this creates an owned instance just for comparison
+  --> $DIR/comparison_flip.rs:8:8
+   |
+LL |     if a.to_string() != "bar" {
+   |        ^^^^^^^^^^^^^ help: try: `a`
+   |
+   = note: `-D clippy::cmp-owned` implied by `-D warnings`
+
+error: this creates an owned instance just for comparison
+  --> $DIR/comparison_flip.rs:12:17
+   |
+LL |     if "bar" != a.to_string() {
+   |        ---------^^^^^^^^^^^^^
+   |        |
+   |        help: try: `a != "bar"`
+
+error: aborting due to 2 previous errors
+
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 64cb7b1cfb80f6c33ff5e81f7af29cceb1e8b73d..78d2bfd474e4a18cbd9f687e488a69fd03ef076d 100644 (file)
@@ -73,4 +73,10 @@ fn main() {
     let _s: String = (&*v.join("\n")).to_string();
 
     format!("prepend {:+}", "s");
+
+    // Issue #8290
+    let x = "foo";
+    let _ = x.to_string();
+    let _ = format!("{x:?}"); // Don't lint on debug
+    let _ = x.to_string();
 }
index a065b1b5683c1b9ccbfeb81df5cf1b96d7d12c4d..009c1aa216fcd8b6e89f1de0b383c486ce038ec8 100644 (file)
@@ -75,4 +75,10 @@ fn main() {
     let _s: String = format!("{}", &*v.join("\n"));
 
     format!("prepend {:+}", "s");
+
+    // Issue #8290
+    let x = "foo";
+    let _ = format!("{x}");
+    let _ = format!("{x:?}"); // Don't lint on debug
+    let _ = format!("{y}", y = x);
 }
index 58ad7499bb26f530c5202239ac79858ab1aaa79c..660be57585e3710f3839e5f07ab2cea93091e27b 100644 (file)
@@ -99,5 +99,17 @@ error: useless use of `format!`
 LL |     let _s: String = format!("{}", &*v.join("/n"));
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
 
-error: aborting due to 15 previous errors
+error: useless use of `format!`
+  --> $DIR/format.rs:81:13
+   |
+LL |     let _ = format!("{x}");
+   |             ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
+
+error: useless use of `format!`
+  --> $DIR/format.rs:83:13
+   |
+LL |     let _ = format!("{y}", y = x);
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
+
+error: aborting due to 17 previous errors
 
index 271754cb06ee7eb7ffa4ac7a598d62b41a335a22..5521870eaecf761af9b0f50bdbdd941d63aaa551 100644 (file)
@@ -78,6 +78,14 @@ pub fn public(p: *const u8) {
     unsafe { std::ptr::read(p) };
 }
 
+type Alias = *const u8;
+
+pub fn type_alias(p: Alias) {
+    println!("{}", unsafe { *p });
+    println!("{:?}", unsafe { p.as_ref() });
+    unsafe { std::ptr::read(p) };
+}
+
 impl Bar {
     fn private(self, p: *const u8) {
         println!("{}", unsafe { *p });
index a2b8c2a384b03ac89d2593f0ccc22b6432d20357..8ebd4997f4f6e836983c92a66191a793429dc3ee 100644 (file)
@@ -69,22 +69,40 @@ LL |     unsafe { std::ptr::read(p) };
    |                             ^
 
 error: this public function might dereference a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:87:34
+  --> $DIR/functions.rs:84:30
+   |
+LL |     println!("{}", unsafe { *p });
+   |                              ^
+
+error: this public function might dereference a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:85:31
+   |
+LL |     println!("{:?}", unsafe { p.as_ref() });
+   |                               ^
+
+error: this public function might dereference a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:86:29
+   |
+LL |     unsafe { std::ptr::read(p) };
+   |                             ^
+
+error: this public function might dereference a raw pointer but is not marked `unsafe`
+  --> $DIR/functions.rs:95:34
    |
 LL |         println!("{}", unsafe { *p });
    |                                  ^
 
 error: this public function might dereference a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:88:35
+  --> $DIR/functions.rs:96:35
    |
 LL |         println!("{:?}", unsafe { p.as_ref() });
    |                                   ^
 
 error: this public function might dereference a raw pointer but is not marked `unsafe`
-  --> $DIR/functions.rs:89:33
+  --> $DIR/functions.rs:97:33
    |
 LL |         unsafe { std::ptr::read(p) };
    |                                 ^
 
-error: aborting due to 13 previous errors
+error: aborting due to 16 previous errors
 
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 69189d9e0c00d911637b320ba9e48b83e3716124..0016009a02f5858b39461dba03a777ba713ebf39 100644 (file)
@@ -138,6 +138,23 @@ fn if_same_then_else2() -> Result<&'static str, ()> {
         let (y, x) = (1, 2);
         return Ok(&foo[x..y]);
     }
+
+    // Issue #7579
+    let _ = if let Some(0) = None { 0 } else { 0 };
+
+    if true {
+        return Err(());
+    } else if let Some(0) = None {
+        return Err(());
+    }
+
+    let _ = if let Some(0) = None {
+        0
+    } else if let Some(1) = None {
+        0
+    } else {
+        0
+    };
 }
 
 fn main() {}
index cef71cf79d79721814cce022ec3ef1a736b31439..639fecb8927bd322b4754c9fb00268107612e793 100644 (file)
@@ -105,4 +105,13 @@ fn main() {
     let os_str = OsStr::new("foo");
     let _ = os_str.to_owned();
     let _ = os_str.to_os_string();
+
+    // issue #8227
+    let pathbuf_ref = &pathbuf;
+    let pathbuf_ref = &pathbuf_ref;
+    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&PathBuf`
+    let _ = pathbuf_ref.to_path_buf();
+    let pathbuf_ref = &pathbuf_ref;
+    let _ = pathbuf_ref.to_owned(); // Don't lint. Returns `&&PathBuf`
+    let _ = pathbuf_ref.to_path_buf();
 }
index e6f7527b67219d2409f514246af6e3911826e0af..0f4124241907f3b73dd9d38d0d9abac3e885053b 100644 (file)
@@ -1,64 +1,76 @@
 error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:65:17
+  --> $DIR/implicit_clone.rs:65:13
    |
 LL |     let _ = vec.to_owned();
-   |                 ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^ help: consider using: `vec.clone()`
    |
    = note: `-D clippy::implicit-clone` implied by `-D warnings`
 
 error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type
-  --> $DIR/implicit_clone.rs:66:17
+  --> $DIR/implicit_clone.rs:66:13
    |
 LL |     let _ = vec.to_vec();
-   |                 ^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^ help: consider using: `vec.clone()`
 
 error: implicitly cloning a `Vec` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:70:21
+  --> $DIR/implicit_clone.rs:70:13
    |
 LL |     let _ = vec_ref.to_owned();
-   |                     ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()`
 
 error: implicitly cloning a `Vec` by calling `to_vec` on its dereferenced type
-  --> $DIR/implicit_clone.rs:71:21
+  --> $DIR/implicit_clone.rs:71:13
    |
 LL |     let _ = vec_ref.to_vec();
-   |                     ^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^ help: consider using: `vec_ref.clone()`
 
 error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:83:17
+  --> $DIR/implicit_clone.rs:83:13
    |
 LL |     let _ = str.to_owned();
-   |                 ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^ help: consider using: `str.clone()`
 
 error: implicitly cloning a `Kitten` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:87:20
+  --> $DIR/implicit_clone.rs:87:13
    |
 LL |     let _ = kitten.to_owned();
-   |                    ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^ help: consider using: `kitten.clone()`
 
 error: implicitly cloning a `PathBuf` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:97:21
+  --> $DIR/implicit_clone.rs:97:13
    |
 LL |     let _ = pathbuf.to_owned();
-   |                     ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()`
 
 error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type
-  --> $DIR/implicit_clone.rs:98:21
+  --> $DIR/implicit_clone.rs:98:13
    |
 LL |     let _ = pathbuf.to_path_buf();
-   |                     ^^^^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `pathbuf.clone()`
 
 error: implicitly cloning a `OsString` by calling `to_owned` on its dereferenced type
-  --> $DIR/implicit_clone.rs:101:23
+  --> $DIR/implicit_clone.rs:101:13
    |
 LL |     let _ = os_string.to_owned();
-   |                       ^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()`
 
 error: implicitly cloning a `OsString` by calling `to_os_string` on its dereferenced type
-  --> $DIR/implicit_clone.rs:102:23
+  --> $DIR/implicit_clone.rs:102:13
    |
 LL |     let _ = os_string.to_os_string();
-   |                       ^^^^^^^^^^^^ help: consider using: `clone`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `os_string.clone()`
 
-error: aborting due to 10 previous errors
+error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type
+  --> $DIR/implicit_clone.rs:113:13
+   |
+LL |     let _ = pathbuf_ref.to_path_buf();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(*pathbuf_ref).clone()`
+
+error: implicitly cloning a `PathBuf` by calling `to_path_buf` on its dereferenced type
+  --> $DIR/implicit_clone.rs:116:13
+   |
+LL |     let _ = pathbuf_ref.to_path_buf();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(**pathbuf_ref).clone()`
+
+error: aborting due to 12 previous errors
 
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..cce216fc649b1667d276f9283ea4c273d146c5cb 100644 (file)
@@ -44,4 +44,31 @@ 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()
+    }
+}
+
+struct S2([u8]);
+impl S2 {
+    fn iter(&self) -> core::slice::Iter<u8> {
+        self.0.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
 
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
new file mode 100644 (file)
index 0000000..a904167
--- /dev/null
@@ -0,0 +1,45 @@
+// run-rustfix
+#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
+
+fn main() {
+    let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
+
+    let _: Option<String> = vec.iter().last().cloned();
+
+    let _: Option<String> = vec.iter().chain(vec.iter()).next().cloned();
+
+    let _: usize = vec.iter().filter(|x| x == &"2").count();
+
+    let _: Vec<_> = vec.iter().take(2).cloned().collect();
+
+    let _: Vec<_> = vec.iter().skip(2).cloned().collect();
+
+    let _ = vec.iter().filter(|x| x == &"2").nth(2).cloned();
+
+    let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
+        .iter().flatten().cloned();
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().map(|x| x.len());
+
+    // This would fail if changed.
+    let _ = vec.iter().cloned().map(|x| x + "2");
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().find(|x| x == "2");
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().all(|x| x.len() == 1);
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().any(|x| x.len() == 1);
+
+    // Should probably stay as it is.
+    let _ = [0, 1, 2, 3, 4].iter().cloned().take(10);
+}
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
new file mode 100644 (file)
index 0000000..dd04e33
--- /dev/null
@@ -0,0 +1,47 @@
+// run-rustfix
+#![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
+
+fn main() {
+    let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
+
+    let _: Option<String> = vec.iter().cloned().last();
+
+    let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
+
+    let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
+
+    let _: Vec<_> = vec.iter().cloned().take(2).collect();
+
+    let _: Vec<_> = vec.iter().cloned().skip(2).collect();
+
+    let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
+
+    let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
+        .iter()
+        .cloned()
+        .flatten();
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().map(|x| x.len());
+
+    // This would fail if changed.
+    let _ = vec.iter().cloned().map(|x| x + "2");
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().find(|x| x == "2");
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().all(|x| x.len() == 1);
+
+    // Not implemented yet
+    let _ = vec.iter().cloned().any(|x| x.len() == 1);
+
+    // Should probably stay as it is.
+    let _ = [0, 1, 2, 3, 4].iter().cloned().take(10);
+}
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
new file mode 100644 (file)
index 0000000..e36b0e3
--- /dev/null
@@ -0,0 +1,58 @@
+error: called `cloned().last()` on an `Iterator`. It may be more efficient to call `last().cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:7:29
+   |
+LL |     let _: Option<String> = vec.iter().cloned().last();
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().last().cloned()`
+   |
+   = note: `-D clippy::iter-overeager-cloned` implied by `-D warnings`
+
+error: called `cloned().next()` on an `Iterator`. It may be more efficient to call `next().cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:9:29
+   |
+LL |     let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
+   |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().chain(vec.iter()).next().cloned()`
+
+error: called `cloned().count()` on an `Iterator`. It may be more efficient to call `count()` instead
+  --> $DIR/iter_overeager_cloned.rs:11:20
+   |
+LL |     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").count()`
+   |
+   = note: `-D clippy::redundant-clone` implied by `-D warnings`
+
+error: called `cloned().take(...)` on an `Iterator`. It may be more efficient to call `take(...).cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:13:21
+   |
+LL |     let _: Vec<_> = vec.iter().cloned().take(2).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().take(2).cloned()`
+
+error: called `cloned().skip(...)` on an `Iterator`. It may be more efficient to call `skip(...).cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:15:21
+   |
+LL |     let _: Vec<_> = vec.iter().cloned().skip(2).collect();
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().skip(2).cloned()`
+
+error: called `cloned().nth(...)` on an `Iterator`. It may be more efficient to call `nth(...).cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:17:13
+   |
+LL |     let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `vec.iter().filter(|x| x == &"2").nth(2).cloned()`
+
+error: called `cloned().flatten()` on an `Iterator`. It may be more efficient to call `flatten().cloned()` instead
+  --> $DIR/iter_overeager_cloned.rs:19:13
+   |
+LL |       let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
+   |  _____________^
+LL | |         .iter()
+LL | |         .cloned()
+LL | |         .flatten();
+   | |__________________^
+   |
+help: try this
+   |
+LL ~     let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
+LL ~         .iter().flatten().cloned();
+   |
+
+error: aborting due to 7 previous errors
+
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..3208048e0d53c82e87407376138c0d0923db3bef 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;
@@ -176,4 +176,52 @@ mod issue6675 {
     }
 }
 
+mod issue8239 {
+    fn more_than_max_suggestion_highest_lines_0() {
+        let frames = Vec::new();
+        frames
+            .iter()
+            .map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                acc.push_str(&f);
+                acc
+            })
+            .unwrap_or_default();
+    }
+
+    fn more_to_max_suggestion_highest_lines_1() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        iter.map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                let _ = "";
+                let _ = "";
+                acc.push_str(&f);
+                acc
+            })
+            .unwrap_or_default();
+    }
+
+    fn equal_to_max_suggestion_highest_lines() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        iter.map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                let _ = "";
+                acc.push_str(&f);
+                acc
+            }).unwrap_or_default();
+    }
+
+    fn less_than_max_suggestion_highest_lines() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        let map = iter.map(|f: &String| f.to_lowercase());
+        map.reduce(|mut acc, f| {
+            acc.push_str(&f);
+            acc
+        }).unwrap_or_default();
+    }
+}
+
 fn main() {}
index 8eadc6ce3b47acace2c3fcf4cea29fd2db831b92..57ab5f03ee2851318b3ba58d9fcc2c72d23e442e 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;
@@ -176,4 +176,54 @@ fn bar() {
     }
 }
 
+mod issue8239 {
+    fn more_than_max_suggestion_highest_lines_0() {
+        let frames = Vec::new();
+        frames
+            .iter()
+            .map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                acc.push_str(&f);
+                acc
+            })
+            .unwrap_or(String::new());
+    }
+
+    fn more_to_max_suggestion_highest_lines_1() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        iter.map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                let _ = "";
+                let _ = "";
+                acc.push_str(&f);
+                acc
+            })
+            .unwrap_or(String::new());
+    }
+
+    fn equal_to_max_suggestion_highest_lines() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        iter.map(|f: &String| f.to_lowercase())
+            .reduce(|mut acc, f| {
+                let _ = "";
+                acc.push_str(&f);
+                acc
+            })
+            .unwrap_or(String::new());
+    }
+
+    fn less_than_max_suggestion_highest_lines() {
+        let frames = Vec::new();
+        let iter = frames.iter();
+        let map = iter.map(|f: &String| f.to_lowercase());
+        map.reduce(|mut acc, f| {
+            acc.push_str(&f);
+            acc
+        })
+        .unwrap_or(String::new());
+    }
+}
+
 fn main() {}
index 9d0c42b10c27f500eaa0469e43d1d1bcbfb0ae65..549b00ae3c45980c75ac3b229d2139e7375e7ccb 100644 (file)
@@ -108,5 +108,57 @@ error: use of `unwrap_or` followed by a function call
 LL |         None.unwrap_or( unsafe { ptr_to_ref(s) }    );
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
 
-error: aborting due to 18 previous errors
+error: use of `unwrap_or` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:189:14
+   |
+LL |             .unwrap_or(String::new());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+
+error: use of `unwrap_or` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:202:14
+   |
+LL |             .unwrap_or(String::new());
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_default()`
+
+error: use of `unwrap_or` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:208:9
+   |
+LL | /         iter.map(|f: &String| f.to_lowercase())
+LL | |             .reduce(|mut acc, f| {
+LL | |                 let _ = "";
+LL | |                 acc.push_str(&f);
+LL | |                 acc
+LL | |             })
+LL | |             .unwrap_or(String::new());
+   | |_____________________________________^
+   |
+help: try this
+   |
+LL ~         iter.map(|f: &String| f.to_lowercase())
+LL +             .reduce(|mut acc, f| {
+LL +                 let _ = "";
+LL +                 acc.push_str(&f);
+LL +                 acc
+LL ~             }).unwrap_or_default();
+   |
+
+error: use of `unwrap_or` followed by a call to `new`
+  --> $DIR/or_fun_call.rs:221:9
+   |
+LL | /         map.reduce(|mut acc, f| {
+LL | |             acc.push_str(&f);
+LL | |             acc
+LL | |         })
+LL | |         .unwrap_or(String::new());
+   | |_________________________________^
+   |
+help: try this
+   |
+LL ~         map.reduce(|mut acc, f| {
+LL +             acc.push_str(&f);
+LL +             acc
+LL ~         }).unwrap_or_default();
+   |
+
+error: aborting due to 22 previous errors
 
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 7dd5742dae9f213d5038af6d0422b6b201342db6..9b33ad6d3f6b3f83b26ca2ab4384bea9ee60cf51 100644 (file)
@@ -1,4 +1,5 @@
 #![crate_type = "lib"]
+#![warn(clippy::return_self_not_must_use)]
 
 #[derive(Clone)]
 pub struct Bar;
index 3793a5559ba55394fcc6497bf113a88e5aadd6e0..94be87dfa31c73c85a57a262c203d162252cc098 100644 (file)
@@ -1,26 +1,31 @@
 error: missing `#[must_use]` attribute on a method returning `Self`
-  --> $DIR/return_self_not_must_use.rs:7:5
+  --> $DIR/return_self_not_must_use.rs:8:5
    |
 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
+  --> $DIR/return_self_not_must_use.rs:18:5
    |
 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
+  --> $DIR/return_self_not_must_use.rs:21:5
    |
 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 f175700a3f479dcf912db12fcb587ed44ea3d94b..5b7e61a349d979c08b68fc04e994c1b35f018e69 100644 (file)
@@ -368,7 +368,7 @@ Otherwise, have a great day =^.^=
         <img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on Github"/>
     </a>
 
-    <script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/7.0.0/markdown-it.min.js"></script>
+    <script src="https://cdnjs.cloudflare.com/ajax/libs/markdown-it/12.3.2/markdown-it.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/highlight.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.5.0/languages/rust.min.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.12/angular.min.js"></script>
index 824816c973a3fd0596ae3a9a38c6fb6299b913b8..deb9bfd24648d50142ab29b810175837c4718885 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 824816c973a3fd0596ae3a9a38c6fb6299b913b8
+Subproject commit deb9bfd24648d50142ab29b810175837c4718885
index bf88026f11f2cc7bb9fefdfe1dbcab642f110afa..f37425e33c864c697af06df66e7473444605c149 160000 (submodule)
@@ -1 +1 @@
-Subproject commit bf88026f11f2cc7bb9fefdfe1dbcab642f110afa
+Subproject commit f37425e33c864c697af06df66e7473444605c149
index 5a67b423225357d0dea17bfc87a842cd7e1c84f8..85019df7867dd429b056a0de325afa6e4d9b344d 100644 (file)
 <core[846817f741e54dfd]::slice::Iter<u8> as core[846817f741e54dfd]::iter::iterator::Iterator>::rposition::<core[846817f741e54dfd]::slice::memchr::memrchr::{closure#1}>::{closure#0}
 alloc[f15a878b47eb696b]::alloc::box_free::<dyn alloc[f15a878b47eb696b]::boxed::FnBox<(), Output = ()>>
 INtC8arrayvec8ArrayVechKj7b_E
-<const_generic[317d481089b8c8fe]::Unsigned<11u8>>
-<const_generic[317d481089b8c8fe]::Signed<152i16>>
-<const_generic[317d481089b8c8fe]::Signed<-11i8>>
-<const_generic[317d481089b8c8fe]::Bool<false: bool>>
-<const_generic[317d481089b8c8fe]::Bool<true: bool>>
-<const_generic[317d481089b8c8fe]::Char<'v': char>>
-<const_generic[317d481089b8c8fe]::Char<'\n': char>>
-<const_generic[317d481089b8c8fe]::Char<'∂': char>>
+<const_generic[317d481089b8c8fe]::Unsigned<11u8>>
+<const_generic[317d481089b8c8fe]::Signed<152i16>>
+<const_generic[317d481089b8c8fe]::Signed<-11i8>>
+<const_generic[317d481089b8c8fe]::Bool<false>>
+<const_generic[317d481089b8c8fe]::Bool<true>>
+<const_generic[317d481089b8c8fe]::Char<'v'>>
+<const_generic[317d481089b8c8fe]::Char<'\n'>>
+<const_generic[317d481089b8c8fe]::Char<'∂'>>
 <const_generic[317d481089b8c8fe]::Foo<_>>::foo::FOO
 foo[0]
 foo[0]
 <core::slice::Iter<u8> as core::iter::iterator::Iterator>::rposition::<core::slice::memchr::memrchr::{closure#1}>::{closure#0}
 alloc::alloc::box_free::<dyn alloc::boxed::FnBox<(), Output = ()>>
 INtC8arrayvec8ArrayVechKj7b_E
-<const_generic::Unsigned<11u8>>
-<const_generic::Signed<152i16>>
-<const_generic::Signed<-11i8>>
-<const_generic::Bool<false: bool>>
-<const_generic::Bool<true: bool>>
-<const_generic::Char<'v': char>>
-<const_generic::Char<'\n': char>>
-<const_generic::Char<'∂': char>>
+<const_generic::Unsigned<11u8>>
+<const_generic::Signed<152i16>>
+<const_generic::Signed<-11i8>>
+<const_generic::Bool<false>>
+<const_generic::Bool<true>>
+<const_generic::Char<'v'>>
+<const_generic::Char<'\n'>>
+<const_generic::Char<'∂'>>
 <const_generic::Foo<_>>::foo::FOO
 foo[0]
 foo[0]
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 c9c8852cd3b56276d223ac6acc1b7ea79b73e643..e1865c8afc2f0c753c73297989f94e8ced5efd1f 100644 (file)
@@ -334,9 +334,7 @@ fn needs_space_after_range(rhs: &ast::Expr) -> bool {
         // satisfy our width restrictions.
         // Style Guide RFC for InlineAsm variant pending
         // https://github.com/rust-dev-tools/fmt-rfcs/issues/152
-        ast::ExprKind::LlvmInlineAsm(..) | ast::ExprKind::InlineAsm(..) => {
-            Some(context.snippet(expr.span).to_owned())
-        }
+        ast::ExprKind::InlineAsm(..) => Some(context.snippet(expr.span).to_owned()),
         ast::ExprKind::TryBlock(ref block) => {
             if let rw @ Some(_) =
                 rewrite_single_line_block(context, "try ", block, Some(&expr.attrs), None, shape)
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 88f5dc432451010436694b49a355e68fb9f27b98..5de30129266a385cdca831ee0b0c582d8980343c 100644 (file)
@@ -1,7 +1,7 @@
 use std::iter::ExactSizeIterator;
 use std::ops::Deref;
 
-use rustc_ast::ast::{self, FnRetTy, Mutability};
+use rustc_ast::ast::{self, FnRetTy, Mutability, Term};
 use rustc_ast::ptr;
 use rustc_span::{symbol::kw, BytePos, Pos, Span};
 
@@ -141,7 +141,7 @@ pub(crate) enum SegmentParam<'a> {
     Const(&'a ast::AnonConst),
     LifeTime(&'a ast::Lifetime),
     Type(&'a ast::Ty),
-    Binding(&'a ast::AssocTyConstraint),
+    Binding(&'a ast::AssocConstraint),
 }
 
 impl<'a> SegmentParam<'a> {
@@ -176,9 +176,9 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
     }
 }
 
-impl Rewrite for ast::AssocTyConstraint {
+impl Rewrite for ast::AssocConstraint {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
-        use ast::AssocTyConstraintKind::{Bound, Equality};
+        use ast::AssocConstraintKind::{Bound, Equality};
 
         let mut result = String::with_capacity(128);
         result.push_str(rewrite_ident(context, self.ident));
@@ -206,11 +206,14 @@ fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String>
     }
 }
 
-impl Rewrite for ast::AssocTyConstraintKind {
+impl Rewrite for ast::AssocConstraintKind {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         match self {
-            ast::AssocTyConstraintKind::Equality { ty } => ty.rewrite(context, shape),
-            ast::AssocTyConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
+            ast::AssocConstraintKind::Equality { term } => match term {
+                Term::Ty(ty) => ty.rewrite(context, shape),
+                Term::Const(c) => c.rewrite(context, shape),
+            },
+            ast::AssocConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
         }
     }
 }
index 0c0b789a6efd1a63614621af60b8c89aa21753f0..2428d8cb0fd89ee6b934629ccc5cfed909f4487b 100644 (file)
@@ -507,7 +507,6 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
         | ast::ExprKind::Err
         | ast::ExprKind::Field(..)
         | ast::ExprKind::InlineAsm(..)
-        | ast::ExprKind::LlvmInlineAsm(..)
         | ast::ExprKind::Let(..)
         | ast::ExprKind::Path(..)
         | ast::ExprKind::Range(..)
index 4c28655bc865354926422bed5ecb321bd328404a..f83a5b1a2ba13f4a24a90d88df1b5d245bd77c74 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",
     "lock_api",
     "log",
     "matchers",
-    "maybe-uninit",
     "md-5",
     "measureme",
     "memchr",
     // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times
     // under control.
     "cargo",
-    "rustc-ap-rustc_ast",
 ];
 
 /// Dependency checks.